Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jackson afterburner module is not compatible with Java11 and GraalVM native image #428

Open
mokmnovatti opened this issue Oct 12, 2021 · 17 comments

Comments

@mokmnovatti
Copy link

mokmnovatti commented Oct 12, 2021

Not sure i'm missing something or not but Jackson AfterBurner module is not compatible with java11 and throwing following error when it is compiled with graalvm-21.01 native image

Error loading class my.service.StreamLambdaHandler: Target_java_lang_ClassLoader.getClassLoadingLock(String): com.oracle.svm.core.jdk.UnsupportedFeatureError
--
com.oracle.svm.core.jdk.UnsupportedFeatureError: Target_java_lang_ClassLoader.getClassLoadingLock(String)
at com.oracle.svm.core.util.VMError.unsupportedFeature(VMError.java:88)
at java.lang.ClassLoader.getClassLoadingLock(ClassLoader.java:259)
at com.fasterxml.jackson.module.afterburner.util.MyClassLoader.loadAndResolve(MyClassLoader.java:79)
at com.fasterxml.jackson.module.afterburner.deser.PropertyMutatorCollector.generateMutatorClass(PropertyMutatorCollector.java:176)
at com.fasterxml.jackson.module.afterburner.deser.PropertyMutatorCollector.buildMutator(PropertyMutatorCollector.java:102)
at com.fasterxml.jackson.module.afterburner.deser.DeserializerModifier.updateBuilder(DeserializerModifier.java:65)
at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.buildBeanDeserializer(BeanDeserializerFactory.java:287)
at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.createBeanDeserializer(BeanDeserializerFactory.java:150)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer2(DeserializerCache.java:414)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer(DeserializerCache.java:349)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:264)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:244)
at com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:142)
at com.fasterxml.jackson.databind.DeserializationContext.findRootValueDeserializer(DeserializationContext.java:591)
at com.fasterxml.jackson.databind.ObjectReader._prefetchRootDeserializer(ObjectReader.java:2340)
at com.fasterxml.jackson.databind.ObjectReader.<init>(ObjectReader.java:192)
at com.fasterxml.jackson.databind.ObjectMapper._newReader(ObjectMapper.java:736)
at com.fasterxml.jackson.databind.ObjectMapper.readerFor(ObjectMapper.java:4051)
at com.amazonaws.serverless.proxy.internal.LambdaContainerHandler.<init>(LambdaContainerHandler.java:107)
at com.amazonaws.serverless.proxy.internal.LambdaContainerHandler.<init>(LambdaContainerHandler.java:118)
at com.amazonaws.serverless.proxy.internal.servlet.AwsLambdaServletContainerHandler.<init>(AwsLambdaServletContainerHandler.java:75)
at com.amazonaws.serverless.proxy.spring.SpringBootLambdaContainerHandler.<init>(SpringBootLambdaContainerHandler.java:135)
at com.amazonaws.serverless.proxy.spring.SpringBootProxyHandlerBuilder.build(SpringBootProxyHandlerBuilder.java:61)
at com.amazonaws.serverless.proxy.spring.SpringBootProxyHandlerBuilder.buildAndInitialize(SpringBootProxyHandlerBuilder.java:80)
at com.amazonaws.serverless.proxy.spring.SpringBootLambdaContainerHandler.getAwsProxyHandler(SpringBootLambdaContainerHandler.java:93)
at my.service.StreamLambdaHandler.<clinit>(StreamLambdaHandler.java:27)
at com.oracle.svm.core.classinitialization.ClassInitializationInfo.invokeClassInitializer(ClassInitializationInfo.java:375)
at com.oracle.svm.core.classinitialization.ClassInitializationInfo.initialize(ClassInitializationInfo.java:295)
at java.lang.Class.ensureInitialized(DynamicHub.java:548)
at com.oracle.svm.core.hub.ClassForNameSupport.forNameOrNull(ClassForNameSupport.java:63)
at com.oracle.svm.core.hub.ClassForNameSupport.forName(ClassForNameSupport.java:69)
at java.lang.Class.forName(DynamicHub.java:1319)

https://github.com/awslabs/aws-serverless-java-container/blob/a72bad46a263d07d71fc2765be94899bfddbba11/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/LambdaContainerHandler.java#L88

