jsii-pacmak 1.114.1 → 1.115.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/lib/npm-modules.d.ts +1 -1
  2. package/lib/npm-modules.js +1 -3
  3. package/lib/packaging.d.ts +1 -5
  4. package/lib/packaging.js +12 -6
  5. package/lib/rosetta-assembly.d.ts +4 -0
  6. package/lib/rosetta-assembly.js +9 -3
  7. package/lib/targets/dotnet/dotnetdocgenerator.d.ts +4 -1
  8. package/lib/targets/dotnet/dotnetdocgenerator.js +66 -13
  9. package/lib/targets/dotnet/dotnetgenerator.d.ts +0 -4
  10. package/lib/targets/dotnet/dotnetgenerator.js +24 -14
  11. package/lib/targets/dotnet/dotnetruntimegenerator.js +11 -2
  12. package/lib/targets/dotnet/dotnettyperesolver.d.ts +13 -0
  13. package/lib/targets/dotnet/dotnettyperesolver.js +40 -2
  14. package/lib/targets/dotnet.d.ts +1 -1
  15. package/lib/targets/dotnet.js +6 -4
  16. package/lib/targets/go/runtime/runtime-type-checking.js +1 -0
  17. package/lib/targets/go/types/go-type-reference.d.ts +3 -0
  18. package/lib/targets/go/types/go-type-reference.js +20 -0
  19. package/lib/targets/go.js +1 -1
  20. package/lib/targets/java.d.ts +28 -4
  21. package/lib/targets/java.js +406 -217
  22. package/lib/targets/python/requirements-dev.txt +1 -1
  23. package/lib/targets/python/type-name.d.ts +18 -0
  24. package/lib/targets/python/type-name.js +59 -1
  25. package/lib/targets/python.d.ts +2 -1
  26. package/lib/targets/python.js +50 -18
  27. package/lib/targets/type-literals.d.ts +22 -0
  28. package/lib/targets/type-literals.js +39 -0
  29. package/lib/type-utils.d.ts +3 -0
  30. package/lib/type-utils.js +10 -0
  31. package/lib/type-visitor.d.ts +19 -0
  32. package/lib/type-visitor.js +47 -0
  33. package/lib/util.d.ts +18 -5
  34. package/lib/util.js +80 -13
  35. package/lib/version.d.ts +1 -1
  36. package/lib/version.js +3 -3
  37. package/package.json +12 -12
@@ -19,6 +19,9 @@ const version_1 = require("../version");
19
19
  const _utils_1 = require("./_utils");
20
20
  const version_utils_1 = require("./version-utils");
21
21
  const rosetta_assembly_1 = require("../rosetta-assembly");
22
+ const type_utils_1 = require("../type-utils");
23
+ const type_visitor_1 = require("../type-visitor");
24
+ const type_literals_1 = require("./type-literals");
22
25
  const index_1 = require("./index");
23
26
  // eslint-disable-next-line @typescript-eslint/no-var-requires,@typescript-eslint/no-require-imports
24
27
  const spdxLicenseList = require('spdx-license-list');
@@ -306,7 +309,7 @@ class Java extends target_1.Target {
306
309
  mvnArguments.push(`--${arg.slice(4)}`);
307
310
  mvnArguments.push(this.arguments[arg].toString());
308
311
  }
