micronaut-core: Unable to create native image with micronaut-http-client and jansi

I’m trying to build an interactive shell application with Micronaut and Jansi but i’m unable to compile it as a GraalVM native image. The compilation fails when both the jansi and micronaut-http-client dependency are on the classpath. The jansi dependency doesn’t contain any links to the project which contains the class in the exception (netty-tcnative, io.netty.internal.tcnative.SSLPrivateKeyMethod) as far as I know but does use JNI which might trigger the error in Micronaut or Netty.

@ilopmar do you have any idea what could cause this error or how to make GraalVM show which class refers to to the mentioned class?

Task List

  • Steps to reproduce provided
  • Stacktrace (if present) provided
  • Example that reproduces the problem uploaded to Github
  • Full description of the issue provided (see below)

Steps to Reproduce

  1. Create a new Micronaut CLI app (mn create-cli-app --build=maven --lang=java --test=junit --features=graalvm,jib,logback,mockito,shade my.package.app)
  2. Build native image (./mvnw clean package -Dpackaging=docker-native -Pgraalvm)
  3. Add jansi dependency (org.fusesource.jansi:jansi:2.3.2, https://github.com/fusesource/jansi/)
  4. Build native image (./mvnw clean package -Dpackaging=docker-native -Pgraalvm)
  5. Change micronaut-http-client dependency from test to compile scope
  6. Building native image will fail (./mvnw clean package -Dpackaging=docker-native -Pgraalvm)

Expected Behaviour

The GraalVM native image compiler should succeed in creating a native image. This is the case when one of the micronaut-http-client or jansi dependencies are removed.

Actual Behaviour

The GraalVM native image compiler fails with an exception:

Fatal error:java.lang.NoClassDefFoundError
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
	at java.base/java.util.concurrent.ForkJoinTask.getThrowableException(ForkJoinTask.java:603)
	at java.base/java.util.concurrent.ForkJoinTask.get(ForkJoinTask.java:1006)
	at com.oracle.svm.hosted.NativeImageGenerator.run(NativeImageGenerator.java:499)
	at com.oracle.svm.hosted.NativeImageGeneratorRunner.buildImage(NativeImageGeneratorRunner.java:370)
	at com.oracle.svm.hosted.NativeImageGeneratorRunner.build(NativeImageGeneratorRunner.java:531)
	at com.oracle.svm.hosted.NativeImageGeneratorRunner.main(NativeImageGeneratorRunner.java:119)
	at com.oracle.svm.hosted.NativeImageGeneratorRunner$JDK9Plus.main(NativeImageGeneratorRunner.java:568)
Caused by: java.lang.NoClassDefFoundError: io/netty/internal/tcnative/SSLPrivateKeyMethod
	at jdk.internal.vm.ci/jdk.vm.ci.hotspot.CompilerToVM.getDeclaredMethods(Native Method)
	at jdk.internal.vm.ci/jdk.vm.ci.hotspot.HotSpotResolvedObjectTypeImpl.getDeclaredMethods(HotSpotResolvedObjectTypeImpl.java:987)
	at com.oracle.svm.jni.access.JNIAccessibleMethod.anyMatchIgnoreReturnType(JNIAccessibleMethod.java:139)
	at com.oracle.svm.jni.access.JNIAccessibleMember.findHidingSubclasses(JNIAccessibleMember.java:103)
	at com.oracle.svm.jni.access.JNIAccessibleMember.findHidingSubclasses(JNIAccessibleMember.java:110)
	at com.oracle.svm.jni.access.JNIAccessibleMember.setHidingSubclasses(JNIAccessibleMember.java:83)
	at com.oracle.svm.jni.access.JNIAccessibleMethod.finishBeforeCompilation(JNIAccessibleMethod.java:135)
	at com.oracle.svm.jni.access.JNIAccessFeature.beforeCompilation(JNIAccessFeature.java:363)
	at com.oracle.svm.hosted.NativeImageGenerator.lambda$doRun$8(NativeImageGenerator.java:644)
	at com.oracle.svm.hosted.FeatureHandler.forEachFeature(FeatureHandler.java:71)
	at com.oracle.svm.hosted.NativeImageGenerator.doRun(NativeImageGenerator.java:644)
	at com.oracle.svm.hosted.NativeImageGenerator.lambda$run$2(NativeImageGenerator.java:495)
	at java.base/java.util.concurrent.ForkJoinTask$AdaptedRunnableAction.exec(ForkJoinTask.java:1407)
	at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
	at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020)
	at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656)
	at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594)
	at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:183)
Caused by: java.lang.ClassNotFoundException: io.netty.internal.tcnative.SSLPrivateKeyMethod
	at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:471)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:589)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
	... 18 more

Environment Information

  • Operating System: MacOS Catalina / Docker Desktop 3.3.1
  • Micronaut Version: 2.4.2
  • JDK Version: GraalVM Java 11 21.0.0.2 (same for 21.1.0)

Example Application

Example application is simply created with steps to reproduce the issue.

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 17 (17 by maintainers)

Most upvoted comments

@traycho The GraalVM team fixed the issue and it will be included in GraalVM 21.2 (to be released on July 20th). I tried with my application and it works properly. Another thing fixed is that now the substitutions are not needed anymore.

I’ve just tried those SSL substitutions in the sample app used in the GraalVM issue and it works!

I’ve also tried with a new Micronaut 2.4.4 application adding the jansi dependency and with the same substitutions, it works. There is an error with class org/grails/datastore/mapping/validation/ValidationException so I tried using a locally built Micronaut snapshot without that class and, as mentioned it works.

P.S: I’ve tried with a normal Micronaut app and used Gradle, but I think that won’t make any difference.