quarkusio / quarkus

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

Native-Image: ApplicationImpl Initialize on runtime when using JAX-RS-Filter #23716

Open knuspertante opened 2 years ago

knuspertante commented 2 years ago

Describe the bug

The build runs fine if we only call / inject the TaskService in TaskResource. But if we use the TaskService in a JAX-RS Filter with NameBinding we need to initialize some Classes at run time. Therefore I tried to initialize our classes:

at run time but still the same error. Only if I initialize io.quarkus.runner.ApplicationImpl at run time the native-build runs. But then Quarkus or the JAX-RS application doesn't run.

When building a native-image with

--trace-class-initialization=software.amazon.awssdk.core.retry.backoff.FullJitterBackoffStrategy\\,software.amazon.awssdk.services.dynamodb.DynamoDbRetryPolicy

the following stack-trace is printed:

Error: Classes that should be initialized at run time got initialized during image building:
 software.amazon.awssdk.core.retry.backoff.FullJitterBackoffStrategy the class was requested to be initialized at run time (from feature io.quarkus.runner.AutoFeature.beforeAnalysis with 'FullJitterBackoffStrategy.class'). io.quarkus.runner.ApplicationImpl caused initialization of this class with the following trace:
    at software.amazon.awssdk.core.retry.backoff.FullJitterBackoffStrategy.<clinit>(FullJitterBackoffStrategy.java:44)
    at software.amazon.awssdk.services.dynamodb.DynamoDbRetryPolicy.<clinit>(DynamoDbRetryPolicy.java:52)
    at software.amazon.awssdk.services.dynamodb.DefaultDynamoDbBaseClientBuilder.finalizeServiceConfiguration(DefaultDynamoDbBaseClientBuilder.java:67)
    at software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder.finalizeChildConfiguration(AwsDefaultClientBuilder.java:175)
    at software.amazon.awssdk.core.client.builder.SdkDefaultClientBuilder.syncClientConfiguration(SdkDefaultClientBuilder.java:161)
    at software.amazon.awssdk.services.dynamodb.DefaultDynamoDbClientBuilder.buildClient(DefaultDynamoDbClientBuilder.java:44)
    at software.amazon.awssdk.services.dynamodb.DefaultDynamoDbClientBuilder.buildClient(DefaultDynamoDbClientBuilder.java:22)
    at software.amazon.awssdk.core.client.builder.SdkDefaultClientBuilder.build(SdkDefaultClientBuilder.java:133)
    at de.j21p.repository.aws.DynamoDBClientHandler.getInstance(DynamoDBClientHandler.java:23)
    at de.j21p.repository.aws.TaskRepositoryAws.<init>(TaskRepositoryAws.java:34)
    at de.j21p.services.TaskService.<init>(TaskService.java:21)
    at de.j21p.services.TaskService_ClientProxy.<init>(Unknown Source)
    at de.j21p.services.TaskService_Bean.proxy(Unknown Source)
    at de.j21p.services.TaskService_Bean.get(Unknown Source)
    at de.j21p.services.TaskService_Bean.get(Unknown Source)
    at de.j21p.filter.TaskEnvironmentRequestFilter_Bean.create(Unknown Source)
    at de.j21p.filter.TaskEnvironmentRequestFilter_Bean.create(Unknown Source)
    at io.quarkus.arc.impl.AbstractSharedContext.createInstanceHandle(AbstractSharedContext.java:101)
    at io.quarkus.arc.impl.AbstractSharedContext$1.get(AbstractSharedContext.java:29)
    at io.quarkus.arc.impl.AbstractSharedContext$1.get(AbstractSharedContext.java:26)
    at io.quarkus.arc.impl.LazyValue.get(LazyValue.java:26)
    at io.quarkus.arc.impl.ComputingCache.computeIfAbsent(ComputingCache.java:69)
    at io.quarkus.arc.impl.AbstractSharedContext.get(AbstractSharedContext.java:26)
    at de.j21p.filter.TaskEnvironmentRequestFilter_Bean.get(Unknown Source)
    at de.j21p.filter.TaskEnvironmentRequestFilter_Bean.get(Unknown Source)
    at io.quarkus.arc.impl.ArcContainerImpl.beanInstanceHandle(ArcContainerImpl.java:428)
    at io.quarkus.arc.impl.ArcContainerImpl.beanInstanceHandle(ArcContainerImpl.java:441)
    at io.quarkus.arc.impl.ArcContainerImpl$1.get(ArcContainerImpl.java:269)
    at io.quarkus.arc.impl.ArcContainerImpl$1.get(ArcContainerImpl.java:266)
    at io.quarkus.resteasy.common.runtime.QuarkusConstructorInjector.construct(QuarkusConstructorInjector.java:39)
    at org.jboss.resteasy.core.providerfactory.ResteasyProviderFactoryImpl.injectedInstance(ResteasyProviderFactoryImpl.java:1399)
    at org.jboss.resteasy.core.interception.jaxrs.JaxrsInterceptorRegistryImpl$AbstractInterceptorFactory.createInterceptor(JaxrsInterceptorRegistryImpl.java:150)
    at org.jboss.resteasy.core.interception.jaxrs.JaxrsInterceptorRegistryImpl$OnDemandInterceptorFactory.initialize(JaxrsInterceptorRegistryImpl.java:168)
    at org.jboss.resteasy.core.interception.jaxrs.JaxrsInterceptorRegistryImpl$OnDemandInterceptorFactory.checkInitialize(JaxrsInterceptorRegistryImpl.java:183)
    at org.jboss.resteasy.core.interception.jaxrs.JaxrsInterceptorRegistryImpl$OnDemandInterceptorFactory.getInterceptor(JaxrsInterceptorRegistryImpl.java:193)
    at org.jboss.resteasy.core.interception.jaxrs.JaxrsInterceptorRegistryImpl$AbstractInterceptorFactory.postMatch(JaxrsInterceptorRegistryImpl.java:124)
    at org.jboss.resteasy.core.interception.jaxrs.JaxrsInterceptorRegistryImpl.postMatch(JaxrsInterceptorRegistryImpl.java:288)
    at org.jboss.resteasy.core.interception.jaxrs.ContainerRequestFilterRegistryImpl.postMatch(ContainerRequestFilterRegistryImpl.java:30)
    at org.jboss.resteasy.core.interception.jaxrs.ContainerRequestFilterRegistryImpl.postMatch(ContainerRequestFilterRegistryImpl.java:12)
    at org.jboss.resteasy.core.ResourceMethodInvoker.<init>(ResourceMethodInvoker.java:142)
    at org.jboss.resteasy.core.ResourceMethodRegistry.processMethod(ResourceMethodRegistry.java:381)
    at org.jboss.resteasy.core.ResourceMethodRegistry.register(ResourceMethodRegistry.java:308)
    at org.jboss.resteasy.core.ResourceMethodRegistry.addResourceFactory(ResourceMethodRegistry.java:259)
    at org.jboss.resteasy.core.ResourceMethodRegistry.addResourceFactory(ResourceMethodRegistry.java:227)
    at org.jboss.resteasy.core.ResourceMethodRegistry.addResourceFactory(ResourceMethodRegistry.java:208)
    at org.jboss.resteasy.core.ResourceMethodRegistry.addResourceFactory(ResourceMethodRegistry.java:192)
    at org.jboss.resteasy.core.ResourceMethodRegistry.addResourceFactory(ResourceMethodRegistry.java:175)
    at org.jboss.resteasy.core.ResourceMethodRegistry.addPerRequestResource(ResourceMethodRegistry.java:87)
    at org.jboss.resteasy.core.ResteasyDeploymentImpl.registerResources(ResteasyDeploymentImpl.java:518)
    at org.jboss.resteasy.core.ResteasyDeploymentImpl.registration(ResteasyDeploymentImpl.java:475)
    at org.jboss.resteasy.core.ResteasyDeploymentImpl.startInternal(ResteasyDeploymentImpl.java:164)
    at org.jboss.resteasy.core.ResteasyDeploymentImpl.start(ResteasyDeploymentImpl.java:121)
    at io.quarkus.resteasy.runtime.standalone.ResteasyStandaloneRecorder.staticInit(ResteasyStandaloneRecorder.java:43)
    at io.quarkus.deployment.steps.ResteasyStandaloneBuildStep$staticInit345281060.deploy_0(Unknown Source)
    at io.quarkus.deployment.steps.ResteasyStandaloneBuildStep$staticInit345281060.deploy(Unknown Source)
    at io.quarkus.runner.ApplicationImpl.<clinit>(Unknown Source)