309
- await (0, util_1.shell)('mvn', [
312
+ await (0, util_1.subprocess)('mvn', [
310
313
  // If we don't run in verbose mode, turn on quiet mode
311
314
  ...(this.arguments.verbose ? [] : ['--quiet']),
312
315
  '--batch-mode',
@@ -395,7 +398,9 @@ class JavaGenerator extends generator_1.Generator {
395
398
  this.openFileIfNeeded(cls);
396
399
  this.addJavaDocs(cls, { api: 'type', fqn: cls.fqn });
397
400
  const classBase = this.getClassBase(cls);
398
- const extendsExpression = classBase ? ` extends ${classBase}` : '';
401
+ const extendsExpression = classBase
402
+ ? ` extends ${displayStatic(classBase)}`
403
+ : '';
399
404
  let implementsExpr = '';
400
405
  if (cls.interfaces?.length ?? 0 > 0) {
401
406
  implementsExpr = ` implements ${cls
@@ -434,9 +439,14 @@ class JavaGenerator extends generator_1.Generator {
434
439
  const initializerAccessLevel = cls.abstract
435
440
  ? 'protected'
436
441
  : this.renderAccessLevel(method);
437
- this.code.openBlock(`${initializerAccessLevel} ${cls.name}(${this.renderMethodParameters(method)})`);
442
+ const types = this.convertTypes(method.parameters);
443
+ if (types.some((t) => t.type === 'param')) {
444
+ throw new Error('Cannot have generic type arguments to a constructor');
445
+ }
446
+ // NOTE: even though a constructor is technically final and we COULD render covariant types, historically we didn't and I'm not changing it.
447
+ this.code.openBlock(`${initializerAccessLevel} ${cls.name}(${this.renderParameters(method.parameters, types, 'final-but-not-cov')})`);
438
448
  this.code.line('super(software.amazon.jsii.JsiiObject.InitializationMode.JSII);');
439
- this.emitUnionParameterValdation(method.parameters);
449
+ this.emitUnionParameterValidation(method.parameters);
440
450
  this.code.line(`software.amazon.jsii.JsiiEngine.getInstance().createNewObject(this${this.renderMethodCallArguments(method)});`);
441
451
  this.code.closeBlock();
442
452
  }
@@ -551,22 +561,33 @@ class JavaGenerator extends generator_1.Generator {
551
561
  onInterfaceMethod(ifc, method) {
552
562
  this.code.line();
553
563
  const returnType = method.returns
554
- ? this.toDecoratedJavaType(method.returns)
555
- : 'void';
564
+ ? forceSingleType(this.toDecoratedJavaTypes(method.returns))
565
+ : mkStatic('void');
556
566
  const methodName = JavaGenerator.safeJavaMethodName(method.name);
557
567
  this.addJavaDocs(method, {
558
568
  api: 'member',
559
569
  fqn: ifc.fqn,
560
570
  memberName: methodName,
571
+ }, {
572
+ returnsUnion: method.returns?.type,
561
573
  });
562
574
  this.emitStabilityAnnotations(method);
563
- this.code.line(`${returnType} ${methodName}(${this.renderMethodParameters(method)});`);
575
+ const types = this.convertTypes(method.parameters);
576
+ this.code.line(`${typeVarDeclarations(types)}${displayStatic(returnType)} ${methodName}(${this.renderParameters(method.parameters, types, 'overridable')});`);
564
577
  }
565
578
  onInterfaceMethodOverload(ifc, overload, _originalMethod) {
566
579
  this.onInterfaceMethod(ifc, overload);
567
580
  }
568
581
  onInterfaceProperty(ifc, prop) {
569
- const getterType = this.toDecoratedJavaType(prop);
582
+ let apparentGetterType = prop;
583
+ // We can only ever return one type, so take the first one
584
+ if (spec.isIntersectionTypeReference(prop.type)) {
585
+ apparentGetterType = {
586
+ optional: prop.optional,
587
+ type: prop.type.intersection.types[0],
588
+ };
589
+ }
590
+ const getterType = forceSingleType(this.toDecoratedJavaTypes(apparentGetterType));
570
591
  const propName = (0, naming_util_1.jsiiToPascalCase)(JavaGenerator.safeJavaPropertyName(prop.name));
571
592
  // for unions we only generate overloads for setters, not getters.
572
593
  this.code.line();
@@ -574,18 +595,20 @@ class JavaGenerator extends generator_1.Generator {
574
595
  api: 'member',
575
596
  fqn: ifc.fqn,
576
597
  memberName: prop.name,
598
+ }, {
599
+ returnsUnion: prop.type,
577
600
  });
578
601
  this.emitStabilityAnnotations(prop);
579
602
  if (prop.optional) {
580
603
  if (prop.overrides) {
581
604
  this.code.line('@Override');
582
605
  }
583
- this.code.openBlock(`default ${getterType} get${propName}()`);
606
+ this.code.openBlock(`default ${displayStatic(getterType)} get${propName}()`);
584
607
  this.code.line('return null;');
585
608
  this.code.closeBlock();
586
609
  }
587
610
  else {
588
- this.code.line(`${getterType} get${propName}();`);
611
+ this.code.line(`${displayStatic(getterType)} get${propName}();`);
589
612
  }
590
613
  if (!prop.immutable) {
591
614
  const setterTypes = this.toDecoratedJavaTypes(prop);
@@ -595,18 +618,19 @@ class JavaGenerator extends generator_1.Generator {
595
618
  api: 'member',
596
619
  fqn: ifc.fqn,
597
620
  memberName: prop.name,
621
+ // Setter doesn't need a union type hint because we're generating overloads
598
622
  });
599
623
  if (prop.optional) {
600
624
  if (prop.overrides) {
601
625
  this.code.line('@Override');
602
626
  }
603
627
  this.code.line('@software.amazon.jsii.Optional');
604
- this.code.openBlock(`default void set${propName}(final ${type} value)`);
605
- this.code.line(`throw new UnsupportedOperationException("'void " + getClass().getCanonicalName() + "#set${propName}(${type})' is not implemented!");`);
628
+ this.code.openBlock(`default void set${propName}(final ${displayStatic(type)} value)`);
629
+ this.code.line(`throw new UnsupportedOperationException("'void " + getClass().getCanonicalName() + "#set${propName}(${displayStatic(type)})' is not implemented!");`);
606
630
  this.code.closeBlock();
607
631
  }
608
632
  else {
609
- this.code.line(`void set${propName}(final ${type} value);`);
633
+ this.code.line(`void set${propName}(final ${displayStatic(type)} value);`);
610
634
  }
611
635
  }
612
636
  }
@@ -938,13 +962,13 @@ class JavaGenerator extends generator_1.Generator {
938
962
  if (consts.length === 0) {
939
963
  return;
940
964
  }
941
- const javaClass = this.toJavaType(cls);
965
+ const javaClass = forceSingleType(this.toJavaTypes(cls));
942
966
  this.code.line();
943
967
  this.code.openBlock('static');
944
968
  for (const prop of consts) {
945
969
  const constName = this.renderConstName(prop);
946
- const propType = this.toNativeType(prop.type, { forMarshalling: true });
947
- const statement = `software.amazon.jsii.JsiiObject.jsiiStaticGet(${javaClass}.class, "${prop.name}", ${propType})`;
970
+ const propType = this.toNativeType(forceSingleType(this.toJavaTypes(prop.type)));
971
+ const statement = `software.amazon.jsii.JsiiObject.jsiiStaticGet(${displayStatic(javaClass)}.class, "${prop.name}", ${propType})`;
948
972
  this.code.line(`${constName} = ${this.wrapCollection(statement, prop.type, prop.optional)};`);
949
973
  }
950
974
  this.code.closeBlock();
@@ -953,7 +977,7 @@ class JavaGenerator extends generator_1.Generator {
953
977
  return this.code.toSnakeCase(prop.name).toLocaleUpperCase(); // java consts are SNAKE_UPPER_CASE
954
978
  }
955
979
  emitConstProperty(parentType, prop) {
956
- const propType = this.toJavaType(prop.type);
980
+ const propType = forceSingleType(this.toJavaTypes(prop.type));
957
981
  const propName = this.renderConstName(prop);
958
982
  const access = this.renderAccessLevel(prop);
959
983
  this.code.line();
@@ -961,15 +985,15 @@ class JavaGenerator extends generator_1.Generator {
961
985
  api: 'member',
962
986
  fqn: parentType.fqn,
963
987
  memberName: prop.name,
988
+ }, {
989
+ returnsUnion: prop.type,
964
990
  });
965
991
  this.emitStabilityAnnotations(prop);
966
- this.code.line(`${access} final static ${propType} ${propName};`);
992
+ this.code.line(`${access} final static ${displayStatic(propType)} ${propName};`);
967
993
  }
968
994
  emitProperty(cls, prop, definingType, { defaultImpl = false, final = false, includeGetter = true, overrides = !!prop.overrides, } = {}) {
969
- const getterType = this.toDecoratedJavaType(prop);
970
- const setterTypes = this.toDecoratedJavaTypes(prop, {
971
- covariant: prop.static,
972
- });
995
+ const setterTypes = this.toDecoratedJavaTypes(prop);
996
+ const getterType = forceSingleType(setterTypes);
973
997
  const propName = (0, naming_util_1.jsiiToPascalCase)(JavaGenerator.safeJavaPropertyName(prop.name));
974
998
  const modifiers = [defaultImpl ? 'default' : this.renderAccessLevel(prop)];
975
999
  if (prop.static)
@@ -978,7 +1002,7 @@ class JavaGenerator extends generator_1.Generator {
978
1002
  modifiers.push('abstract');
979
1003
  if (final && !prop.abstract && !defaultImpl)
980
1004
  modifiers.push('final');
981
- const javaClass = this.toJavaType(cls);
1005
+ const javaClass = forceSingleType(this.toJavaTypes(cls));
982
1006
  // for unions we only generate overloads for setters, not getters.
983
1007
  if (includeGetter) {
984
1008
  this.code.line();
@@ -986,12 +1010,14 @@ class JavaGenerator extends generator_1.Generator {
986
1010
  api: 'member',
987
1011
  fqn: definingType.fqn,
988
1012
  memberName: prop.name,
1013
+ }, {
1014
+ returnsUnion: prop.type,
989
1015
  });
990
1016
  if (overrides && !prop.static) {
991
1017
  this.code.line('@Override');
992
1018
  }
993
1019
  this.emitStabilityAnnotations(prop);
994
- const signature = `${modifiers.join(' ')} ${getterType} get${propName}()`;
1020
+ const signature = `${modifiers.join(' ')} ${displayStatic(getterType)} get${propName}()`;
995
1021
  if (prop.abstract && !defaultImpl) {
996
1022
  this.code.line(`${signature};`);
997
1023
  }
@@ -999,14 +1025,12 @@ class JavaGenerator extends generator_1.Generator {
999
1025
  this.code.openBlock(signature);
1000
1026
  let statement;
1001
1027
  if (prop.static) {
1002
- statement = `software.amazon.jsii.JsiiObject.jsiiStaticGet(${this.toJavaType(cls)}.class, `;
1028
+ statement = `software.amazon.jsii.JsiiObject.jsiiStaticGet(${displayStatic(forceSingleType(this.toJavaTypes(cls)))}.class, `;
1003
1029
  }
1004
1030
  else {
1005
1031
  statement = 'software.amazon.jsii.Kernel.get(this, ';
1006
1032
  }
1007
- statement += `"${prop.name}", ${this.toNativeType(prop.type, {
1008
- forMarshalling: true,
1009
- })})`;
1033
+ statement += `"${prop.name}", ${this.toNativeType(forceSingleType(this.toJavaTypes(prop.type)))})`;
1010
1034
  this.code.line(`return ${this.wrapCollection(statement, prop.type, prop.optional)};`);
1011
1035
  this.code.closeBlock();
1012
1036
  }
@@ -1018,12 +1042,14 @@ class JavaGenerator extends generator_1.Generator {
1018
1042
  api: 'member',
1019
1043
  fqn: cls.fqn,
1020
1044
  memberName: prop.name,
1045
+ // No union type hint for setters
1021
1046
  });
1022
1047
  if (overrides && !prop.static) {
1023
1048
  this.code.line('@Override');
1024
1049
  }
1025
1050
  this.emitStabilityAnnotations(prop);
1026
- const signature = `${modifiers.join(' ')} void set${propName}(final ${type} value)`;
1051
+ // We could have emitted a covariant argument type here, but we didn't historically and I'm not changing that now.
1052
+ const signature = `${modifiers.join(' ')} void set${propName}(final ${displayStatic(type)} value)`;
1027
1053
  if (prop.abstract && !defaultImpl) {
1028
1054
  this.code.line(`${signature};`);
1029
1055
  }
@@ -1036,19 +1062,20 @@ class JavaGenerator extends generator_1.Generator {
1036
1062
  // This allows the compiler to do this type checking for us,
1037
1063
  // so we should not emit these checks for primitive-only unions.
1038
1064
  // Also, Java does not allow us to perform these checks if the types
1039
- // have no overlap (eg if a String instanceof Number).
1040
- if (type.includes('java.lang.Object') &&
1065
+ // have no overlap (eg if we emit code for `String instanceof Number`,
1066
+ // which will always return `false`, the compiler would reject the code).
1067
+ if (displayStatic(type).includes('java.lang.Object') &&
1041
1068
  (!spec.isPrimitiveTypeReference(prop.type) ||
1042
1069
  prop.type.primitive === spec.PrimitiveType.Any)) {
1043
- this.emitUnionParameterValdation([
1070
+ this.emitUnionParameterValidation([
1044
1071
  {
1045
1072
  name: 'value',
1046
- type: this.filterType(prop.type, { covariant: prop.static, optional: prop.optional }, type),
1073
+ type: this.filterType(prop, type),
1047
1074
  },
1048
1075
  ]);
1049
1076
  }
1050
1077
  if (prop.static) {
1051
- statement += `software.amazon.jsii.JsiiObject.jsiiStaticSet(${javaClass}.class, `;
1078
+ statement += `software.amazon.jsii.JsiiObject.jsiiStaticSet(${displayStatic(javaClass)}.class, `;
1052
1079
  }
1053
1080
  else {
1054
1081
  statement += 'software.amazon.jsii.Kernel.set(this, ';
@@ -1074,20 +1101,19 @@ class JavaGenerator extends generator_1.Generator {
1074
1101
  *
1075
1102
  * @returns a type reference that matches the provided javaType.
1076
1103
  */
1077
- filterType(ref, { covariant, optional }, javaType) {
1078
- if (!spec.isUnionTypeReference(ref)) {
1104
+ filterType(prop, javaType) {
1105
+ if (!spec.isUnionTypeReference(prop.type)) {
1079
1106
  // No filterning needed -- this isn't a type union!
1080
- return ref;
1107
+ return prop.type;
1081
1108
  }
1082
- const types = ref.union.types.filter((t) => this.toDecoratedJavaType({ optional, type: t }, { covariant }) ===
1083
- javaType);
1084
- assert(types.length > 0, `No type found in ${spec.describeTypeReference(ref)} has Java type ${javaType}`);
1109
+ const types = prop.type.union.types.filter((t) => typesEqual(forceSingleType(annotateOptional(prop, this.toJavaTypes(t))), javaType));
1110
+ assert(types.length > 0, `No type found in ${spec.describeTypeReference(prop.type)} has Java type ${displayStatic(javaType)}`);
1085
1111
  return { union: { types } };
1086
1112
  }
1087
1113
  emitMethod(cls, method, { defaultImpl = false, final = false, overrides = !!method.overrides, } = {}) {
1088
1114
  const returnType = method.returns
1089
- ? this.toDecoratedJavaType(method.returns)
1090
- : 'void';
1115
+ ? forceSingleType(this.toDecoratedJavaTypes(method.returns))
1116
+ : mkStatic('void');
1091
1117
  const modifiers = [
1092
1118
  defaultImpl ? 'default' : this.renderAccessLevel(method),
1093
1119
  ];
@@ -1099,12 +1125,15 @@ class JavaGenerator extends generator_1.Generator {
1099
1125
  modifiers.push('final');
1100
1126
  const async = !!method.async;
1101
1127
  const methodName = JavaGenerator.safeJavaMethodName(method.name);
1102
- const signature = `${returnType} ${methodName}(${this.renderMethodParameters(method)})`;
1128
+ const types = this.convertTypes(method.parameters);
1129
+ const signature = `${typeVarDeclarations(types)}${displayStatic(returnType)} ${methodName}(${this.renderParameters(method.parameters, types, method.static ? 'final' : 'overridable')})`;
1103
1130
  this.code.line();
1104
1131
  this.addJavaDocs(method, {
1105
1132
  api: 'member',
1106
1133
  fqn: cls.fqn,
1107
1134
  memberName: method.name,
1135
+ }, {
1136
+ returnsUnion: method.returns?.type,
1108
1137
  });
1109
1138
  this.emitStabilityAnnotations(method);
1110
1139
  if (overrides && !method.static) {
@@ -1115,7 +1144,7 @@ class JavaGenerator extends generator_1.Generator {
1115
1144
  }
1116
1145
  else {
1117
1146
  this.code.openBlock(`${modifiers.join(' ')} ${signature}`);
1118
- this.emitUnionParameterValdation(method.parameters);
1147
+ this.emitUnionParameterValidation(method.parameters);
1119
1148
  this.code.line(this.renderMethodCall(cls, method, async));
1120
1149
  this.code.closeBlock();
1121
1150
  }
@@ -1125,21 +1154,21 @@ class JavaGenerator extends generator_1.Generator {
1125
1154
  *
1126
1155
  * @param parameters the list of parameters received by the function.
1127
1156
  */
1128
- emitUnionParameterValdation(parameters) {
1157
+ emitUnionParameterValidation(parameters) {
1129
1158
  if (!this.runtimeTypeChecking) {
1130
1159
  // We were configured not to emit those, so bail out now.
1131
1160
  return;
1132
1161
  }
1133
- const unionParameters = parameters?.filter(({ type }) => containsUnionType(type));
1162
+ const unionParameters = parameters?.filter(({ type }) => (0, type_utils_1.containsUnionType)(type));
1134
1163
  if (unionParameters == null || unionParameters.length === 0) {
1135
1164
  return;
1136
1165
  }
1137
1166
  this.code.openBlock('if (software.amazon.jsii.Configuration.getRuntimeTypeChecking())');
1138
1167
  for (const param of unionParameters) {
1139
1168
  if (param.variadic) {
1140
- const javaType = this.toJavaType(param.type);
1169
+ const javaType = this.toSingleJavaType(param.type);
1141
1170
  const asListName = `__${param.name}__asList`;
1142
- this.code.line(`final java.util.List<${javaType}> ${asListName} = java.util.Arrays.asList(${param.name});`);
1171
+ this.code.line(`final java.util.List<${displayStatic(javaType)}> ${asListName} = java.util.Arrays.asList(${param.name});`);
1143
1172
  validate.call(this, asListName, `.append("${param.name}")`, {
1144
1173
  collection: {
1145
1174
  kind: spec.CollectionKind.Array,
@@ -1175,8 +1204,8 @@ class JavaGenerator extends generator_1.Generator {
1175
1204
  const idxName = `__idx_${suffix}`;
1176
1205
  const valName = `__val_${suffix}`;
1177
1206
  this.code.openBlock(`for (int ${idxName} = 0; ${idxName} < ${value}.size(); ${idxName}++)`);
1178
- const eltType = this.toJavaType(elementType);
1179
- this.code.line(`final ${eltType} ${valName} = ${value}.get(${idxName});`);
1207
+ const eltType = this.toSingleJavaType(elementType);
1208
+ this.code.line(`final ${displayStatic(eltType)} ${valName} = ${value}.get(${idxName});`);
1180
1209
  validate.call(this, valName, isRawArray
1181
1210
  ? `${descr}.append("[").append(${idxName}).append("]")`
1182
1211
  : `${descr}.append(".get(").append(${idxName}).append(")")`, elementType, parameterName);
@@ -1201,9 +1230,9 @@ class JavaGenerator extends generator_1.Generator {
1201
1230
  .slice(0, 6);
1202
1231
  const varName = `__item_${suffix}`;
1203
1232
  const valName = `__val_${suffix}`;
1204
- const javaElemType = this.toJavaType(elementType);
1205
- this.code.openBlock(`for (final java.util.Map.Entry<String, ${javaElemType}> ${varName}: ${value}.entrySet())`);
1206
- this.code.line(`final ${javaElemType} ${valName} = ${varName}.getValue();`);
1233
+ const javaElemType = this.toSingleJavaType(elementType);
1234
+ this.code.openBlock(`for (final java.util.Map.Entry<String, ${displayStatic(javaElemType)}> ${varName}: ${value}.entrySet())`);
1235
+ this.code.line(`final ${displayStatic(javaElemType)} ${valName} = ${varName}.getValue();`);
1207
1236
  validate.call(this, valName, `${descr}.append(".get(\\"").append((${varName}.getKey())).append("\\")")`, elementType, parameterName);
1208
1237
  this.code.closeBlock();
1209
1238
  }
@@ -1224,9 +1253,9 @@ class JavaGenerator extends generator_1.Generator {
1224
1253
  else {
1225
1254
  checked.add(javaRawType);
1226
1255
  }
1227
- const javaType = this.toJavaType(typeRef);
1228
- if (javaRawType !== javaType) {
1229
- nestedCollectionUnionTypes.set(javaType, typeRef);
1256
+ const javaType = this.toSingleJavaType(typeRef);
1257
+ if (javaRawType !== displayStatic(javaType)) {
1258
+ nestedCollectionUnionTypes.set(displayStatic(javaType), typeRef);
1230
1259
  }
1231
1260
  const test = `${value} instanceof ${javaRawType}`;
1232
1261
  if (typeRefs.length > 1) {
@@ -1245,7 +1274,7 @@ class JavaGenerator extends generator_1.Generator {
1245
1274
  this.code.openBlock(')');
1246
1275
  const placeholders = typeRefs
1247
1276
  .map((typeRef) => {
1248
- return `${this.toJavaType(typeRef)}`;
1277
+ return `${displayStatic(this.toSingleJavaType(typeRef))}`;
1249
1278
  })
1250
1279
  .join(', ');
1251
1280
  this.code.indent(`throw new IllegalArgumentException(`);
@@ -1403,6 +1432,8 @@ class JavaGenerator extends generator_1.Generator {
1403
1432
  toJavaProp(property, definingType, inherited) {
1404
1433
  const safeName = JavaGenerator.safeJavaPropertyName(property.name);
1405
1434
  const propName = (0, naming_util_1.jsiiToPascalCase)(safeName);
1435
+ const noIntersectionJavaTypes = this.toJavaTypes(removeIntersections(property.type));
1436
+ const singleJavaType = forceSingleType(noIntersectionJavaTypes);
1406
1437
  return {
1407
1438
  docs: property.docs,
1408
1439
  spec: property,
@@ -1411,13 +1442,10 @@ class JavaGenerator extends generator_1.Generator {
1411
1442
  jsiiName: property.name,
1412
1443
  nullable: !!property.optional,
1413
1444
  fieldName: this.code.toCamelCase(safeName),
1414
- fieldJavaType: this.toJavaType(property.type),
1415
- paramJavaType: this.toJavaType(property.type, { covariant: true }),
1416
- fieldNativeType: this.toNativeType(property.type),
1417
- fieldJavaClass: `${this.toJavaType(property.type, {
1418
- forMarshalling: true,
1419
- })}.class`,
1420
- javaTypes: this.toJavaTypes(property.type, { covariant: true }),
1445
+ renderedFieldType: displayStatic(singleJavaType),
1446
+ renderedParamType: displayType(singleJavaType, 'covariant'),
1447
+ renderedNativeFieldType: this.toNativeType(singleJavaType),
1448
+ javaTypes: this.toJavaTypes(property.type),
1421
1449
  immutable: property.immutable ?? false,
1422
1450
  inherited,
1423
1451
  };
@@ -1450,22 +1478,22 @@ class JavaGenerator extends generator_1.Generator {
1450
1478
  }
1451
1479
  const structType = this.reflectAssembly.findType(firstStruct.type.fqn);
1452
1480
  const structParamName = this.code.toCamelCase(JavaGenerator.safeJavaPropertyName(firstStruct.name));
1453
- const structBuilder = `${this.toJavaType(firstStruct.type)}.${BUILDER_CLASS_NAME}`;
1481
+ const structBuilder = `${displayStatic(this.toSingleJavaType(firstStruct.type))}.${BUILDER_CLASS_NAME}`;
1454
1482
  const positionalParams = cls.initializer.parameters
1455
1483
  .filter((p) => p !== firstStruct)
1456
1484
  .map((param) => ({
1457
1485
  param,
1458
1486
  fieldName: this.code.toCamelCase(JavaGenerator.safeJavaPropertyName(param.name)),
1459
- javaType: this.toJavaType(param.type),
1487
+ javaType: this.toSingleJavaType(param.type),
1460
1488
  }));
1461
- const builtType = this.toJavaType(cls);
1489
+ const builtType = this.toSingleJavaType(cls);
1462
1490
  this.code.line();
1463
1491
  this.code.line('/**');
1464
1492
  // eslint-disable-next-line prettier/prettier
1465
- this.code.line(` * ${(0, _utils_1.stabilityPrefixFor)(cls.initializer)}A fluent builder for {@link ${builtType}}.`);
1493
+ this.code.line(` * ${(0, _utils_1.stabilityPrefixFor)(cls.initializer)}A fluent builder for {@link ${displayStatic(builtType)}}.`);
1466
1494
  this.code.line(' */');
1467
1495
  this.emitStabilityAnnotations(cls.initializer);
1468
- this.code.openBlock(`public static final class ${BUILDER_CLASS_NAME} implements software.amazon.jsii.Builder<${builtType}>`);
1496
+ this.code.openBlock(`public static final class ${BUILDER_CLASS_NAME} implements software.amazon.jsii.Builder<${displayStatic(builtType)}>`);
1469
1497
  // Static factory method(s)
1470
1498
  for (const params of computeOverrides(positionalParams)) {
1471
1499
  const dummyMethod = {
@@ -1483,7 +1511,7 @@ class JavaGenerator extends generator_1.Generator {
1483
1511
  });
1484
1512
  this.emitStabilityAnnotations(cls.initializer);
1485
1513
  this.code.openBlock(`public static ${BUILDER_CLASS_NAME} create(${params
1486
- .map((param) => `final ${param.javaType}${param.param.variadic ? '...' : ''} ${param.fieldName}`)
1514
+ .map((param) => `final ${displayStatic(param.javaType)}${param.param.variadic ? '...' : ''} ${param.fieldName}`)
1487
1515
  .join(', ')})`);
1488
1516
  this.code.line(`return new ${BUILDER_CLASS_NAME}(${positionalParams
1489
1517
  .map((param, idx) => (idx < params.length ? param.fieldName : 'null'))
@@ -1493,13 +1521,13 @@ class JavaGenerator extends generator_1.Generator {
1493
1521
  // Private properties
1494
1522
  this.code.line();
1495
1523
  for (const param of positionalParams) {
1496
- this.code.line(`private final ${param.javaType}${param.param.variadic ? '[]' : ''} ${param.fieldName};`);
1524
+ this.code.line(`private final ${displayStatic(param.javaType)}${param.param.variadic ? '[]' : ''} ${param.fieldName};`);
1497
1525
  }
1498
1526
  this.code.line(`private ${firstStruct.optional ? '' : 'final '}${structBuilder} ${structParamName};`);
1499
1527
  // Private constructor
1500
1528
  this.code.line();
1501
1529
  this.code.openBlock(`private ${BUILDER_CLASS_NAME}(${positionalParams
1502
- .map((param) => `final ${param.javaType}${param.param.variadic ? '...' : ''} ${param.fieldName}`)
1530
+ .map((param) => `final ${displayStatic(param.javaType)}${param.param.variadic ? '...' : ''} ${param.fieldName}`)
1503
1531
  .join(', ')})`);
1504
1532
  for (const param of positionalParams) {
1505
1533
  this.code.line(`this.${param.fieldName} = ${param.fieldName};`);
@@ -1527,16 +1555,14 @@ class JavaGenerator extends generator_1.Generator {
1527
1555
  },
1528
1556
  ],
1529
1557
  };
1530
- for (const javaType of this.toJavaTypes(prop.type.spec, {
1531
- covariant: true,
1532
- })) {
1558
+ for (const javaType of this.toJavaTypes(prop.type.spec)) {
1533
1559
  this.addJavaDocs(setter, {
1534
1560
  api: 'member',
1535
1561
  fqn: prop.definingType.fqn, // Could be inherited
1536
1562
  memberName: prop.name,
1537
1563
  });
1538
1564
  this.emitStabilityAnnotations(prop.spec);
1539
- this.code.openBlock(`public ${BUILDER_CLASS_NAME} ${fieldName}(final ${javaType} ${fieldName})`);
1565
+ this.code.openBlock(`public ${BUILDER_CLASS_NAME} ${fieldName}(final ${displayType(javaType, 'covariant')} ${fieldName})`);
1540
1566
  this.code.line(`this.${structParamName}${firstStruct.optional ? '()' : ''}.${fieldName}(${fieldName});`);
1541
1567
  this.code.line('return this;');
1542
1568
  this.code.closeBlock();
@@ -1545,11 +1571,11 @@ class JavaGenerator extends generator_1.Generator {
1545
1571
  // Final build method
1546
1572
  this.code.line();
1547
1573
  this.code.line('/**');
1548
- this.code.line(` * @return a newly built instance of {@link ${builtType}}.`);
1574
+ this.code.line(` * @return a newly built instance of {@link ${displayStatic(builtType)}}.`);
1549
1575
  this.code.line(' */');
1550
1576
  this.emitStabilityAnnotations(cls.initializer);
1551
1577
  this.code.line('@Override');
1552
- this.code.openBlock(`public ${builtType} build()`);
1578
+ this.code.openBlock(`public ${displayStatic(builtType)} build()`);
1553
1579
  const params = cls.initializer.parameters.map((param) => {
1554
1580
  if (param === firstStruct) {
1555
1581
  return firstStruct.optional
@@ -1558,7 +1584,7 @@ class JavaGenerator extends generator_1.Generator {
1558
1584
  }
1559
1585
  return `this.${positionalParams.find((p) => param === p.param).fieldName}`;
1560
1586
  });
1561
- this.code.indent(`return new ${builtType}(`);
1587
+ this.code.indent(`return new ${displayStatic(builtType)}(`);
1562
1588
  params.forEach((param, idx) => this.code.line(`${param}${idx < params.length - 1 ? ',' : ''}`));
1563
1589
  this.code.unindent(');');
1564
1590
  this.code.closeBlock();
@@ -1580,7 +1606,7 @@ class JavaGenerator extends generator_1.Generator {
1580
1606
  this.code.line('/**');
1581
1607
  this.code.line(` * Sets the value of {@link ${parentType.name}#${getterFor(prop.fieldName)}}`);
1582
1608
  const summary = prop.docs?.summary ?? 'the value to be set';
1583
- this.code.line(` * ${paramJavadoc(prop.fieldName, prop.nullable, summary)}`);
1609
+ this.code.line(` * ${this.paramJavadoc(prop.fieldName, prop.nullable, summary)}`);
1584
1610
  if (prop.docs?.remarks != null) {
1585
1611
  const indent = ' '.repeat(7 + prop.fieldName.length);
1586
1612
  const remarks = myMarkDownToJavaDoc(this.convertSamplesInMarkdown(prop.docs.remarks, {
@@ -1598,17 +1624,18 @@ class JavaGenerator extends generator_1.Generator {
1598
1624
  }
1599
1625
  this.code.line(' */');
1600
1626
  this.emitStabilityAnnotations(prop.spec);
1627
+ const renderedType = displayType(type, 'covariant');
1601
1628
  // We add an explicit cast if both types are generic but they are not identical (one is covariant, the other isn't)
1602
- const explicitCast = type.includes('<') &&
1603
- prop.fieldJavaType.includes('<') &&
1604
- type !== prop.fieldJavaType
1605
- ? `(${prop.fieldJavaType})`
1629
+ const explicitCast = renderedType.includes('<') &&
1630
+ prop.renderedFieldType.includes('<') &&
1631
+ renderedType !== prop.renderedFieldType
1632
+ ? `(${prop.renderedFieldType})`
1606
1633
  : '';
1607
1634
  if (explicitCast !== '') {
1608
1635
  // We'll be doing a safe, but unchecked cast, so suppress that warning
1609
1636
  this.code.line('@SuppressWarnings("unchecked")');
1610
1637
  }
1611
- this.code.openBlock(`public ${builderName} ${prop.fieldName}(${type} ${prop.fieldName})`);
1638
+ this.code.openBlock(`public ${typeVarDeclarations([type])}${builderName} ${prop.fieldName}(${renderedType} ${prop.fieldName})`);
1612
1639
  this.code.line(`this.${prop.fieldName} = ${explicitCast}${prop.fieldName};`);
1613
1640
  this.code.line('return this;');
1614
1641
  this.code.closeBlock();
@@ -1635,7 +1662,7 @@ class JavaGenerator extends generator_1.Generator {
1635
1662
  this.code.line(' */');
1636
1663
  this.emitStabilityAnnotations(classSpec);
1637
1664
  this.code.openBlock(`public static final class ${BUILDER_CLASS_NAME} implements software.amazon.jsii.Builder<${classSpec.name}>`);
1638
- props.forEach((prop) => this.code.line(`${prop.fieldJavaType} ${prop.fieldName};`));
1665
+ props.forEach((prop) => this.code.line(`${prop.renderedFieldType} ${prop.fieldName};`));
1639
1666
  props.forEach((prop) => this.emitBuilderSetter(prop, BUILDER_CLASS_NAME, classSpec));
1640
1667
  // Start build()
1641
1668
  this.code.line();
@@ -1680,7 +1707,7 @@ class JavaGenerator extends generator_1.Generator {
1680
1707
  this.code.line(ANN_INTERNAL);
1681
1708
  this.code.openBlock(`final class ${INTERFACE_PROXY_CLASS_NAME} extends software.amazon.jsii.JsiiObject implements ${ifc.name}`);
1682
1709
  // Immutable properties
1683
- props.forEach((prop) => this.code.line(`private final ${prop.fieldJavaType} ${prop.fieldName};`));
1710
+ props.forEach((prop) => this.code.line(`private final ${prop.renderedFieldType} ${prop.fieldName};`));
1684
1711
  // Start JSII reference constructor
1685
1712
  this.code.line();
1686
1713
  this.code.line('/**');
@@ -1689,7 +1716,7 @@ class JavaGenerator extends generator_1.Generator {
1689
1716
  this.code.line(' */');
1690
1717
  this.code.openBlock(`protected ${INTERFACE_PROXY_CLASS_NAME}(final software.amazon.jsii.JsiiObjectRef objRef)`);
1691
1718
  this.code.line('super(objRef);');
1692
- props.forEach((prop) => this.code.line(`this.${prop.fieldName} = software.amazon.jsii.Kernel.get(this, "${prop.jsiiName}", ${prop.fieldNativeType});`));
1719
+ props.forEach((prop) => this.code.line(`this.${prop.fieldName} = software.amazon.jsii.Kernel.get(this, "${prop.jsiiName}", ${prop.renderedNativeFieldType});`));
1693
1720
  this.code.closeBlock();
1694
1721
  // End JSII reference constructor
1695
1722
  // Start builder constructor
@@ -1697,14 +1724,14 @@ class JavaGenerator extends generator_1.Generator {
1697
1724
  this.code.line('/**');
1698
1725
  this.code.line(' * Constructor that initializes the object based on literal property values passed by the {@link Builder}.');
1699
1726
  this.code.line(' */');
1700
- if (props.some((prop) => prop.fieldJavaType !== prop.paramJavaType)) {
1727
+ if (props.some((prop) => prop.renderedFieldType !== prop.renderedParamType)) {
1701
1728
  this.code.line('@SuppressWarnings("unchecked")');
1702
1729
  }
1703
1730
  this.code.openBlock(`protected ${INTERFACE_PROXY_CLASS_NAME}(final ${BUILDER_CLASS_NAME} builder)`);
1704
1731
  this.code.line('super(software.amazon.jsii.JsiiObject.InitializationMode.JSII);');
1705
1732
  props.forEach((prop) => {
1706
- const explicitCast = prop.fieldJavaType !== prop.paramJavaType
1707
- ? `(${prop.fieldJavaType})`
1733
+ const explicitCast = prop.renderedFieldType !== prop.renderedParamType
1734
+ ? `(${prop.renderedFieldType})`
1708
1735
  : '';
1709
1736
  this.code.line(`this.${prop.fieldName} = ${explicitCast}${_validateIfNonOptional(`builder.${prop.fieldName}`, prop)};`);
1710
1737
  });
@@ -1714,7 +1741,7 @@ class JavaGenerator extends generator_1.Generator {
1714
1741
  props.forEach((prop) => {
1715
1742
  this.code.line();
1716
1743
  this.code.line('@Override');
1717
- this.code.openBlock(`public final ${prop.fieldJavaType} get${prop.propName}()`);
1744
+ this.code.openBlock(`public final ${prop.renderedFieldType} get${prop.propName}()`);
1718
1745
  this.code.line(`return this.${prop.fieldName};`);
1719
1746
  this.code.closeBlock();
1720
1747
  });
@@ -1855,8 +1882,11 @@ class JavaGenerator extends generator_1.Generator {
1855
1882
  return { filePath, name };
1856
1883
  }
1857
1884
  // eslint-disable-next-line complexity
1858
- addJavaDocs(doc, apiLoc, defaultText) {
1859
- if (!defaultText &&
1885
+ addJavaDocs(doc, apiLoc, unionHint) {
1886
+ const returnsUnion = unionHint?.returnsUnion && (0, type_utils_1.containsUnionType)(unionHint.returnsUnion)
1887
+ ? this.renderTypeReference(unionHint.returnsUnion)
1888
+ : undefined;
1889
+ if (!returnsUnion &&
1860
1890
  Object.keys(doc.docs ?? {}).length === 0 &&
1861
1891
  !(doc.parameters ?? []).some((p) => Object.keys(p.docs ?? {}).length !== 0)) {
1862
1892
  return;
@@ -1866,12 +1896,12 @@ class JavaGenerator extends generator_1.Generator {
1866
1896
  if (docs.summary) {
1867
1897
  paras.push(stripNewLines(myMarkDownToJavaDoc((0, _utils_1.renderSummary)(docs))));
1868
1898
  }
1869
- else if (defaultText) {
1870
- paras.push(myMarkDownToJavaDoc(defaultText));
1871
- }
1872
1899
  if (docs.remarks) {
1873
1900
  paras.push(myMarkDownToJavaDoc(this.convertSamplesInMarkdown(docs.remarks, apiLoc)).trimRight());
1874
1901
  }
1902
+ if (returnsUnion) {
1903
+ paras.push(`Returns union: ${returnsUnion}`);
1904
+ }
1875
1905
  if (docs.default) {
1876
1906
  paras.push(`Default: ${docs.default}`); // NOTE: there is no annotation in JavaDoc for this
1877
1907
  }
@@ -1907,7 +1937,7 @@ class JavaGenerator extends generator_1.Generator {
1907
1937
  if (method.parameters) {
1908
1938
  for (const param of method.parameters) {
1909
1939
  const summary = param.docs?.summary;
1910
- tagLines.push(paramJavadoc(param.name, param.optional, summary));
1940
+ tagLines.push(this.paramJavadoc(param.name, param.optional, summary, param.type));
1911
1941
  }
1912
1942
  }
1913
1943
  }
@@ -1927,134 +1957,150 @@ class JavaGenerator extends generator_1.Generator {
1927
1957
  }
1928
1958
  this.code.line(' */');
1929
1959
  }
1960
+ paramJavadoc(name, optional, summary, unionTypeHint) {
1961
+ const parts = ['@param', name];
1962
+ if (summary) {
1963
+ parts.push(stripNewLines(myMarkDownToJavaDoc(endWithPeriod(summary))));
1964
+ }
1965
+ if (unionTypeHint && (0, type_utils_1.containsUnionType)(unionTypeHint)) {
1966
+ parts.push(`Takes union: ${this.renderTypeReference(unionTypeHint)}.`);
1967
+ }
1968
+ if (!optional) {
1969
+ parts.push('This parameter is required.');
1970
+ }
1971
+ return parts.join(' ');
1972
+ }
1930
1973
  getClassBase(cls) {
1931
1974
  if (!cls.base) {
1932
- return 'software.amazon.jsii.JsiiObject';
1975
+ return mkStatic('software.amazon.jsii.JsiiObject');
1933
1976
  }
1934
- return this.toJavaType({ fqn: cls.base });
1977
+ return this.toJavaTypes({ fqn: cls.base })[0];
1935
1978
  }
1936
- toDecoratedJavaType(optionalValue, { covariant = false } = {}) {
1937
- const result = this.toDecoratedJavaTypes(optionalValue, { covariant });
1938
- if (result.length > 1) {
1939
- return `${optionalValue.optional ? ANN_NULLABLE : ANN_NOT_NULL} java.lang.Object`;
1940
- }
1941
- return result[0];
1979
+ /**
1980
+ * Convert an OptionalValue, adding the `NotNull` or `Nullable` declarations as appropriate
1981
+ */
1982
+ toDecoratedJavaTypes(optionalValue) {
1983
+ return annotateOptional(optionalValue, this.toJavaTypes(optionalValue.type));
1942
1984
  }
1943
- toDecoratedJavaTypes(optionalValue, { covariant = false } = {}) {
1944
- return this.toJavaTypes(optionalValue.type, { covariant }).map((nakedType) => `${optionalValue.optional ? ANN_NULLABLE : ANN_NOT_NULL} ${nakedType}`);
1985
+ /**
1986
+ * Renders a type without generic arguments
1987
+ *
1988
+ * Necessary because of type erasure; the compiler
1989
+ * will not let you check `foo instanceof Map<String, Foo>`,
1990
+ * and you must instead check `foo instanceof Map`.
1991
+ */
1992
+ toJavaTypeNoGenerics(type) {
1993
+ return forceSingleType(this.toJavaTypes(type)).typeSymbol;
1945
1994
  }
1946
- // Strips <*> from the type name.
1947
- // necessary, because of type erasure; the compiler
1948
- // will not let you check `foo instanceof Map<String, Foo>`,
1949
- // and you must instead check `foo instanceof Map`.
1950
- toJavaTypeNoGenerics(type, opts) {
1951
- const typeStr = this.toJavaType(type, opts);
1952
- const leftAngleBracketIdx = typeStr.indexOf('<');
1953
- const rightAngleBracketIdx = typeStr.indexOf('>');
1954
- if ((leftAngleBracketIdx < 0 && rightAngleBracketIdx >= 0) ||
1955
- (leftAngleBracketIdx >= 0 && rightAngleBracketIdx < 0)) {
1956
- throw new Error(`Invalid generic type: found ${typeStr}`);
1995
+ /**
1996
+ * Return the jsii object that represents this native type
1997
+ */
1998
+ toNativeType(type) {
1999
+ if (type.type === 'static' && type.typeSymbol === 'java.util.List') {
2000
+ const nativeElementType = this.toNativeType(type.typeArguments[0]);
2001
+ return `software.amazon.jsii.NativeType.listOf(${nativeElementType})`;
1957
2002
  }
1958
- return leftAngleBracketIdx > 0 && rightAngleBracketIdx > 0
1959
- ? typeStr.slice(0, leftAngleBracketIdx)
1960
- : typeStr;
1961
- }
1962
- toJavaType(type, opts) {
1963
- const types = this.toJavaTypes(type, opts);
1964
- if (types.length > 1) {
1965
- return 'java.lang.Object';
2003
+ if (type.type === 'static' && type.typeSymbol === 'java.util.Map') {
2004
+ const nativeElementType = this.toNativeType(type.typeArguments[1]);
2005
+ return `software.amazon.jsii.NativeType.mapOf(${nativeElementType})`;
1966
2006
  }
1967
- return types[0];
2007
+ return `software.amazon.jsii.NativeType.forClass(${marshallingType(type)})`;
1968
2008
  }
1969
- toNativeType(type, { forMarshalling = false, covariant = false } = {}) {
1970
- if (spec.isCollectionTypeReference(type)) {
1971
- const nativeElementType = this.toNativeType(type.collection.elementtype, {
1972
- forMarshalling,
1973
- covariant,
1974
- });
1975
- switch (type.collection.kind) {
1976
- case spec.CollectionKind.Array:
1977
- return `software.amazon.jsii.NativeType.listOf(${nativeElementType})`;
1978
- case spec.CollectionKind.Map:
1979
- return `software.amazon.jsii.NativeType.mapOf(${nativeElementType})`;
1980
- default:
1981
- throw new Error(`Unsupported collection kind: ${type.collection.kind}`);
1982
- }
1983
- }
1984
- return `software.amazon.jsii.NativeType.forClass(${this.toJavaType(type, {
1985
- forMarshalling,
1986
- covariant,
1987
- })}.class)`;
2009
+ /**
2010
+ * Convert a jsii type to a single Java type, collapsing to object if necessary
2011
+ */
2012
+ toSingleJavaType(typeref, { typeSymGen = undefined } = {}) {
2013
+ return forceSingleType(this.toJavaTypes(typeref, { typeSymGen }));
1988
2014
  }
1989
- toJavaTypes(typeref, { forMarshalling = false, covariant = false } = {}) {
2015
+ /**
2016
+ * Convert a jsii type to a union of Java types
2017
+ */
2018
+ toJavaTypes(typeref, { typeSymGen = undefined } = {}) {
2019
+ typeSymGen = typeSymGen ?? newTypeSymGen();
1990
2020
  if (spec.isPrimitiveTypeReference(typeref)) {
1991
2021
  return [this.toJavaPrimitive(typeref.primitive)];
1992
2022
  }
1993
2023
  else if (spec.isCollectionTypeReference(typeref)) {
1994
- return [this.toJavaCollection(typeref, { forMarshalling, covariant })];
2024
+ return [
2025
+ this.toJavaCollection(typeref, {
2026
+ typeSymGen,
2027
+ }),
2028
+ ];
1995
2029
  }
1996
2030
  else if (spec.isNamedTypeReference(typeref)) {
1997
- return [this.toNativeFqn(typeref.fqn)];
2031
+ const literal = (0, type_literals_1.literalTypeReference)(typeref);
2032
+ return literal
2033
+ ? [mkStatic(literal)]
2034
+ : [mkStatic(this.toNativeFqn(typeref.fqn))];
1998
2035
  }
1999
2036
  else if (spec.isUnionTypeReference(typeref)) {
2000
- const types = new Array();
2001
- for (const subtype of typeref.union.types) {
2002
- for (const t of this.toJavaTypes(subtype, {
2003
- forMarshalling,
2004
- covariant,
2005
- })) {
2006
- types.push(t);
2007
- }
2008
- }
2009
- return types;
2010
- }
2011
- throw new Error(`Invalid type reference: ${JSON.stringify(typeref)}`);
2012
- }
2013
- toJavaCollection(ref, { forMarshalling, covariant, }) {
2014
- const elementJavaType = this.toJavaType(ref.collection.elementtype, {
2015
- covariant,
2037
+ return typeref.union.types.flatMap((subtype) => this.toJavaTypes(subtype, { typeSymGen }));
2038
+ }
2039
+ else if (spec.isIntersectionTypeReference(typeref)) {
2040
+ const typeVariable = typeSymGen();
2041
+ return [
2042
+ mkParam(typeVariable, `${typeVariable} extends ${typeref.intersection.types
2043
+ // Take the first type of any given union (an intersect-of-union
2044
+ // would have been rejected by jsii-compiler anyway)
2045
+ .map((t) => displayStatic(this.toJavaTypes(t)[0]))
2046
+ .join(' & ')}`),
2047
+ ];
2048
+ }
2049
+ throw new Error(`Unrenderable type reference: ${JSON.stringify(typeref)}`);
2050
+ }
2051
+ toJavaCollection(ref, { typeSymGen }) {
2052
+ const elementJavaType = this.toSingleJavaType(ref.collection.elementtype, {
2053
+ typeSymGen,
2016
2054
  });
2017
- const typeConstraint = covariant
2018
- ? makeCovariant(elementJavaType)
2019
- : elementJavaType;
2020
2055
  switch (ref.collection.kind) {
2021
2056
  case spec.CollectionKind.Array:
2022
- return forMarshalling
2023
- ? 'java.util.List'
2024
- : `java.util.List<${typeConstraint}>`;
2057
+ return mkStatic('java.util.List', [elementJavaType]);
2025
2058
  case spec.CollectionKind.Map:
2026
- return forMarshalling
2027
- ? 'java.util.Map'
2028
- : `java.util.Map<java.lang.String, ${typeConstraint}>`;
2059
+ return mkStatic('java.util.Map', [
2060
+ mkStatic('java.lang.String'),
2061
+ elementJavaType,
2062
+ ]);
2029
2063
  default:
2030
2064
  throw new Error(`Unsupported collection kind: ${ref.collection.kind}`);
2031
2065
  }
2032
- function makeCovariant(javaType) {
2033
- // Don't emit a covariant expression for String (it's `final` in Java)
2034
- if (javaType === 'java.lang.String') {
2035
- return javaType;
2036
- }
2037
- return `? extends ${javaType}`;
2038
- }
2039
2066
  }
2040
2067
  toJavaPrimitive(primitive) {
2041
2068
  switch (primitive) {
2042
2069
  case spec.PrimitiveType.Boolean:
2043
- return 'java.lang.Boolean';
2070
+ return mkStatic('java.lang.Boolean');
2044
2071
  case spec.PrimitiveType.Date:
2045
- return 'java.time.Instant';
2072
+ return mkStatic('java.time.Instant');
2046
2073
  case spec.PrimitiveType.Json:
2047
- return 'com.fasterxml.jackson.databind.node.ObjectNode';
2074
+ return mkStatic('com.fasterxml.jackson.databind.node.ObjectNode');
2048
2075
  case spec.PrimitiveType.Number:
2049
- return 'java.lang.Number';
2076
+ return mkStatic('java.lang.Number');
2050
2077
  case spec.PrimitiveType.String:
2051
- return 'java.lang.String';
2078
+ return mkStatic('java.lang.String');
2052
2079
  case spec.PrimitiveType.Any:
2053
- return 'java.lang.Object';
2080
+ return mkStatic('java.lang.Object');
2054
2081
  default:
2055
2082
  throw new Error(`Unknown primitive type: ${primitive}`);
2056
2083
  }
2057
2084
  }
2085
+ /**
2086
+ * Render a type reference to something human readable for use in JavaDocs
2087
+ */
2088
+ renderTypeReference(x) {
2089
+ return (0, type_visitor_1.visitTypeReference)(x, {
2090
+ primitive: (x) => `{@link ${this.toJavaPrimitive(x.primitive).typeSymbol}}`,
2091
+ named: (x) => `{@link ${this.toNativeFqn(x.fqn)}}`,
2092
+ collection: (x) => {
2093
+ switch (x.collection.kind) {
2094
+ case spec.CollectionKind.Array:
2095
+ return `List<${this.renderTypeReference(x.collection.elementtype)}>`;
2096
+ case spec.CollectionKind.Map:
2097
+ return `Map<String, ${this.renderTypeReference(x.collection.elementtype)}>`;
2098
+ }
2099
+ },
2100
+ union: (x) => `either ${x.union.types.map((x) => this.renderTypeReference(x)).join(' or ')}`,
2101
+ intersection: (x) => `${x.intersection.types.map((x) => this.renderTypeReference(x)).join(' + ')}`,
2102
+ });
2103
+ }
2058
2104
  renderMethodCallArguments(method) {
2059
2105
  if (!method.parameters || method.parameters.length === 0) {
2060
2106
  return '';
@@ -2082,17 +2128,16 @@ class JavaGenerator extends generator_1.Generator {
2082
2128
  renderMethodCall(cls, method, async) {
2083
2129
  let statement = '';
2084
2130
  if (method.static) {
2085
- const javaClass = this.toJavaType(cls);
2086
- statement += `software.amazon.jsii.JsiiObject.jsiiStaticCall(${javaClass}.class, `;
2131
+ const javaClass = this.toSingleJavaType(cls);
2132
+ statement += `software.amazon.jsii.JsiiObject.jsiiStaticCall(${displayStatic(javaClass)}.class, `;
2087
2133
  }
2088
2134
  else {
2089
2135
  statement += `software.amazon.jsii.Kernel.${async ? 'asyncCall' : 'call'}(this, `;
2090
2136
  }
2091
2137
  statement += `"${method.name}"`;
2092
2138
  if (method.returns) {
2093
- statement += `, ${this.toNativeType(method.returns.type, {
2094
- forMarshalling: true,
2095
- })}`;
2139
+ const returnsType = forceSingleType(this.toJavaTypes(method.returns.type));
2140
+ statement += `, ${this.toNativeType(returnsType)}`;
2096
2141
  }
2097
2142
  else {
2098
2143
  statement += ', software.amazon.jsii.NativeType.VOID';
@@ -2128,20 +2173,28 @@ class JavaGenerator extends generator_1.Generator {
2128
2173
  }
2129
2174
  // In the case of "optional", the value needs ot be explicitly cast to allow for cases where the raw type was returned.
2130
2175
  return optional
2131
- ? `java.util.Optional.ofNullable((${this.toJavaType(type)})(${statement})).map(java.util.Collections::${wrapper}).orElse(null)`
2176
+ ? `java.util.Optional.ofNullable((${displayStatic(this.toSingleJavaType(type))})(${statement})).map(java.util.Collections::${wrapper}).orElse(null)`
2132
2177
  : `java.util.Collections.${wrapper}(${statement})`;
2133
2178
  }
2134
2179
  return statement;
2135
2180
  }
2136
- renderMethodParameters(method) {
2181
+ convertTypes(parameters) {
2182
+ return (parameters ?? []).map((p) => {
2183
+ return forceSingleType(this.toDecoratedJavaTypes(p));
2184
+ });
2185
+ }
2186
+ renderParameters(parameters, types, overridable) {
2187
+ parameters = parameters ?? [];
2188
+ if (parameters.length !== types.length) {
2189
+ throw new Error(`Arrays not same length: ${parameters.length} !== ${types.length}`);
2190
+ }
2191
+ // We can render covariant parameters only for methods that aren't overridable... so only for static methods currently.
2192
+ // (There are some more places where we could do this, like properties and constructors, but historically we didn't
2193
+ // and I don't want to mess with this too much because the risk/reward isn't there.)
2194
+ const cov = overridable === 'final' ? 'covariant' : undefined;
2137
2195
  const params = [];
2138
- if (method.parameters) {
2139
- for (const p of method.parameters) {
2140
- // We can render covariant parameters only for methods that aren't overridable... so only for static methods currently.
2141
- params.push(`final ${this.toDecoratedJavaType(p, {
2142
- covariant: method.static,
2143
- })}${p.variadic ? '...' : ''} ${JavaGenerator.safeJavaPropertyName(p.name)}`);
2144
- }
2196
+ for (const [p, type] of (0, util_1.zip)(parameters, types)) {
2197
+ params.push(`final ${displayType(type, cov)}${p.variadic ? '...' : ''} ${JavaGenerator.safeJavaPropertyName(p.name)}`);
2145
2198
  }
2146
2199
  return params.join(', ');
2147
2200
  }
@@ -2451,16 +2504,6 @@ function isNullable(optionalValue) {
2451
2504
  (spec.isPrimitiveTypeReference(optionalValue.type) &&
2452
2505
  optionalValue.type.primitive === spec.PrimitiveType.Any));
2453
2506
  }
2454
- function paramJavadoc(name, optional, summary) {
2455
- const parts = ['@param', name];
2456
- if (summary) {
2457
- parts.push(stripNewLines(myMarkDownToJavaDoc(endWithPeriod(summary))));
2458
- }
2459
- if (!optional) {
2460
- parts.push('This parameter is required.');
2461
- }
2462
- return parts.join(' ');
2463
- }
2464
2507
  function endWithPeriod(s) {
2465
2508
  s = s.trimRight();
2466
2509
  if (!s.endsWith('.')) {
@@ -2602,11 +2645,6 @@ function splitNamespace(ns) {
2602
2645
  function escape(s) {
2603
2646
  return s.replace(/["\\<>&]/g, (c) => `&#${c.charCodeAt(0)};`);
2604
2647
  }
2605
- function containsUnionType(typeRef) {
2606
- return (spec.isUnionTypeReference(typeRef) ||
2607
- (spec.isCollectionTypeReference(typeRef) &&
2608
- containsUnionType(typeRef.collection.elementtype)));
2609
- }
2610
2648
  function myMarkDownToJavaDoc(source) {
2611
2649
  if (source.includes('{@link') || source.includes('{@code')) {
2612
2650
  // Slightly dirty hack: if we are seeing this, it means the docstring was provided literally
@@ -2625,4 +2663,155 @@ function stripNewLines(x) {
2625
2663
  function escapeEndingComment(x) {
2626
2664
  return x.replace(/\*\//g, '*\\/');
2627
2665
  }
2666
+ function newTypeSymGen() {
2667
+ let cnt = 1;
2668
+ return () => {
2669
+ return `T${cnt++}`;
2670
+ };
2671
+ }
2672
+ function mkStatic(typeSymbol, typeArguments = []) {
2673
+ return { typeSymbol, annotation: '', type: 'static', typeArguments };
2674
+ }
2675
+ function mkParam(typeVariable, typeVarDeclaration) {
2676
+ return {
2677
+ type: 'param',
2678
+ annotation: '',
2679
+ typeSymbol: typeVariable,
2680
+ typeVariable,
2681
+ typeVarDeclaration,
2682
+ };
2683
+ }
2684
+ function displayStatic(x, options) {
2685
+ if (x.type !== 'static') {
2686
+ throw new Error(`Expected static type here, got ${JSON.stringify(x)}`);
2687
+ }
2688
+ return displayType(x, options);
2689
+ }
2690
+ function displayType(x, options) {
2691
+ switch (x.type) {
2692
+ case 'param':
2693
+ return `${x.annotation}${x.typeSymbol}`;
2694
+ case 'static':
2695
+ return [
2696
+ `${x.annotation}${x.typeSymbol}`,
2697
+ (x.typeArguments ?? []).length > 0
2698
+ ? `<${x
2699
+ .typeArguments.map((t, i) => {
2700
+ const subT = displayType(t, options);
2701
+ // For Map<K, V> we only want to make V covariant.
2702
+ // Since that's and List<T> are the only types we have generics
2703
+ // for anyway, we hack it here (as opposed to storing a field on
2704
+ // the type object itself). This is simpler and Good Enough For Now(tm).
2705
+ const isLastParameter = i === (x.typeArguments ?? []).length - 1;
2706
+ // Don't emit a covariant expression for String (it's `final` in Java)
2707
+ const isString = subT === 'java.lang.String';
2708
+ return options === 'covariant' && isLastParameter && !isString
2709
+ ? `? extends ${subT}`
2710
+ : subT;
2711
+ })
2712
+ .join(', ')}>`
2713
+ : '',
2714
+ ].join('');
2715
+ }
2716
+ }
2717
+ function typeVarDeclarations(types) {
2718
+ const ret = [];
2719
+ for (const t of types) {
2720
+ recurse(t);
2721
+ }
2722
+ return ret.length > 0 ? `<${ret.join(', ')}> ` : '';
2723
+ function recurse(t) {
2724
+ switch (t.type) {
2725
+ case 'param':
2726
+ ret.push(t.typeVarDeclaration);
2727
+ break;
2728
+ case 'static':
2729
+ for (const arg of t.typeArguments ?? []) {
2730
+ recurse(arg);
2731
+ }
2732
+ break;
2733
+ }
2734
+ }
2735
+ }
2736
+ function typesEqual(a, b, opts) {
2737
+ if (a.type !== b.type) {
2738
+ return false;
2739
+ }
2740
+ if (a.typeSymbol !== b.typeSymbol) {
2741
+ return false;
2742
+ }
2743
+ if (a.type === 'static' && b.type === 'static' && opts === 'deep') {
2744
+ if (a.typeArguments?.length !== b.typeArguments?.length) {
2745
+ return false;
2746
+ }
2747
+ if (a.typeArguments) {
2748
+ for (let i = 0; i < a.typeArguments.length; i++) {
2749
+ if (!typesEqual(a.typeArguments[i], b.typeArguments[i])) {
2750
+ return false;
2751
+ }
2752
+ }
2753
+ }
2754
+ }
2755
+ return true;
2756
+ }
2757
+ // endregion
2758
+ /**
2759
+ * Return a reference for the marshalling class object
2760
+ *
2761
+ * Basically returns `Type.class`, disregarding any generic
2762
+ * type arguments.
2763
+ */
2764
+ function marshallingType(x) {
2765
+ switch (x.type) {
2766
+ case 'static':
2767
+ return `${x.typeSymbol}.class`;
2768
+ case 'param':
2769
+ throw new Error(`Cannot marshall a type parameter: ${JSON.stringify(x)}`);
2770
+ }
2771
+ }
2772
+ /**
2773
+ * Return the one type from a union, or collapse to Object if there's more than one type in the union
2774
+ */
2775
+ function forceSingleType(types) {
2776
+ if (types.length > 1) {
2777
+ return {
2778
+ ...mkStatic('java.lang.Object'),
2779
+ // Copy the annotation
2780
+ annotation: types[0].annotation,
2781
+ };
2782
+ }
2783
+ return types[0];
2784
+ }
2785
+ function annotateOptional(optionalValue, types) {
2786
+ return types.map((t) => ({
2787
+ ...t,
2788
+ annotation: `${optionalValue.optional ? ANN_NULLABLE : ANN_NOT_NULL} `,
2789
+ }));
2790
+ }
2791
+ /**
2792
+ * Resolve any type intersections to the first type
2793
+ */
2794
+ function removeIntersections(x) {
2795
+ if (spec.isIntersectionTypeReference(x)) {
2796
+ return x.intersection.types[0];
2797
+ }
2798
+ if (spec.isUnionTypeReference(x)) {
2799
+ return {
2800
+ ...x,
2801
+ union: {
2802
+ types: x.union.types.map(removeIntersections),
2803
+ },
2804
+ };
2805
+ }
2806
+ if (spec.isCollectionTypeReference(x)) {
2807
+ return {
2808
+ ...x,
2809
+ collection: {
2810
+ kind: x.collection.kind,
2811
+ elementtype: removeIntersections(x.collection.elementtype),
2812
+ },
2813
+ };
2814
+ }
2815
+ return x;
2816
+ }
2628
2817
  //# sourceMappingURL=java.js.map