Graal: [native-image] Failed to compile spring-boot project to native image (UnsupportedFeatureException)

Created on 18 Apr 2018  路  12Comments  路  Source: oracle/graal

I'm trying to compile a 'simple' spring-boot web project to native image.
Project source:
https://drive.google.com/file/d/136E00Gux6vL3tvcZFM3KgcNuIvtXWlj1/view?usp=sharing

Command:
native-image -jar graal-0.0.1-SNAPSHOT.jar

Log:

Build on Server(pid: 25018, port: 26682)*
   classlist:   1,200.03 ms
       (cap):   1,115.73 ms
       setup:   2,508.68 ms
    analysis:   8,853.48 ms
error: unsupported features in 3 methods
Detailed message:
Error: com.oracle.graal.pointsto.constraints.UnsupportedFeatureException: Unsupported constructor java.lang.ClassLoader.<init>(ClassLoader) is reachable: The declaring class of this element has been substituted, but this element is not present in the substitution class
To diagnose the issue, you can add the option -H:+ReportUnsupportedElementsAtRuntime. The unsupported element is then reported at run time when it is accessed the first time.
Trace: 
    at parsing java.security.SecureClassLoader.<init>(SecureClassLoader.java:76)
Call path from entry point to java.security.SecureClassLoader.<init>(ClassLoader): 
    at java.security.SecureClassLoader.<init>(SecureClassLoader.java:76)
    at java.net.URLClassLoader.<init>(URLClassLoader.java:100)
    at org.springframework.boot.loader.LaunchedURLClassLoader.<init>(LaunchedURLClassLoader.java:50)
    at org.springframework.boot.loader.Launcher.createClassLoader(Launcher.java:74)
    at org.springframework.boot.loader.Launcher.createClassLoader(Launcher.java:64)
    at org.springframework.boot.loader.Launcher.launch(Launcher.java:49)
    at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:51)
    at com.oracle.svm.reflect.proxies.Proxy_1_JarLauncher_main.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.oracle.svm.core.JavaMainWrapper.run(JavaMainWrapper.java:199)
    at Lcom/oracle/svm/core/code/CEntryPointCallStubs;.com_002eoracle_002esvm_002ecore_002eJavaMainWrapper_002erun_0028int_002corg_002egraalvm_002enativeimage_002ec_002etype_002eCCharPointerPointer_0029(generated:0)
Error: com.oracle.graal.pointsto.constraints.UnsupportedFeatureException: Unsupported field java.net.URL.handlers is reachable
To diagnose the issue, you can add the option -H:+ReportUnsupportedElementsAtRuntime. The unsupported element is then reported at run time when it is accessed the first time.
Trace: 
    at parsing java.net.URL.setURLStreamHandlerFactory(URL.java:1118)
Call path from entry point to java.net.URL.setURLStreamHandlerFactory(URLStreamHandlerFactory): 
    at java.net.URL.setURLStreamHandlerFactory(URL.java:1110)
    at org.springframework.boot.loader.jar.JarFile.resetCachedUrlHandlers(JarFile.java:392)
    at org.springframework.boot.loader.jar.JarFile.registerUrlProtocolHandler(JarFile.java:382)
    at org.springframework.boot.loader.Launcher.launch(Launcher.java:48)
    at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:51)
    at com.oracle.svm.reflect.proxies.Proxy_1_JarLauncher_main.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.oracle.svm.core.JavaMainWrapper.run(JavaMainWrapper.java:199)
    at Lcom/oracle/svm/core/code/CEntryPointCallStubs;.com_002eoracle_002esvm_002ecore_002eJavaMainWrapper_002erun_0028int_002corg_002egraalvm_002enativeimage_002ec_002etype_002eCCharPointerPointer_0029(generated:0)
Error: com.oracle.graal.pointsto.constraints.UnsupportedFeatureException: Unsupported method java.security.ProtectionDomain.getCodeSource() is reachable: The declaring class of this element has been substituted, but this element is not present in the substitution class
To diagnose the issue, you can add the option -H:+ReportUnsupportedElementsAtRuntime. The unsupported element is then reported at run time when it is accessed the first time.
Trace: 
    at parsing org.springframework.boot.loader.Launcher.createArchive(Launcher.java:118)