com.oracle.svm.core.util.UserError$UserException: Classes that should be initialized at run time got initialized during image building:
 software.amazon.awssdk.core.retry.backoff.FullJitterBackoffStrategy the class was requested to be initialized at run time (from feature io.quarkus.runner.AutoFeature.beforeAnalysis with 'FullJitterBackoffStrategy.class'). io.quarkus.runner.ApplicationImpl caused initialization of this class with the following trace:
    at software.amazon.awssdk.core.retry.backoff.FullJitterBackoffStrategy.<clinit>(FullJitterBackoffStrategy.java:44)
    at software.amazon.awssdk.services.dynamodb.DynamoDbRetryPolicy.<clinit>(DynamoDbRetryPolicy.java:52)
    at software.amazon.awssdk.services.dynamodb.DefaultDynamoDbBaseClientBuilder.finalizeServiceConfiguration(DefaultDynamoDbBaseClientBuilder.java:67)
    at software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder.finalizeChildConfiguration(AwsDefaultClientBuilder.java:175)
    at software.amazon.awssdk.core.client.builder.SdkDefaultClientBuilder.syncClientConfiguration(SdkDefaultClientBuilder.java:161)
    at software.amazon.awssdk.services.dynamodb.DefaultDynamoDbClientBuilder.buildClient(DefaultDynamoDbClientBuilder.java:44)
    at software.amazon.awssdk.services.dynamodb.DefaultDynamoDbClientBuilder.buildClient(DefaultDynamoDbClientBuilder.java:22)
    at software.amazon.awssdk.core.client.builder.SdkDefaultClientBuilder.build(SdkDefaultClientBuilder.java:133)
    at de.j21p.repository.aws.DynamoDBClientHandler.getInstance(DynamoDBClientHandler.java:23)
    at de.j21p.repository.aws.TaskRepositoryAws.<init>(TaskRepositoryAws.java:34)
    at de.j21p.services.TaskService.<init>(TaskService.java:21)
    at de.j21p.services.TaskService_ClientProxy.<init>(Unknown Source)
    at de.j21p.services.TaskService_Bean.proxy(Unknown Source)
    at de.j21p.services.TaskService_Bean.get(Unknown Source)
    at de.j21p.services.TaskService_Bean.get(Unknown Source)
    at de.j21p.filter.TaskEnvironmentRequestFilter_Bean.create(Unknown Source)
    at de.j21p.filter.TaskEnvironmentRequestFilter_Bean.create(Unknown Source)
    at io.quarkus.arc.impl.AbstractSharedContext.createInstanceHandle(AbstractSharedContext.java:101)
    at io.quarkus.arc.impl.AbstractSharedContext$1.get(AbstractSharedContext.java:29)
    at io.quarkus.arc.impl.AbstractSharedContext$1.get(AbstractSharedContext.java:26)
    at io.quarkus.arc.impl.LazyValue.get(LazyValue.java:26)
    at io.quarkus.arc.impl.ComputingCache.computeIfAbsent(ComputingCache.java:69)
    at io.quarkus.arc.impl.AbstractSharedContext.get(AbstractSharedContext.java:26)
    at de.j21p.filter.TaskEnvironmentRequestFilter_Bean.get(Unknown Source)
    at de.j21p.filter.TaskEnvironmentRequestFilter_Bean.get(Unknown Source)
    at io.quarkus.arc.impl.ArcContainerImpl.beanInstanceHandle(ArcContainerImpl.java:428)
    at io.quarkus.arc.impl.ArcContainerImpl.beanInstanceHandle(ArcContainerImpl.java:441)
    at io.quarkus.arc.impl.ArcContainerImpl$1.get(ArcContainerImpl.java:269)
    at io.quarkus.arc.impl.ArcContainerImpl$1.get(ArcContainerImpl.java:266)
    at io.quarkus.resteasy.common.runtime.QuarkusConstructorInjector.construct(QuarkusConstructorInjector.java:39)
    at org.jboss.resteasy.core.providerfactory.ResteasyProviderFactoryImpl.injectedInstance(ResteasyProviderFactoryImpl.java:1399)
    at org.jboss.resteasy.core.interception.jaxrs.JaxrsInterceptorRegistryImpl$AbstractInterceptorFactory.createInterceptor(JaxrsInterceptorRegistryImpl.java:150)
    at org.jboss.resteasy.core.interception.jaxrs.JaxrsInterceptorRegistryImpl$OnDemandInterceptorFactory.initialize(JaxrsInterceptorRegistryImpl.java:168)
    at org.jboss.resteasy.core.interception.jaxrs.JaxrsInterceptorRegistryImpl$OnDemandInterceptorFactory.checkInitialize(JaxrsInterceptorRegistryImpl.java:183)
    at org.jboss.resteasy.core.interception.jaxrs.JaxrsInterceptorRegistryImpl$OnDemandInterceptorFactory.getInterceptor(JaxrsInterceptorRegistryImpl.java:193)
    at org.jboss.resteasy.core.interception.jaxrs.JaxrsInterceptorRegistryImpl$AbstractInterceptorFactory.postMatch(JaxrsInterceptorRegistryImpl.java:124)
    at org.jboss.resteasy.core.interception.jaxrs.JaxrsInterceptorRegistryImpl.postMatch(JaxrsInterceptorRegistryImpl.java:288)
    at org.jboss.resteasy.core.interception.jaxrs.ContainerRequestFilterRegistryImpl.postMatch(ContainerRequestFilterRegistryImpl.java:30)
    at org.jboss.resteasy.core.interception.jaxrs.ContainerRequestFilterRegistryImpl.postMatch(ContainerRequestFilterRegistryImpl.java:12)
    at org.jboss.resteasy.core.ResourceMethodInvoker.<init>(ResourceMethodInvoker.java:142)
    at org.jboss.resteasy.core.ResourceMethodRegistry.processMethod(ResourceMethodRegistry.java:381)
    at org.jboss.resteasy.core.ResourceMethodRegistry.register(ResourceMethodRegistry.java:308)
    at org.jboss.resteasy.core.ResourceMethodRegistry.addResourceFactory(ResourceMethodRegistry.java:259)
    at org.jboss.resteasy.core.ResourceMethodRegistry.addResourceFactory(ResourceMethodRegistry.java:227)
    at org.jboss.resteasy.core.ResourceMethodRegistry.addResourceFactory(ResourceMethodRegistry.java:208)
    at org.jboss.resteasy.core.ResourceMethodRegistry.addResourceFactory(ResourceMethodRegistry.java:192)
    at org.jboss.resteasy.core.ResourceMethodRegistry.addResourceFactory(ResourceMethodRegistry.java:175)
    at org.jboss.resteasy.core.ResourceMethodRegistry.addPerRequestResource(ResourceMethodRegistry.java:87)
    at org.jboss.resteasy.core.ResteasyDeploymentImpl.registerResources(ResteasyDeploymentImpl.java:518)
    at org.jboss.resteasy.core.ResteasyDeploymentImpl.registration(ResteasyDeploymentImpl.java:475)
    at org.jboss.resteasy.core.ResteasyDeploymentImpl.startInternal(ResteasyDeploymentImpl.java:164)
    at org.jboss.resteasy.core.ResteasyDeploymentImpl.start(ResteasyDeploymentImpl.java:121)
    at io.quarkus.resteasy.runtime.standalone.ResteasyStandaloneRecorder.staticInit(ResteasyStandaloneRecorder.java:43)
    at io.quarkus.deployment.steps.ResteasyStandaloneBuildStep$staticInit345281060.deploy_0(Unknown Source)
    at io.quarkus.deployment.steps.ResteasyStandaloneBuildStep$staticInit345281060.deploy(Unknown Source)
    at io.quarkus.runner.ApplicationImpl.<clinit>(Unknown Source)

    at com.oracle.svm.core.util.UserError.abort(UserError.java:73)
    at com.oracle.svm.hosted.classinitialization.ConfigurableClassInitialization.checkDelayedInitialization(ConfigurableClassInitialization.java:555)
    at com.oracle.svm.hosted.classinitialization.ClassInitializationFeature.duringAnalysis(ClassInitializationFeature.java:167)
    at com.oracle.svm.hosted.NativeImageGenerator.lambda$runPointsToAnalysis$10(NativeImageGenerator.java:704)
    at com.oracle.svm.hosted.FeatureHandler.forEachFeature(FeatureHandler.java:74)
    at com.oracle.svm.hosted.NativeImageGenerator.lambda$runPointsToAnalysis$11(NativeImageGenerator.java:704)
    at com.oracle.graal.pointsto.PointsToAnalysis.runAnalysis(PointsToAnalysis.java:755)
    at com.oracle.svm.hosted.NativeImageGenerator.runPointsToAnalysis(NativeImageGenerator.java:702)
    at com.oracle.svm.hosted.NativeImageGenerator.doRun(NativeImageGenerator.java:537)
    at com.oracle.svm.hosted.NativeImageGenerator.run(NativeImageGenerator.java:494)
    at com.oracle.svm.hosted.NativeImageGeneratorRunner.buildImage(NativeImageGeneratorRunner.java:426)
    at com.oracle.svm.hosted.NativeImageGeneratorRunner.build(NativeImageGeneratorRunner.java:587)
    at com.oracle.svm.hosted.NativeImageGeneratorRunner.main(NativeImageGeneratorRunner.java:126)
    at com.oracle.svm.hosted.NativeImageGeneratorRunner$JDK9Plus.main(NativeImageGeneratorRunner.java:617)
                        1,5s (2,5% of total time) in 23 GCs | Peak RSS: 3,22GB | CPU load: 2,32
