Repository: quarkusio/quarkus
Issue: CoreSerializationInGraalITCase of integration test Main fails with latest GraalVM

### Describe the bug

CoreSerializationInGraalITCase of integration test Main fails with latest GraalVM. 

See https://github.com/graalvm/mandrel/runs/3296489189?check_suite_focus=true#step:9:440

### Expected behavior

Test should pass.

### Actual behavior

Test fails with:

```
[ERROR] io.quarkus.it.main.CoreSerializationInGraalITCase.testEntitySerializationFromServlet  Time elapsed: 0.052 s  <<< FAILURE!
java.lang.AssertionError: 
1 expectation failed.
Response body doesn't match expectation.
Expected: is "OK"
  Actual: java.io.InvalidClassException: io.quarkus.it.corestuff.serialization.SomeSerializationObject; no valid constructor
	java.io.InvalidClassException: io.quarkus.it.corestuff.serialization.SomeSerializationObject; no valid constructor
	at java.io.ObjectStreamClass$ExceptionInfo.newInvalidClassException(ObjectStreamClass.java:159)
	at java.io.ObjectStreamClass.checkDeserialize(ObjectStreamClass.java:875)
	at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2170)
	at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1679)
	at java.io.ObjectInputStream.readObject(ObjectInputStream.java:493)
	at java.io.ObjectInputStream.readObject(ObjectInputStream.java:451)
	at io.quarkus.it.corestuff.SerializationTestEndpoint.reflectiveSetterInvoke(SerializationTestEndpoint.java:50)
	at io.quarkus.it.corestuff.SerializationTestEndpoint.doGet(SerializationTestEndpoint.java:29)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:503)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:590)
	at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74)
	at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:129)
	at io.opentracing.contrib.jaxrs2.server.SpanFinishingFilter.doFilter(SpanFinishingFilter.java:52)
	at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
	at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
	at io.quarkus.micrometer.runtime.binder.vertx.VertxMeterBinderUndertowServletFilter.doFilter(VertxMeterBinderUndertowServletFilter.java:28)
	at javax.servlet.http.HttpFilter.doFilter(HttpFilter.java:97)
	at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
	at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
	at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)
	at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:63)
	at io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)
	at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
	at io.undertow.servlet.handlers.RedirectDirHandler.handleRequest(RedirectDirHandler.java:67)
	at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:133)
	at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
	at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
	at io.undertow.security.handlers.AuthenticationConstraintHandler.handleRequest(AuthenticationConstraintHandler.java:53)
	at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
	at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:65)
	at io.undertow.servlet.handlers.security.ServletSecurityConstraintHandler.handleRequest(ServletSecurityConstraintHandler.java:59)
	at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
	at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
	at io.undertow.security.handlers.NotificationReceiverHandler.handleRequest(NotificationReceiverHandler.java:50)
	at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
	at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
	at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
	at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:247)
	at io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:56)
	at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:111)
	at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:108)
	at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
	at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
	at io.quarkus.undertow.runtime.UndertowDeploymentRecorder$9$1.call(UndertowDeploymentRecorder.java:589)
	at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:227)
	at io.undertow.servlet.handlers.ServletInitialHandler.handleRequest(ServletInitialHandler.java:152)
	at io.quarkus.undertow.runtime.UndertowDeploymentRecorder$1.handleRequest(UndertowDeploymentRecorder.java:119)
	at io.undertow.server.Connectors.executeRootHandler(Connectors.java:290)
	at io.undertow.server.DefaultExchangeHandler.handle(DefaultExchangeHandler.java:18)
	at io.quarkus.undertow.runtime.UndertowDeploymentRecorder$5$1.run(UndertowDeploymentRecorder.java:415)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
	at java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at io.quarkus.vertx.core.runtime.VertxCoreRecorder$13.runWith(VertxCoreRecorder.java:536)
	at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2449)
	at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1478)
	at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
	at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.lang.Thread.run(Thread.java:829)
	at com.oracle.svm.core.thread.JavaThreads.threadStartRoutine(JavaThreads.java:567)
	at com.oracle.svm.core.posix.thread.PosixJavaThreads.pthreadStartRoutine(PosixJavaThreads.java:192)
```

