serverless-java-container icon indicating copy to clipboard operation
serverless-java-container copied to clipboard

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

Open mokmnovatti opened this issue 4 years ago • 17 comments

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

mokmnovatti avatar Oct 12 '21 12:10 mokmnovatti

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?

deki avatar Oct 12 '21 12:10 deki

Sure thing !

mokmnovatti avatar Oct 12 '21 12:10 mokmnovatti

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 avatar Oct 13 '21 03:10 mokmnovatti

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 ! ");
    }
}

mokmnovatti avatar Oct 14 '21 03:10 mokmnovatti

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

siddharthjain210 avatar Jan 06 '22 18:01 siddharthjain210

@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.

deki avatar Jan 06 '22 19:01 deki

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.

siddharthjain210 avatar Jan 08 '22 06:01 siddharthjain210

@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.

mokmnovatti avatar Jan 08 '22 07:01 mokmnovatti

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.

siddharthjain210 avatar Jan 08 '22 14:01 siddharthjain210

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.

joain946 avatar Jan 17 '22 14:01 joain946

@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.

deki avatar Jan 24 '22 19:01 deki

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?

joain946 avatar Jan 25 '22 10:01 joain946

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 avatar Jan 26 '22 09:01 deki

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

deki avatar Jan 27 '22 05:01 deki

@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

Muthuveerappanv avatar May 30 '22 22:05 Muthuveerappanv

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

jsyrjala avatar Dec 14 '22 08:12 jsyrjala

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.

deki avatar Jan 30 '24 07:01 deki