quarkusio / quarkus

Quarkus: Supersonic Subatomic Java.
https://quarkus.io
Apache License 2.0
13.35k stars 2.56k forks source link

Methods accessed reflectively starting with GraalVM for JDK 23+26 #41283

Closed zakkak closed 1 day ago

zakkak commented 2 weeks ago

Describe the bug

Starting with GraalVM for JDK 23 we see a lot of java.lang.BootstrapMethodError: java.lang.NoSuchMethodError, see https://github.com/oracle/graal/actions/runs/9558273459

I don't fully understand what's happening but the issue seems related to https://bugs.openjdk.org/browse/JDK-8229959.

I initially thought that registering the missing methods would be enough, but it looks like this is not the right way to go for all cases as some of the proxied classes may be used by the application itself and we don't know which methods will be reflective accessed in this case. E.g. in https://github.com/quarkusio/quarkus/blob/50372634952488c3249f0f3bc4982792653cfd9f/integration-tests/spring-web/src/main/java/io/quarkus/it/spring/web/CustomAdvice.java#L37

the test is invoking getRequestURI on the proxied HttpServletRequest resulting in the following error/trace:

``` 2024-06-18 15:09:11,655 ERROR [io.und.req.io] (executor-thread-1) Exception handling request 039ab309-6350-4f4d-a9b6-bf2b04583f7c-1 to /exception/re/pojo: java.lang.BootstrapMethodError: java.lang.NoSuchMethodError: jakarta.servlet.http.HttpServletRequest.getRequestURI() at jdk.proxy4/jdk.proxy4.$Proxy/s995751da.getRequestURI(Unknown Source) at io.quarkus.it.spring.web.CustomAdvice.handleResponseEntityException(CustomAdvice.java:37) at io.quarkus.spring.web.mappers.HandledResponseEntityException_Mapper_3d26ef0eeceea5013e29d92323a3aaebdec04719.toResponse(Unknown Source) at io.quarkus.spring.web.mappers.HandledResponseEntityException_Mapper_3d26ef0eeceea5013e29d92323a3aaebdec04719.toResponse(Unknown Source) at org.jboss.resteasy.core.ExceptionHandler.executeExceptionMapper(ExceptionHandler.java:139) at org.jboss.resteasy.core.ExceptionHandler.unwrapException(ExceptionHandler.java:183) at org.jboss.resteasy.core.ExceptionHandler.handleApplicationException(ExceptionHandler.java:100) at org.jboss.resteasy.core.ExceptionHandler.handleException(ExceptionHandler.java:344) at org.jboss.resteasy.core.SynchronousDispatcher.writeException(SynchronousDispatcher.java:205) at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:452) at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:240) at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:154) at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:321) at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:157) at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:229) at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:222) at io.quarkus.resteasy.runtime.ResteasyFilter$ResteasyResponseWrapper.service(ResteasyFilter.java:70) at io.quarkus.resteasy.runtime.ResteasyFilter$ResteasyResponseWrapper.sendError(ResteasyFilter.java:76) at io.undertow.servlet.handlers.DefaultServlet.doGet(DefaultServlet.java:172) at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:527) at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:614) at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74) at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:129) at io.quarkus.resteasy.runtime.ResteasyFilter.doFilter(ResteasyFilter.java:31) 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.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46) at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:65) 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$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:630) at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:227) at io.undertow.servlet.handlers.ServletInitialHandler.handleRequest(ServletInitialHandler.java:152) at io.undertow.server.handlers.CanonicalPathHandler.handleRequest(CanonicalPathHandler.java:49) at io.quarkus.undertow.runtime.UndertowDeploymentRecorder$1.handleRequest(UndertowDeploymentRecorder.java:126) at io.undertow.server.Connectors.executeRootHandler(Connectors.java:284) at io.undertow.server.DefaultExchangeHandler.handle(DefaultExchangeHandler.java:18) at io.quarkus.undertow.runtime.UndertowDeploymentRecorder$5$2.run(UndertowDeploymentRecorder.java:445) at java.base@24/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572) at java.base@24/java.util.concurrent.FutureTask.run(FutureTask.java:317) at io.quarkus.vertx.core.runtime.VertxCoreRecorder$14.runWith(VertxCoreRecorder.java:599) at org.jboss.threads.EnhancedQueueExecutor$Task.doRunWith(EnhancedQueueExecutor.java:2516) at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2495) at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1521) at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:11) at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:11) at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) at java.base@24/java.lang.Thread.runWith(Thread.java:1588) at java.base@24/java.lang.Thread.run(Thread.java:1575) at org.graalvm.nativeimage.builder/com.oracle.svm.core.thread.PlatformThreads.threadStartRoutine(PlatformThreads.java:834) at org.graalvm.nativeimage.builder/com.oracle.svm.core.thread.PlatformThreads.threadStartRoutine(PlatformThreads.java:810) Caused by: java.lang.NoSuchMethodError: jakarta.servlet.http.HttpServletRequest.getRequestURI() at jdk.proxy4/jdk.proxy4.$Proxy/s995751da.$getMethod(Unknown Source) ... 68 more ```

