Skip to content

Commit 6e91eb7

Browse files
authored
fix(java): Correctly pass variadic arguments (#465)
The previous iteration was incorrectly forwarding variadic methods' "rest" argument to the JSII runtime, causing a runtime failure at the deserialization site.
1 parent 3a6b21c commit 6e91eb7

File tree

4 files changed

+33
-6
lines changed

4 files changed

+33
-6
lines changed

packages/jsii-java-runtime-test/project/src/test/java/software/amazon/jsii/testing/ComplianceTest.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
import software.amazon.jsii.tests.calculator.SyncVirtualMethods;
5151
import software.amazon.jsii.tests.calculator.UnionProperties;
5252
import software.amazon.jsii.tests.calculator.UsesInterfaceWithProperties;
53+
import software.amazon.jsii.tests.calculator.VariadicMethod;
5354
import software.amazon.jsii.tests.calculator.composition.CompositeOperation;
5455
import software.amazon.jsii.tests.calculator.lib.EnumFromScopedModule;
5556
import software.amazon.jsii.tests.calculator.lib.IFriendly;
@@ -1029,6 +1030,13 @@ public void objectIdDoesNotGetReallocatedWhenTheConstructorPassesThisOut() {
10291030
assertTrue(object != null);
10301031
}
10311032

1033+
@Test
1034+
public void variadicMethodCanBeInvoked() {
1035+
final VariadicMethod variadicMethod = new VariadicMethod(1);
1036+
final List<java.lang.Number> result = variadicMethod.asArray(3, 4, 5, 6);
1037+
assertEquals(Arrays.asList(1, 3, 4, 5, 6), result);
1038+
}
1039+
10321040
static class PartiallyInitializedThisConsumerImpl extends PartiallyInitializedThisConsumer {
10331041
@Override
10341042
public String consumePartiallyInitializedThis(final ConstructorPassesThisOut obj,

packages/jsii-pacmak/lib/targets/java.ts

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -997,9 +997,28 @@ class JavaGenerator extends Generator {
997997

998998
private renderMethodCallArguments(method: spec.Method) {
999999
if (!method.parameters || method.parameters.length === 0) { return ''; }
1000-
const values = method.parameters.map(param =>
1001-
isNullable(param) ? param.name : `java.util.Objects.requireNonNull(${param.name}, "${param.name} is required")`);
1002-
return `, new Object[] { ${values.join(', ')} }`;
1000+
const regularParams = method.parameters.filter(p => !p.variadic);
1001+
const values = regularParams.map(_renderParameter);
1002+
const valueStr = `new Object[] { ${values.join(', ')} }`;
1003+
if (method.variadic) {
1004+
const valuesStream = `java.util.Arrays.<Object>stream(${valueStr})`;
1005+
1006+
const lastParam = method.parameters[method.parameters.length - 1];
1007+
const restStream = `java.util.Arrays.<Object>stream(${lastParam.name})`;
1008+
1009+
const fullStream = regularParams.length > 0
1010+
? `java.util.stream.Stream.concat(${valuesStream}, ${restStream})`
1011+
: restStream;
1012+
return `, ${fullStream}.toArray(Object[]::new)`;
1013+
} else {
1014+
return `, ${valueStr}`;
1015+
}
1016+
1017+
function _renderParameter(param: spec.Parameter) {
1018+
return isNullable(param)
1019+
? param.name
1020+
: `java.util.Objects.requireNonNull(${param.name}, "${param.name} is required")`;
1021+
}
10031022
}
10041023

10051024
private renderMethodCall(cls: spec.TypeReference, method: spec.Method, async: boolean) {

packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/DontComplainAboutVariadicAfterOptional.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@ public DontComplainAboutVariadicAfterOptional() {
1212
}
1313

1414
public java.lang.String optionalAndVariadic(@javax.annotation.Nullable final java.lang.String optional, final java.lang.String... things) {
15-
return this.jsiiCall("optionalAndVariadic", java.lang.String.class, new Object[] { optional, java.util.Objects.requireNonNull(things, "things is required") });
15+
return this.jsiiCall("optionalAndVariadic", java.lang.String.class, java.util.stream.Stream.concat(java.util.Arrays.<Object>stream(new Object[] { optional }), java.util.Arrays.<Object>stream(things)).toArray(Object[]::new));
1616
}
1717
}

packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/VariadicMethod.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@ protected VariadicMethod(final software.amazon.jsii.JsiiObject.InitializationMod
1111
*/
1212
public VariadicMethod(final java.lang.Number... prefix) {
1313
super(software.amazon.jsii.JsiiObject.InitializationMode.Jsii);
14-
software.amazon.jsii.JsiiEngine.getInstance().createNewObject(this, new Object[] { java.util.Objects.requireNonNull(prefix, "prefix is required") });
14+
software.amazon.jsii.JsiiEngine.getInstance().createNewObject(this, java.util.Arrays.<Object>stream(prefix).toArray(Object[]::new));
1515
}
1616

1717
/**
1818
* @param first the first element of the array to be returned (after the `prefix` provided at construction time).
1919
* @param others other elements to be included in the array.
2020
*/
2121
public java.util.List<java.lang.Number> asArray(final java.lang.Number first, final java.lang.Number... others) {
22-
return this.jsiiCall("asArray", java.util.List.class, new Object[] { java.util.Objects.requireNonNull(first, "first is required"), java.util.Objects.requireNonNull(others, "others is required") });
22+
return this.jsiiCall("asArray", java.util.List.class, java.util.stream.Stream.concat(java.util.Arrays.<Object>stream(new Object[] { java.util.Objects.requireNonNull(first, "first is required") }), java.util.Arrays.<Object>stream(others)).toArray(Object[]::new));
2323
}
2424
}

0 commit comments

Comments
 (0)