Call path from entry point to org.springframework.boot.loader.Launcher.createArchive(): 
    at org.springframework.boot.loader.Launcher.createArchive(Launcher.java:117)
    at org.springframework.boot.loader.ExecutableArchiveLauncher.<init>(ExecutableArchiveLauncher.java:38)
    at org.springframework.boot.loader.JarLauncher.<init>(JarLauncher.java:35)
    at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:51)
    at com.oracle.svm.reflect.proxies.Proxy_1_JarLauncher_main.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.oracle.svm.core.JavaMainWrapper.run(JavaMainWrapper.java:199)
    at Lcom/oracle/svm/core/code/CEntryPointCallStubs;.com_002eoracle_002esvm_002ecore_002eJavaMainWrapper_002erun_0028int_002corg_002egraalvm_002enativeimage_002ec_002etype_002eCCharPointerPointer_0029(generated:0)

Error: Processing image build request failed
native-image

Most helpful comment

Well, GraalVM looks promising for microservices world, since services are getting fat and start time is increasing, which breaks one of the microservices paradigm - fast startup.
Since most of the microsevices in java are build upon Spring Boot it's crucial to have possibility to build native image from it.
I would like to use/test as soon issues with spring will be resolved.
Can we make this issue/thread main for spring/boot? :D
Looking forward! Thanks!

All 12 comments

Thank you for your report. Spring-boot uses dynamic class loading which is a limitation of SubstrateVM. Sometimes it is possible to avoid dynamic class loading (which might reduce some functionality). I will look into this possibility for spring-boot.

You can get past this specific error by not using the fat jar launcher as a main method. But there are other bogies lurking. Spring Boot has a static (but optional) dependency on Groovy, for example, so even though it will never be used at runtime, a native-image cannot be built because groovy.lang.Closure is not available for a vanilla app. If you add Groovy to the classpath (even though it will not be used) you can get past that, but the build fails again because of a java.lang.ClassCastException: jdk.vm.ci.hotspot.HotSpotUnresolvedJavaType cannot be cast to jdk.vm.ci.meta.ResolvedJavaType. I managed to build a binary image by creating a dummy, empty interface called groovy.lang.Closure and putting that on the classpath instead of the real groovy. Then the image fails at runtime because of an issue with java.lang.reflect.Proxy (I'll open a separate ticket about that because it might be interesting on its own).

@dsyer can you provide the trace for the java.lang.ClassCastException: jdk.vm.ci.hotspot.HotSpotUnresolvedJavaType cannot be cast to jdk.vm.ci.meta.ResolvedJavaType that you mention above? Thank you!

Sure:

$ native-image -cp ~/.sdkman/candidates/groovy/3.0.0-alpha-2/lib/groovy-3.0.0-alpha-2.jar:$CLASSPATH --no-server -H:Name=hello com.example.LauncherApplication -H:+ReportUnsupportedElementsAtRuntime
   classlist:   2,997.09 ms
       (cap):     868.76 ms
       setup:   1,770.21 ms
    analysis:   7,681.46 ms
fatal error: org.graalvm.compiler.java.BytecodeParser$BytecodeParserError: java.lang.ClassCastException: jdk.vm.ci.hotspot.HotSpotUnresolvedJavaType cannot be cast to jdk.vm.ci.meta.ResolvedJavaType
    at parsing org.springframework.beans.factory.groovy.GroovyDynamicElementReader.invokeMethod(GroovyDynamicElementReader.groovy:75)
    at org.graalvm.compiler.java.BytecodeParser.throwParserError(BytecodeParser.java:2339)
    at com.oracle.svm.hosted.phases.SharedGraphBuilderPhase$SharedBytecodeParser.throwParserError(SharedGraphBuilderPhase.java:92)
    at org.graalvm.compiler.java.BytecodeParser.iterateBytecodesForBlock(BytecodeParser.java:3070)
    at org.graalvm.compiler.java.BytecodeParser.processBlock(BytecodeParser.java:2886)
    at org.graalvm.compiler.java.BytecodeParser.build(BytecodeParser.java:880)
    at org.graalvm.compiler.java.BytecodeParser.buildRootMethod(BytecodeParser.java:774)
    at org.graalvm.compiler.java.GraphBuilderPhase$Instance.run(GraphBuilderPhase.java:93)
    at org.graalvm.compiler.phases.Phase.run(Phase.java:47)
    at org.graalvm.compiler.phases.BasePhase.apply(BasePhase.java:195)
    at org.graalvm.compiler.phases.Phase.apply(Phase.java:40)
    at org.graalvm.compiler.phases.Phase.apply(Phase.java:36)
    at com.oracle.graal.pointsto.flow.MethodTypeFlowBuilder.parse(MethodTypeFlowBuilder.java:195)
    at com.oracle.graal.pointsto.flow.MethodTypeFlowBuilder.apply(MethodTypeFlowBuilder.java:319)
    at com.oracle.graal.pointsto.flow.MethodTypeFlow.doParse(MethodTypeFlow.java:308)
    at com.oracle.graal.pointsto.flow.MethodTypeFlow.ensureParsed(MethodTypeFlow.java:298)
    at com.oracle.graal.pointsto.flow.MethodTypeFlow.addContext(MethodTypeFlow.java:105)
    at com.oracle.graal.pointsto.DefaultAnalysisPolicy$DefaultVirtualInvokeTypeFlow.onObservedUpdate(DefaultAnalysisPolicy.java:184)
    at com.oracle.graal.pointsto.flow.TypeFlow.notifyObservers(TypeFlow.java:345)
    at com.oracle.graal.pointsto.flow.TypeFlow.update(TypeFlow.java:387)
    at com.oracle.graal.pointsto.BigBang$2.run(BigBang.java:498)
    at com.oracle.graal.pointsto.util.CompletionExecutor.lambda$execute$0(CompletionExecutor.java:172)
    at java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1402)
    at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
    at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
    at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
    at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