Since we don't know what methods might be invoked on the proxied classes I think we need to register all methods of proxied classes for reflective access. I am not sure how to detect which classes are being proxied though...

Expected behavior

Tests should build and pass as they do with GraalVM for JDK 21 and 22

Actual behavior

Tests fail with errors like the following:

``` 2024-06-18 03:52:55,782 ERROR [io.und.req.io] (executor-thread-1) Exception handling request aa886ec8-cb17-44e6-9d69-b4300fab13ee-1 to /fruits: java.lang.BootstrapMethodError: java.lang.NoSuchMethodError: jakarta.ws.rs.ext.Providers.getContextResolver(java.lang.Class, jakarta.ws.rs.core.MediaType) at jdk.proxy4/jdk.proxy4.$Proxy/sfa608265.getContextResolver(Unknown Source) at com.fasterxml.jackson.jakarta.rs.json.JacksonJsonProvider._locateMapperViaProvider(JacksonJsonProvider.java:197) at com.fasterxml.jackson.jakarta.rs.base.ProviderBase.locateMapper(ProviderBase.java:889) at org.jboss.resteasy.plugins.providers.jackson.ResteasyJackson2Provider.writeTo(ResteasyJackson2Provider.java:226) at org.jboss.resteasy.core.messagebody.AsyncBufferedMessageBodyWriter.asyncWriteTo(AsyncBufferedMessageBodyWriter.java:24) at org.jboss.resteasy.core.interception.jaxrs.ServerWriterInterceptorContext.writeTo(ServerWriterInterceptorContext.java:81) at org.jboss.resteasy.core.interception.jaxrs.AbstractWriterInterceptorContext.asyncProceed(AbstractWriterInterceptorContext.java:190) at org.jboss.resteasy.core.interception.jaxrs.AbstractWriterInterceptorContext.getStarted(AbstractWriterInterceptorContext.java:158) at org.jboss.resteasy.core.interception.jaxrs.ServerWriterInterceptorContext.lambda$getStarted$0(ServerWriterInterceptorContext.java:68) at org.jboss.resteasy.core.interception.jaxrs.ServerWriterInterceptorContext.aroundWriteTo(ServerWriterInterceptorContext.java:87) at org.jboss.resteasy.core.interception.jaxrs.ServerWriterInterceptorContext.getStarted(ServerWriterInterceptorContext.java:68) at org.jboss.resteasy.core.ServerResponseWriter.lambda$writeNomapResponse$3(ServerResponseWriter.java:166) at org.jboss.resteasy.core.interception.jaxrs.ContainerResponseContextImpl.filter(ContainerResponseContextImpl.java:365) at org.jboss.resteasy.core.ServerResponseWriter.executeFilters(ServerResponseWriter.java:243) at org.jboss.resteasy.core.ServerResponseWriter.writeNomapResponse(ServerResponseWriter.java:100) at org.jboss.resteasy.core.ServerResponseWriter.writeNomapResponse(ServerResponseWriter.java:73) at org.jboss.resteasy.core.SynchronousDispatcher.writeResponse(SynchronousDispatcher.java:518) at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:458) at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:240) at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:154) at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:321) at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:157) at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:229) at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:222) at io.quarkus.resteasy.runtime.ResteasyFilter$ResteasyResponseWrapper.service(ResteasyFilter.java:70) at io.quarkus.resteasy.runtime.ResteasyFilter$ResteasyResponseWrapper.sendError(ResteasyFilter.java:76) at io.undertow.servlet.handlers.DefaultServlet.doGet(DefaultServlet.java:172) at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:527) at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:614) at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74) at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:129) at io.quarkus.resteasy.runtime.ResteasyFilter.doFilter(ResteasyFilter.java:31) 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.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46) at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:65) 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$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:630) at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:227) at io.undertow.servlet.handlers.ServletInitialHandler.handleRequest(ServletInitialHandler.java:152) at io.undertow.server.handlers.CanonicalPathHandler.handleRequest(CanonicalPathHandler.java:49) at io.quarkus.undertow.runtime.UndertowDeploymentRecorder$1.handleRequest(UndertowDeploymentRecorder.java:126) at io.undertow.server.Connectors.executeRootHandler(Connectors.java:284) at io.undertow.server.DefaultExchangeHandler.handle(DefaultExchangeHandler.java:18) at io.quarkus.undertow.runtime.UndertowDeploymentRecorder$5$2.run(UndertowDeploymentRecorder.java:445) at java.base@24/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572) at java.base@24/java.util.concurrent.FutureTask.run(FutureTask.java:317) at io.quarkus.vertx.core.runtime.VertxCoreRecorder$14.runWith(VertxCoreRecorder.java:599) at org.jboss.threads.EnhancedQueueExecutor$Task.doRunWith(EnhancedQueueExecutor.java:2516) at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2495) at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1521) at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:11) at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:11) at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) at java.base@24/java.lang.Thread.runWith(Thread.java:1588) at java.base@24/java.lang.Thread.run(Thread.java:1575) at org.graalvm.nativeimage.builder/com.oracle.svm.core.thread.PlatformThreads.threadStartRoutine(PlatformThreads.java:834) at org.graalvm.nativeimage.builder/com.oracle.svm.core.thread.PlatformThreads.threadStartRoutine(PlatformThreads.java:810) Caused by: java.lang.NoSuchMethodError: jakarta.ws.rs.ext.Providers.getContextResolver(java.lang.Class, jakarta.ws.rs.core.MediaType) at jdk.proxy4/jdk.proxy4.$Proxy/sfa608265.$getMethod(Unknown Source) ... 76 more ```