but when the afterburner module is removed it is working fine !

might be good idea to migrate to https://github.com/stevenschlansker/jackson-blackbird which is promising with Java11

Find the code at https://github.com/mokmnovatti/my-service

@deki
Copy link
Collaborator

deki commented Oct 12, 2021

Yeah, that is a known issue, see #369.

https://github.com/FasterXML/jackson-modules-base/tree/master/blackbird looks like the way to go. Would you be willing to create a PR for that?

@mokmnovatti
Copy link
Author

Sure thing !

@mokmnovatti
Copy link
Author

After some testings realizes that blackbird also not supporting native image generation with graal and it is throwing the exception below

Error loading class my.service.StreamLambdaHandler: Defining anonymous classes at runtime is not supported.: com.oracle.svm.core.jdk.UnsupportedFeatureError
com.oracle.svm.core.jdk.UnsupportedFeatureError: Defining anonymous classes at runtime is not supported.
at com.oracle.svm.core.util.VMError.unsupportedFeature(VMError.java:88)
at jdk.internal.misc.Unsafe.defineAnonymousClass(Unsafe.java:211)
at java.lang.invoke.InnerClassLambdaMetafactory.spinInnerClass(InnerClassLambdaMetafactory.java:302)
at java.lang.invoke.InnerClassLambdaMetafactory.buildCallSite(InnerClassLambdaMetafactory.java:193)
at java.lang.invoke.LambdaMetafactory.metafactory(LambdaMetafactory.java:329)
at com.fasterxml.jackson.module.blackbird.deser.BBDeserializerModifier.createSetter(BBDeserializerModifier.java:204)
at com.fasterxml.jackson.module.blackbird.deser.BBDeserializerModifier.nextProperty(BBDeserializerModifier.java:193)
at com.fasterxml.jackson.module.blackbird.deser.BBDeserializerModifier.findOptimizableProperties(BBDeserializerModifier.java:126)
at com.fasterxml.jackson.module.blackbird.deser.BBDeserializerModifier.updateBuilder(BBDeserializerModifier.java:79)
at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.buildBeanDeserializer(BeanDeserializerFactory.java:287)
at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.createBeanDeserializer(BeanDeserializerFactory.java:150)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer2(DeserializerCache.java:414)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer(DeserializerCache.java:349)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:264)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:244)
at com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:142)
at com.fasterxml.jackson.databind.DeserializationContext.findRootValueDeserializer(DeserializationContext.java:591)
at com.fasterxml.jackson.databind.ObjectReader._prefetchRootDeserializer(ObjectReader.java:2340)
at com.fasterxml.jackson.databind.ObjectReader.<init>(ObjectReader.java:192)
at com.fasterxml.jackson.databind.ObjectMapper._newReader(ObjectMapper.java:736)
at com.fasterxml.jackson.databind.ObjectMapper.readerFor(ObjectMapper.java:4051)
at com.amazonaws.serverless.proxy.internal.LambdaContainerHandler.<init>(LambdaContainerHandler.java:111)
at com.amazonaws.serverless.proxy.internal.LambdaContainerHandler.<init>(LambdaContainerHandler.java:122)
at com.amazonaws.serverless.proxy.internal.servlet.AwsLambdaServletContainerHandler.<init>(AwsLambdaServletContainerHandler.java:75)

image

To support native-image generation, need to get rid of this after burner module as in the,

https://github.com/awslabs/aws-serverless-java-container/blob/3e55220f53182017a39cfe4905cb82cd149d45e1/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/LambdaContainerHandler.java#L83

going forward jdk > 16 is not supporting the Unsafe.defineAnonymousClass https://bugs.openjdk.java.net/browse/JDK-8243287
so better to wait for graal 21.3

@mokmnovatti
Copy link
Author

Workaround ->

import com.oracle.svm.core.annotate.Substitute;
import com.oracle.svm.core.annotate.TargetClass;

@TargetClass(className = "com.amazonaws.serverless.proxy.internal.LambdaContainerHandler.class")
final class LambdaContainerHandlerSubstitute {

    @Substitute
    private static void registerAfterBurner() {
        System.out.println("Registering after burner is not supported by the Graal VM yet ! ");
    }
}