### How to Reproduce?

1. Download the "jdk" artifact from https://github.com/graalvm/mandrel/actions/runs/1118484129
2. Unzip it and then unarchive `jdk.tgz`
3. `export GRAALVM_HOME=path/to/extracted/mandrelvm`
4. `./mvnw -B --settings .github/mvn-settings.xml --fail-at-end  -DfailIfNoTests=false -Dnative -Dnative.surefire.skip -Dformat.skip -Dno-descriptor-tests -DskipDocs -Dquarkus.container-image.build=false -pl integration-tests/main verify`

### Output of `uname -a` or `ver`

Linux 5.12.15-300.fc34.x86_64 #1 SMP Wed Jul 7 19:46:50 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux

### Output of `java -version`

openjdk version "11.0.12" 2021-07-20 OpenJDK Runtime Environment 18.9 (build 11.0.12+7) OpenJDK 64-Bit Server VM 18.9 (build 11.0.12+7, mixed mode, sharing)

### GraalVM version (if different from Java)

e3dd4282fe23d2a37fc8b6f2507c86a39d41bb02

### Quarkus version or git rev

57d1dae99a635b32951d7e1594f0969fc61dceb1

### Build tool (ie. output of `mvnw --version` or `gradlew --version`)

Apache Maven 3.8.1 (05c21c65bdfed0f71a2f2ada8b84da59348c4c5d) Maven home: /home/zakkak/.m2/wrapper/dists/apache-maven-3.8.1-bin/2l5mhf2pq2clrde7f7qp1rdt5m/apache-maven-3.8.1 Java version: 11.0.12, vendor: Red Hat, Inc., runtime: /usr/lib/jvm/java-11-openjdk-11.0.12.0.7-0.fc34.x86_64 Default locale: en_IE, platform encoding: UTF-8 OS name: "linux", version: "5.12.15-300.fc34.x86_64", arch: "amd64", family: "unix"

### Additional information

The graal change that brought this up appears to be https://github.com/oracle/graal/pull/3050

I am not sure it's worth digging this further. I think we should adapt Quarkus' serialization support (https://github.com/quarkusio/quarkus/pull/15380/files) to use the new feature instead when using GraalVM >=21.3.

WDYT?

cc @JiriOndrusek 

Changed files:
core/deployment/src/main/java/io/quarkus/deployment/steps/NativeImageAutoFeatureStep.java

diff --git a/core/deployment/src/main/java/io/quarkus/deployment/steps/NativeImageAutoFeatureStep.java b/core/deployment/src/main/java/io/quarkus/deployment/steps/NativeImageAutoFeatureStep.java
index dacefc389d6..4709fdaac3a 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/steps/NativeImageAutoFeatureStep.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/steps/NativeImageAutoFeatureStep.java
@@ -538,13 +538,53 @@ private MethodDescriptor createRegisterSerializationForClassMethod(ClassCreator
                 ofMethod(Thread.class, "getContextClassLoader", ClassLoader.class),
                 currentThread);
 
-        ResultHandle objectClass = tc.invokeStaticMethod(
-                ofMethod(Class.class, "forName", Class.class, String.class, boolean.class, ClassLoader.class),
-                tc.load("java.lang.Object"), tc.load(false), tccl);
+        MethodDescriptor forNameMethodDescriptor = ofMethod(Class.class, "forName", Class.class, String.class, boolean.class,
+                ClassLoader.class);
+
+        MethodDescriptor lookupMethod = ofMethod("com.oracle.svm.util.ReflectionUtil", "lookupMethod", Method.class,
+                Class.class, String.class,
+                Class[].class);
+        MethodDescriptor invokeMethodDescriptor = ofMethod(Method.class, "invoke", Object.class, Object.class,
+                Object[].class);
+
+        BranchResult graalVm21_3Test = tc.ifGreaterEqualZero(
+                tc.invokeVirtualMethod(VERSION_COMPARE_TO, tc.invokeStaticMethod(VERSION_CURRENT),
+                        tc.marshalAsArray(int.class, tc.load(21), tc.load(3))));
+
+        BytecodeCreator greaterThan21_3 = graalVm21_3Test.trueBranch();
+        ResultHandle runtimeSerializationClass = greaterThan21_3.invokeStaticMethod(forNameMethodDescriptor,
+                greaterThan21_3.load("org.graalvm.nativeimage.hosted.RuntimeSerialization"),
+                greaterThan21_3.load(false), tccl);
+        ResultHandle registerArgTypes = greaterThan21_3.newArray(Class.class, greaterThan21_3.load(1));
+        greaterThan21_3.writeArrayValue(registerArgTypes, 0, greaterThan21_3.loadClass(Class[].class));
+        ResultHandle registerLookupMethod = greaterThan21_3.invokeStaticMethod(lookupMethod, runtimeSerializationClass,
+                greaterThan21_3.load("register"), registerArgTypes);
+        ResultHandle registerArgs = greaterThan21_3.newArray(Object.class, greaterThan21_3.load(1));
+        ResultHandle classesToRegister = greaterThan21_3.newArray(Class.class, greaterThan21_3.load(1));
+        greaterThan21_3.writeArrayValue(classesToRegister, 0, clazz);
+        greaterThan21_3.writeArrayValue(registerArgs, 0, classesToRegister);
+        greaterThan21_3.invokeVirtualMethod(invokeMethodDescriptor, registerLookupMethod,
+                greaterThan21_3.loadNull(), registerArgs);
+        greaterThan21_3.returnValue(null);
+
+        ResultHandle objectClass = tc.invokeStaticMethod(forNameMethodDescriptor, tc.load("java.lang.Object"),
+                tc.load(false), tccl);
+        ResultHandle serializationRegistryClass = tc.invokeStaticMethod(forNameMethodDescriptor,
+                tc.load("com.oracle.svm.core.jdk.serialize.SerializationRegistry"),
+                tc.load(false), tccl);
+        ResultHandle addReflectionsClass = tc.invokeStaticMethod(forNameMethodDescriptor,
+                tc.load("com.oracle.svm.reflect.serialize.hosted.SerializationFeature"),
+                tc.load(false), tccl);
 
         ResultHandle serializationSupport = tc.invokeStaticMethod(
                 IMAGE_SINGLETONS_LOOKUP,
-                tc.loadClass("com.oracle.svm.core.jdk.serialize.SerializationRegistry"));
+                serializationRegistryClass);
+
+        ResultHandle addReflectionsLookupArgs = tc.newArray(Class.class, tc.load(2));
+        tc.writeArrayValue(addReflectionsLookupArgs, 0, tc.loadClass(Class.class));
+        tc.writeArrayValue(addReflectionsLookupArgs, 1, tc.loadClass(Class.class));
+        ResultHandle addReflectionsLookupMethod = tc.invokeStaticMethod(lookupMethod, addReflectionsClass,
+                tc.load("addReflections"), addReflectionsLookupArgs);
 
         ResultHandle reflectionFactory = tc.invokeStaticMethod(
                 ofMethod("sun.reflect.ReflectionFactory", "getReflectionFactory", "sun.reflect.ReflectionFactory"));