------------------------------------------------------------------------------------------------------------------------
Produced artifacts:
 /project/janus-funqy-rest-quarkus-1.0.0-SNAPSHOT-runner.build_artifacts.txt
========================================================================================================================
Failed generating 'janus-funqy-rest-quarkus-1.0.0-SNAPSHOT-runner' after 57,6s.
Error: Image build request failed with exit status 1

Expected behavior

The native-build will run because TaskService is working in TaskResource but not in JAX-RS filter.

Actual behavior

No response

How to Reproduce?

Reproducer:

  1. Create ResourceService which calls DynamoDB
  2. Create JAX-RS Resource
  3. Create JAX-RS NameBinding Interface
  4. Create JAX-RS Filter

Unfortunately I can't share my code.

Output of uname -a or ver

Darwin MacBook-Pro-21.local 21.2.0 Darwin Kernel Version 21.2.0: Sun Nov 28 20:28:41 PST 2021; root:xnu-8019.61.5~1/RELEASE_ARM64_T6000 arm64

Output of java -version

openjdk version "17.0.1" 2021-10-19 OpenJDK Runtime Environment Temurin-17.0.1+12 (build 17.0.1+12) OpenJDK 64-Bit Server VM Temurin-17.0.1+12 (build 17.0.1+12, mixed mode)