Caused by: java.lang.ClassCastException: jdk.vm.ci.hotspot.HotSpotUnresolvedJavaType cannot be cast to jdk.vm.ci.meta.ResolvedJavaType
    at com.oracle.graal.pointsto.infrastructure.WrappedConstantPool.lookupConstant(WrappedConstantPool.java:140)
    at org.graalvm.compiler.java.BytecodeParser.lookupConstant(BytecodeParser.java:3828)
    at org.graalvm.compiler.java.BytecodeParser.genLoadConstant(BytecodeParser.java:3566)
    at org.graalvm.compiler.java.BytecodeParser.processBytecode(BytecodeParser.java:4513)
    at org.graalvm.compiler.java.BytecodeParser.iterateBytecodesForBlock(BytecodeParser.java:3065)
    ... 23 more
Error: Image building with exit status 1

is there any other workaround for building native-image for spring boot app, or for now it's blocked w\o any hopes?

There's no way yet to run a Spring Boot application. Not even the GenericConversionService from spring-core will work in a native image right now I think, so that's a blocker for a large class of Spring applications (not just Spring Boot). The Graal team have said they are interested in making it work though, so I wouldn't say there is no hope, but certainly it is blocked on this and other issues.

Well, GraalVM looks promising for microservices world, since services are getting fat and start time is increasing, which breaks one of the microservices paradigm - fast startup.
Since most of the microsevices in java are build upon Spring Boot it's crucial to have possibility to build native image from it.
I would like to use/test as soon issues with spring will be resolved.
Can we make this issue/thread main for spring/boot? :D
Looking forward! Thanks!

See #507 about the ConversionService issue.

I have created SPR-16991 to track SubstrateVM Spring support status.

More than a week ago Josh Long at the beginning of his Devoxx (devoxx.pl) talk demoed a Spring Boot/Fu app built as a native image using GraalVM: https://github.com/spring-projects/spring-fu/issues/29

@joshlong used the Kotlin sample app from here: https://github.com/spring-projects/spring-fu/issues/29. There's another minimal Spring app in Java here that works: https://github.com/dsyer/spring-boot-micro-apps (see the instructions in the README). Neither of those apps uses Spring Boot.

The originally reported issue has been fixed. With the latest release, you can build an image using native-image --report-unsupported-elements-at-runtime -jar build/libs/graal-0.0.1-SNAPSHOT.jar. However, running the image I get:

$ ./graal-0.0.1-SNAPSHOT 
Exception in thread "main" java.lang.IllegalStateException: java.lang.IllegalStateException: Unable to determine code source archive
    at org.springframework.boot.loader.ExecutableArchiveLauncher.<init>(ExecutableArchiveLauncher.java:41)
    at org.springframework.boot.loader.JarLauncher.<init>(JarLauncher.java:35)
    at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:51)
Caused by: java.lang.IllegalStateException: Unable to determine code source archive
    at org.springframework.boot.loader.Launcher.createArchive(Launcher.java:122)
    at org.springframework.boot.loader.ExecutableArchiveLauncher.<init>(ExecutableArchiveLauncher.java:38)
    ... 2 more

It looks like the example app tries to execute a jar which is currently not supported with native-image.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

igor-ramazanov picture igor-ramazanov  路  3Comments

jinwuxia picture jinwuxia  路  3Comments

janostgren picture janostgren  路  3Comments

sxend picture sxend  路  3Comments

helloguo picture helloguo  路  3Comments