From 9d85f1c6345d8f9f08099679dc2a8e340cd78b24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9F=91=A8=F0=9F=8F=BC=E2=80=8D=F0=9F=92=BB=20Romain=20M?= =?UTF-8?q?arcadier-Muller?= Date: Wed, 17 Apr 2019 09:21:16 +0200 Subject: [PATCH] fix(java): Correctly pass variadic arguments The previous iteration was incorrectly forwarding variadic methods' "rest" argument to the JSII runtime, causing a runtime failure at the deserialization site. --- .../amazon/jsii/testing/ComplianceTest.java | 8 ++++++ packages/jsii-pacmak/lib/targets/java.ts | 25 ++++++++++++++++--- ...ontComplainAboutVariadicAfterOptional.java | 2 +- .../jsii/tests/calculator/VariadicMethod.java | 4 +-- 4 files changed, 33 insertions(+), 6 deletions(-) diff --git a/packages/jsii-java-runtime-test/project/src/test/java/software/amazon/jsii/testing/ComplianceTest.java b/packages/jsii-java-runtime-test/project/src/test/java/software/amazon/jsii/testing/ComplianceTest.java index 227efb4ab6..d98dbd1ed2 100644 --- a/packages/jsii-java-runtime-test/project/src/test/java/software/amazon/jsii/testing/ComplianceTest.java +++ b/packages/jsii-java-runtime-test/project/src/test/java/software/amazon/jsii/testing/ComplianceTest.java @@ -50,6 +50,7 @@ import software.amazon.jsii.tests.calculator.SyncVirtualMethods; import software.amazon.jsii.tests.calculator.UnionProperties; import software.amazon.jsii.tests.calculator.UsesInterfaceWithProperties; +import software.amazon.jsii.tests.calculator.VariadicMethod; import software.amazon.jsii.tests.calculator.composition.CompositeOperation; import software.amazon.jsii.tests.calculator.lib.EnumFromScopedModule; import software.amazon.jsii.tests.calculator.lib.IFriendly; @@ -1029,6 +1030,13 @@ public void objectIdDoesNotGetReallocatedWhenTheConstructorPassesThisOut() { assertTrue(object != null); } + @Test + public void variadicMethodCanBeInvoked() { + final VariadicMethod variadicMethod = new VariadicMethod(1); + final List result = variadicMethod.asArray(3, 4, 5, 6); + assertEquals(Arrays.asList(1, 3, 4, 5, 6), result); + } + static class PartiallyInitializedThisConsumerImpl extends PartiallyInitializedThisConsumer { @Override public String consumePartiallyInitializedThis(final ConstructorPassesThisOut obj, diff --git a/packages/jsii-pacmak/lib/targets/java.ts b/packages/jsii-pacmak/lib/targets/java.ts index 2a577d9223..04109d78f5 100644 --- a/packages/jsii-pacmak/lib/targets/java.ts +++ b/packages/jsii-pacmak/lib/targets/java.ts @@ -997,9 +997,28 @@ class JavaGenerator extends Generator { private renderMethodCallArguments(method: spec.Method) { if (!method.parameters || method.parameters.length === 0) { return ''; } - const values = method.parameters.map(param => - isNullable(param) ? param.name : `java.util.Objects.requireNonNull(${param.name}, "${param.name} is required")`); - return `, new Object[] { ${values.join(', ')} }`; + const regularParams = method.parameters.filter(p => !p.variadic); + const values = regularParams.map(_renderParameter); + const valueStr = `new Object[] { ${values.join(', ')} }`; + if (method.variadic) { + const valuesStream = `java.util.Arrays.stream(${valueStr})`; + + const lastParam = method.parameters[method.parameters.length - 1]; + const restStream = `java.util.Arrays.stream(${lastParam.name})`; + + const fullStream = regularParams.length > 0 + ? `java.util.stream.Stream.concat(${valuesStream}, ${restStream})` + : restStream; + return `, ${fullStream}.toArray(Object[]::new)`; + } else { + return `, ${valueStr}`; + } + + function _renderParameter(param: spec.Parameter) { + return isNullable(param) + ? param.name + : `java.util.Objects.requireNonNull(${param.name}, "${param.name} is required")`; + } } private renderMethodCall(cls: spec.TypeReference, method: spec.Method, async: boolean) { diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/DontComplainAboutVariadicAfterOptional.java b/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/DontComplainAboutVariadicAfterOptional.java index 325a1eb378..04bbf2c7ce 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/DontComplainAboutVariadicAfterOptional.java +++ b/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/DontComplainAboutVariadicAfterOptional.java @@ -12,6 +12,6 @@ public DontComplainAboutVariadicAfterOptional() { } public java.lang.String optionalAndVariadic(@javax.annotation.Nullable final java.lang.String optional, final java.lang.String... things) { - return this.jsiiCall("optionalAndVariadic", java.lang.String.class, new Object[] { optional, java.util.Objects.requireNonNull(things, "things is required") }); + return this.jsiiCall("optionalAndVariadic", java.lang.String.class, java.util.stream.Stream.concat(java.util.Arrays.stream(new Object[] { optional }), java.util.Arrays.stream(things)).toArray(Object[]::new)); } } diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/VariadicMethod.java b/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/VariadicMethod.java index 912b4b1116..72602ae7da 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/VariadicMethod.java +++ b/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/VariadicMethod.java @@ -11,7 +11,7 @@ protected VariadicMethod(final software.amazon.jsii.JsiiObject.InitializationMod */ public VariadicMethod(final java.lang.Number... prefix) { super(software.amazon.jsii.JsiiObject.InitializationMode.Jsii); - software.amazon.jsii.JsiiEngine.getInstance().createNewObject(this, new Object[] { java.util.Objects.requireNonNull(prefix, "prefix is required") }); + software.amazon.jsii.JsiiEngine.getInstance().createNewObject(this, java.util.Arrays.stream(prefix).toArray(Object[]::new)); } /** @@ -19,6 +19,6 @@ public VariadicMethod(final java.lang.Number... prefix) { * @param others other elements to be included in the array. */ public java.util.List asArray(final java.lang.Number first, final java.lang.Number... others) { - 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") }); + return this.jsiiCall("asArray", java.util.List.class, java.util.stream.Stream.concat(java.util.Arrays.stream(new Object[] { java.util.Objects.requireNonNull(first, "first is required") }), java.util.Arrays.stream(others)).toArray(Object[]::new)); } }