How to Reproduce?

  1. Grab the latest GraalVM CE dev build from release https://github.com/graalvm/graalvm-ce-dev-builds/releases
  2. Extract it and set GRAALVM_HOME to point to the extracted directory
  3. ./mvnw -Dnative -pl integration-tests/spring-web -Dnative.surefire.skip -Dformat.skip -Dno-descriptor-tests clean verify -Dquarkus.native.container-build=false -Dtest-containers -Dstart-containers

Output of uname -a or ver

No response

Output of java -version

23 and 24

Mandrel or GraalVM version (if different from Java)

GraalVM for JDK 23 (and 24)

Quarkus version or git rev

50372634952488c3249f0f3bc4982792653cfd9f

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

No response

Additional information

No response

quarkus-bot[bot] commented 2 weeks ago

/cc @Karm (mandrel), @galderz (mandrel)

dmlloyd commented 2 weeks ago

Last time I saw this issue (which was recently, but yet I don't remember where it was), it was because of a class which had javax vs jakarta (i.e. a version mismatch problem). I don't know whether that might be the case here though.

zakkak commented 2 weeks ago

I don't know whether that might be the case here though.

I think it's not related to this. Note that we see the issue with other packages as well, e.g. java.sql

zakkak commented 6 days ago

This should now be fixed by https://github.com/oracle/graal/pull/9184, I will wait for the CI to confirm.

jerboaa commented 2 days ago

Example errors of this look like:

 2024-06-18 03:52:55,782 ERROR [io.und.req.io] (executor-thread-1) Exception handling request aa886ec8-cb17-44e6-9d69-b4300fab13ee-1 to /fruits: java.lang.BootstrapMethodError: java.lang.NoSuchMethodError: jakarta.ws.rs.ext.Providers.getContextResolver(java.lang.Class, jakarta.ws.rs.core.MediaType)
    at jdk.proxy4/jdk.proxy4.$Proxy/sfa608265.getContextResolver(Unknown Source)
    at com.fasterxml.jackson.jakarta.rs.json.JacksonJsonProvider._locateMapperViaProvider(JacksonJsonProvider.java:197)