@siddharthjain210
Copy link

Is there any fix available for jackson for JAVA-11, serverless-container 1.6? I am getting the same issue.

@deki
Copy link
Collaborator

deki commented Jan 6, 2022

@siddharthjain210 have you read the previous comments?

We are open for suggestions on how to fix it. For now the workaround above can be used.

@siddharthjain210
Copy link

I am not able to understand where should i add this class. Should it be added in the application module. How would the imports from com.oracle.svm would be resolved.

@mokmnovatti
Copy link
Author

@siddharthjain210

Please use it like below

Add the following dependency to your project.

        <dependency>
            <groupId>org.graalvm.nativeimage</groupId>
            <artifactId>svm</artifactId>
            <version>${graalvm-nativeimage-svm.version}</version>
            <scope>provided</scope>
        </dependency>

Create a class in your project with the above content.

When you build your native image, it will load this substitution from the classpath.

@siddharthjain210
Copy link

siddharthjain210 commented Jan 8, 2022

Thanks @mokmnovatti @deki. Able to resolve the issue with the temporary fix. Just needed to add a little change:

import com.oracle.svm.core.annotate.Substitute;
import com.oracle.svm.core.annotate.TargetClass;

@TargetClass(com.amazonaws.serverless.proxy.internal.LambdaContainerHandler.class)
public final class LambdaContainerHandlerSubstitute {

    @Substitute
    private static void registerAfterBurner() {
        System.out.println("Registering after burner is not supported by the Graal VM yet ! ");
    }
}

The GraalVm 21.3 throws an error on using className on @target.

@joain946
Copy link

Is there a workaround for projects that doesn't use GraalVM?
I have a regular Java 11 Lambda which shows this warning during each cold start. Which is a bit annoying.
Since the method is static it means that I can't override it and there is no way of creating my own ObjectMapper that then can be used.
So a way of override it or if it would default use Blackbird would solve my issue.

@deki
Copy link
Collaborator

deki commented Jan 24, 2022

@joain946 as mentioned above we are open for suggestions.

The critical part is in https://github.com/awslabs/aws-serverless-java-container/blob/3b5f1f021dc102678e2fb4da24c798b13b2457dd/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/LambdaContainerHandler.java#L88 so in case you want to create a pull request with a proposal on how to change it, we will definitely review it.

@joain946
Copy link

The problem is that I don't have enough knowledge on what is going on here to be able to do a PR.

First of all, is Afterburner needed at all? Because removing it would solve everything. Not sure if it was added for performance or functionality.

Second would be to not use a static method for registering since that can't be overriden. But maybe that is causing issues for GraalVM instead?

@deki deki added this to the Release 2.0 milestone Jan 25, 2022
@deki
Copy link
Collaborator

deki commented Jan 26, 2022

Well in my view it's not required but the performance is worse without it. So for 2.0 we should probably replace Afterburner with Blackbird and make it configurable so it can be disabled.

@deki
Copy link
Collaborator

deki commented Jan 27, 2022

Just found https://github.com/quarkusio/qson, maybe also worth trying, works well with GraalVM and Quarkus.

@Muthuveerappanv
Copy link

@mokmnovatti I'm trying to create a native-springboot app with graal 21.1 and spring-native. your sample code was helpful in resolving some of the reflection issues. I'm facing this issue now:

2022-05-30 21:22:26.675  WARN 10 --- [           main] w.s.c.ServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is org.springframework.context.ApplicationContextException: Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean.

Have you faced this issue? any help would be appreciated, thanks

Another user has posted in stackoverflow about the same issue - https://stackoverflow.com/questions/72162962/native-image-spring-boot-aws-serverless-java-container-startup-error-mis

@jsyrjala
Copy link

Any plans, estimates or guesses when aws-serverless-java-container 2.0 might be available?

@deki deki removed this from the Release 2.0 milestone Jan 30, 2024
@deki
Copy link
Collaborator

deki commented Jan 30, 2024

We've added a sample for native https://github.com/aws/serverless-java-container/tree/main/samples/springboot3/pet-store-native which is working well. Removing the 2.0 milestone as this issue is no longer a blocker for GraalVM.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants