From bb4ec5f79c02429f7889dfa201a1b66ea672a2b1 Mon Sep 17 00:00:00 2001 From: Zheng Feng Date: Thu, 2 Jun 2022 14:43:28 +0800 Subject: [PATCH] add a test for lambda capturing --- .../quarkus/it/rest/ReflectionResource.java | 13 ++++++ .../io/quarkus/it/rest/ResourceLambda.java | 40 +++++++++++++++++++ .../it/rest/SerializableDoubleFunction.java | 17 ++++++++ .../src/main/resources/application.properties | 1 + .../main/resources/serialization-config.json | 9 +++++ .../it/main/RegisterForReflectionITCase.java | 11 +++++ .../main/RegisterForReflectionTestCase.java | 9 +++++ 7 files changed, 100 insertions(+) create mode 100644 integration-tests/main/src/main/java/io/quarkus/it/rest/ResourceLambda.java create mode 100644 integration-tests/main/src/main/java/io/quarkus/it/rest/SerializableDoubleFunction.java create mode 100644 integration-tests/main/src/main/resources/serialization-config.json diff --git a/integration-tests/main/src/main/java/io/quarkus/it/rest/ReflectionResource.java b/integration-tests/main/src/main/java/io/quarkus/it/rest/ReflectionResource.java index 6a3227b8f31ee..4ced953e49df0 100644 --- a/integration-tests/main/src/main/java/io/quarkus/it/rest/ReflectionResource.java +++ b/integration-tests/main/src/main/java/io/quarkus/it/rest/ReflectionResource.java @@ -17,4 +17,17 @@ public String getSimpleClassName(@QueryParam("className") String className) { return "FAILED"; } } + + @GET + @Path("/lambda") + public String getLambdaClassName() { + try { + ResourceLambda lambda = new ResourceLambda(); + Class clazz = lambda.getLambdaFuncClass(5); + return clazz.getSimpleName(); + } catch (Exception e) { + return e.toString(); + } + } + } diff --git a/integration-tests/main/src/main/java/io/quarkus/it/rest/ResourceLambda.java b/integration-tests/main/src/main/java/io/quarkus/it/rest/ResourceLambda.java new file mode 100644 index 0000000000000..aa262c4e00edf --- /dev/null +++ b/integration-tests/main/src/main/java/io/quarkus/it/rest/ResourceLambda.java @@ -0,0 +1,40 @@ +package io.quarkus.it.rest; + +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.lang.invoke.SerializedLambda; +import java.util.Comparator; + +import io.quarkus.runtime.annotations.RegisterForReflection; + +/** + * This class is registering itself for lambda capturing + */ +@RegisterForReflection(lambdaCapturingTypes = "java.util.Comparator", targets = { + SerializedLambda.class, SerializableDoubleFunction.class }, serialization = true) +public class ResourceLambda { + private static final String file = "target/serialized.txt"; + + public Class getLambdaFuncClass(Integer n) throws IOException, ClassNotFoundException { + SerializableDoubleFunction func = new SerializableDoubleFunction(n); + Comparator comp = Comparator.comparingDouble(func); + serializeObject(comp); + return deserializeObject().getClass(); + } + + private void serializeObject(Object o) throws IOException { + FileOutputStream out = new FileOutputStream(file); + ObjectOutputStream objectOutputStream = new ObjectOutputStream(out); + objectOutputStream.writeObject(o); + objectOutputStream.close(); + } + + private Object deserializeObject() throws IOException, ClassNotFoundException { + FileInputStream in = new FileInputStream(file); + ObjectInputStream objectInputStream = new ObjectInputStream(in); + return objectInputStream.readObject(); + } +} diff --git a/integration-tests/main/src/main/java/io/quarkus/it/rest/SerializableDoubleFunction.java b/integration-tests/main/src/main/java/io/quarkus/it/rest/SerializableDoubleFunction.java new file mode 100644 index 0000000000000..5bfa0f0b93ecc --- /dev/null +++ b/integration-tests/main/src/main/java/io/quarkus/it/rest/SerializableDoubleFunction.java @@ -0,0 +1,17 @@ +package io.quarkus.it.rest; + +import java.io.Serializable; +import java.util.function.ToDoubleFunction; + +class SerializableDoubleFunction implements Serializable, ToDoubleFunction { + private final double value; + + public SerializableDoubleFunction(double inputValue) { + value = inputValue; + } + + @Override + public double applyAsDouble(Integer o) { + return value; + } +} diff --git a/integration-tests/main/src/main/resources/application.properties b/integration-tests/main/src/main/resources/application.properties index a6e7df99951e9..d475fde49725c 100644 --- a/integration-tests/main/src/main/resources/application.properties +++ b/integration-tests/main/src/main/resources/application.properties @@ -52,6 +52,7 @@ quarkus.native.resources.excludes = **/unwanted.* quarkus.log.metrics.enabled=true +#quarkus.native.additional-build-args =-H:ReflectionConfigurationFiles=reflection-config.json,-H:SerializationConfigurationResources=serialization-config.json quarkus.native.additional-build-args =-H:ReflectionConfigurationFiles=reflection-config.json quarkus.class-loading.removed-resources."io.quarkus\:quarkus-integration-test-shared-library"=io/quarkus/it/shared/RemovedResource.class quarkus.class-loading.removed-resources."io.quarkus\:quarkus-integration-test-main"=io/quarkus/it/rest/RemovedJaxRsApplication.class diff --git a/integration-tests/main/src/main/resources/serialization-config.json b/integration-tests/main/src/main/resources/serialization-config.json new file mode 100644 index 0000000000000..c6df476fbdbc6 --- /dev/null +++ b/integration-tests/main/src/main/resources/serialization-config.json @@ -0,0 +1,9 @@ +{ + "types":[ + {"name":"io.quarkus.it.rest.SerializableDoubleFunction"}, + {"name":"java.lang.invoke.SerializedLambda"} + ], + "lambdaCapturingTypes":[ + {"name":"java.util.Comparator"} + ] +} diff --git a/integration-tests/main/src/test/java/io/quarkus/it/main/RegisterForReflectionITCase.java b/integration-tests/main/src/test/java/io/quarkus/it/main/RegisterForReflectionITCase.java index 0a029bb77e394..af22bc1ae7443 100644 --- a/integration-tests/main/src/test/java/io/quarkus/it/main/RegisterForReflectionITCase.java +++ b/integration-tests/main/src/test/java/io/quarkus/it/main/RegisterForReflectionITCase.java @@ -1,6 +1,7 @@ package io.quarkus.it.main; import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.startsWith; import org.junit.jupiter.api.Test; @@ -68,6 +69,16 @@ public void testTargetWithoutNested() { assertRegistration("FAILED", resourceD + "$StaticClassOfD$OtherAccessibleClassOfD"); } + @Test + @DisableIfBuiltWithGraalVMOlderThan(GraalVMVersion.GRAALVM_22_1) + public void testLambdaCapturing() { + final String resourceLambda = BASE_PKG + ".ResourceLambda"; + + // Starting with GraalVM 22.1 support Lambda functions serialization + // (see https://github.com/oracle/graal/issues/3756) + RestAssured.given().when().get("/reflection/lambda").then().body(startsWith("Comparator$$Lambda$")); + } + private void assertRegistration(String expected, String queryParam) { RestAssured.given().queryParam("className", queryParam).when().get(ENDPOINT).then().body(is(expected)); } diff --git a/integration-tests/main/src/test/java/io/quarkus/it/main/RegisterForReflectionTestCase.java b/integration-tests/main/src/test/java/io/quarkus/it/main/RegisterForReflectionTestCase.java index 377613fac5c99..8fc4235a14cb0 100644 --- a/integration-tests/main/src/test/java/io/quarkus/it/main/RegisterForReflectionTestCase.java +++ b/integration-tests/main/src/test/java/io/quarkus/it/main/RegisterForReflectionTestCase.java @@ -1,6 +1,7 @@ package io.quarkus.it.main; import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.startsWith; import org.junit.jupiter.api.Test; @@ -51,6 +52,14 @@ public void testTargetWithoutNested() { assertRegistration("OtherAccessibleClassOfD", resourceD + "$StaticClassOfD$OtherAccessibleClassOfD"); } + @Test + public void testLambdaCapturing() { + final String resourceLambda = BASE_PKG + ".ResourceLambda"; + + assertRegistration("ResourceLambda", resourceLambda); + RestAssured.given().when().get("/reflection/lambda").then().body(startsWith("Comparator$$Lambda$")); + } + private void assertRegistration(String expected, String queryParam) { RestAssured.given().queryParam("className", queryParam).when().get(ENDPOINT).then().body(is(expected)); }