@@ -552,7 +592,7 @@ private MethodDescriptor createRegisterSerializationForClassMethod(ClassCreator
         AssignableResultHandle newSerializationConstructor = tc.createVariable(Constructor.class);
 
         ResultHandle externalizableClass = tc.invokeStaticMethod(
-                ofMethod(Class.class, "forName", Class.class, String.class, boolean.class, ClassLoader.class),
+                forNameMethodDescriptor,
                 tc.load("java.io.Externalizable"), tc.load(false), tccl);
 
         BranchResult isExternalizable = tc
@@ -562,13 +602,12 @@ private MethodDescriptor createRegisterSerializationForClassMethod(ClassCreator
 
         ResultHandle array1 = ifIsExternalizable.newArray(Class.class, tc.load(1));
         ResultHandle classClass = ifIsExternalizable.invokeStaticMethod(
-                ofMethod(Class.class, "forName", Class.class, String.class, boolean.class, ClassLoader.class),
+                forNameMethodDescriptor,
                 ifIsExternalizable.load("java.lang.Class"), ifIsExternalizable.load(false), tccl);
         ifIsExternalizable.writeArrayValue(array1, 0, classClass);
 
         ResultHandle externalizableLookupMethod = ifIsExternalizable.invokeStaticMethod(
-                ofMethod("com.oracle.svm.util.ReflectionUtil", "lookupMethod", Method.class, Class.class, String.class,
-                        Class[].class),
+                lookupMethod,
                 ifIsExternalizable.loadClass(ObjectStreamClass.class), ifIsExternalizable.load("getExternalizableConstructor"),
                 array1);
 
@@ -576,18 +615,17 @@ private MethodDescriptor createRegisterSerializationForClassMethod(ClassCreator
         ifIsExternalizable.writeArrayValue(array2, 0, clazz);
 
         ResultHandle externalizableConstructor = ifIsExternalizable.invokeVirtualMethod(
-                ofMethod(Method.class, "invoke", Object.class, Object.class,
-                        Object[].class),
-                externalizableLookupMethod, ifIsExternalizable.loadNull(), array2);
+                invokeMethodDescriptor, externalizableLookupMethod, ifIsExternalizable.loadNull(), array2);
 
         ResultHandle externalizableConstructorClass = ifIsExternalizable.invokeVirtualMethod(
                 ofMethod(Constructor.class, "getDeclaringClass", Class.class),
                 externalizableConstructor);
 
-        ifIsExternalizable.invokeStaticMethod(
-                ofMethod("com.oracle.svm.reflect.serialize.hosted.SerializationFeature", "addReflections", void.class,
-                        Class.class, Class.class),
-                clazz, externalizableConstructorClass);
+        ResultHandle addReflectionsArgs1 = ifIsExternalizable.newArray(Class.class, tc.load(2));
+        ifIsExternalizable.writeArrayValue(addReflectionsArgs1, 0, clazz);
+        ifIsExternalizable.writeArrayValue(addReflectionsArgs1, 1, externalizableConstructorClass);
+        ifIsExternalizable.invokeVirtualMethod(invokeMethodDescriptor, addReflectionsLookupMethod,
+                ifIsExternalizable.loadNull(), addReflectionsArgs1);
 
         ifIsExternalizable.returnValue(null);
 
@@ -618,26 +656,22 @@ private MethodDescriptor createRegisterSerializationForClassMethod(ClassCreator
                 ofMethod(Constructor.class, "getDeclaringClass", Class.class),
                 newSerializationConstructor);
 
-        ResultHandle lookupMethod = tc.invokeStaticMethod(
-                ofMethod("com.oracle.svm.util.ReflectionUtil", "lookupMethod", Method.class, Class.class, String.class,
-                        Class[].class),
-                tc.loadClass(Constructor.class), tc.load("getConstructorAccessor"),
+        ResultHandle getConstructorAccessor = tc.invokeStaticMethod(
+                lookupMethod, tc.loadClass(Constructor.class), tc.load("getConstructorAccessor"),
                 tc.newArray(Class.class, tc.load(0)));
 
         ResultHandle accessor = tc.invokeVirtualMethod(
-                ofMethod(Method.class, "invoke", Object.class, Object.class,
-                        Object[].class),
-                lookupMethod, newSerializationConstructor,
+                invokeMethodDescriptor, getConstructorAccessor, newSerializationConstructor,
                 tc.newArray(Object.class, tc.load(0)));
 
         tc.invokeVirtualMethod(
                 ofMethod("com.oracle.svm.reflect.serialize.SerializationSupport", "addConstructorAccessor",
                         Object.class, Class.class, Class.class, Object.class),
                 serializationSupport, clazz, newSerializationConstructorClass, accessor);
-        tc.invokeStaticMethod(
-                ofMethod("com.oracle.svm.reflect.serialize.hosted.SerializationFeature", "addReflections", void.class,
-                        Class.class, Class.class),
-                clazz, objectClass);
+        ResultHandle addReflectionsArgs2 = tc.newArray(Class.class, tc.load(2));
+        tc.writeArrayValue(addReflectionsArgs2, 0, clazz);
+        tc.writeArrayValue(addReflectionsArgs2, 1, objectClass);
+        tc.invokeVirtualMethod(invokeMethodDescriptor, addReflectionsLookupMethod, tc.loadNull(), addReflectionsArgs2);
 
         addSerializationForClass.returnValue(null);