GraalVM version (if different from Java)

Container-Build

Quarkus version or git rev

2.7.0.Final

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

3.8.1

Additional information

No response

quarkus-bot[bot] commented 2 years ago

/cc @matejvasek, @patriot1burke

geoand commented 2 years ago

Any chance you can put together a sample application that exhibits this behavior?

knuspertante commented 2 years ago

Hey @geoand,

sorry for the delay. Today I found enough time to implement a sample application.

See: Quarkus Sample Application: Github Issue 23716

Pls use the following maven command to build this application.

mvn clean package -Pnative,lambda

If you comment this line out, the native-build will work

geoand commented 2 years ago

Thanks.

Note that the issue should likely be moved to https://github.com/quarkiverse/quarkus-amazon-services.

@jerboaa I see you had done some GraalVM related work on the DynamoDB extension, so do you mind taking a look?

Thanks

jerboaa commented 2 years ago

@geoand I'm not really familiar with the amazon web services stack. Last I've looked at this was due to some random class usages which needed to be runtime inited for quarkus native. That's why. Anyway, I'll see what I can do. If anybody beats me to it, be my guest ;-)

jerboaa commented 2 years ago

@knuspertante Based on this comment: https://github.com/quarkusio/quarkus/issues/14904#issuecomment-1057799863 What happens if you add the dymodb dep to your repro app? Like so: https://github.com/quarkusio/quarkus-quickstarts/blob/main/amazon-dynamodb-quickstart/pom.xml#L55..L58

I haven't tried this myself but it may get you somewhere :)

knuspertante commented 2 years ago

@jerboaa thanks for having a look at this issue!

I already use this dependency. See: pom.xml

I also exclude the the dynamodb-sdk. See: pom.xml

In my opinion this must be related to the initialization time of the JAX-RS-Filter.

Btw. I think, the tag area/funqy could be removed.

jerboaa commented 2 years ago

@geoand So I had a look at this. It seems the core of the problem is a limitation of using dynamodb in jax-rs filters. The conflict seem to come from that a) quarkus initializes everything at build time (in this case the entire resteasy jaxrs stack and related quarkus glue) b) this application uses a JAX-RS-filter which in turn uses amazon dynamodb which needs to initialize some of its classes at image runtime. Hence, there is a fundamental conflict between build time init of quarkus vs. this application's filter, which hooks into the guts of quarkus. The way to make this particular application work would be to runtime-init quarkus wholesale in native mode. Perhaps I'm missing something, though.

I think the best avenue to help @knuspertante would be to get some quarkus JAX-RS filter expert involved who can give some guidance as to how to solve this particular problem some other way.

I don't think I can help with this problem unless quarkus can be made runtime-initialized-compatible in native mode which currently, AFAIK, it isn't.

geoand commented 2 years ago

Thanks for looking into it @jerboaa