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

HotSpot mode NoClassDefFoundError: org/graalvm/nativeimage/ImageInfo #30998

Closed
Karm opened this issue Feb 8, 2023 · 12 comments
Closed

HotSpot mode NoClassDefFoundError: org/graalvm/nativeimage/ImageInfo #30998

Karm opened this issue Feb 8, 2023 · 12 comments
Assignees
Labels
area/mandrel kind/bug Something isn't working triage/wontfix This will not be worked on

Comments

@Karm
Copy link
Member

Karm commented Feb 8, 2023

Describe the bug

I have this MicroProfile smoke test Quarkus app that used to work the way I build it both in Native and in JVM mode. It seems that the JVM (HotSpot) mode of running a jar is broken, with Q 2.16.0 and 2.16.1 too. It might be something no longer compatible in the pom, old maven, deprecated way of treating the app, no necessarily a bug.
I do realize this is unlikely to be a Quarkus bug as a whole CI hell would have been loose otherwise already.

It's #28650

Expected behavior

Both native and JVM mode work.

Actual behavior

JVM mode is missing org.graalvm.sdk.graal-sdk?

How to Reproduce?

Env

$ git clone https://github.com/Karm/mandrel-integration-tests.git
$ cd mandrel-integration-tests/apps/quarkus-full-microprofile/
$ export JAVA_HOME=/home/karm/workspaceRH/mandrel-release/mandrel-java17-22.3.1.0-Final/;export GRAALVM_HOME=${JAVA_HOME};export PATH=${JAVA_HOME}/bin:${PATH}
$ native-image --version
native-image 22.3.1.0-Final Mandrel Distribution (Java Version 17.0.6+10)
$ java --version
openjdk 17.0.6 2023-01-17
OpenJDK Runtime Environment Temurin-17.0.6+10 (build 17.0.6+10)
OpenJDK 64-Bit Server VM Temurin-17.0.6+10 (build 17.0.6+10, mixed mode, sharing)
$ javac --version
javac 17.0.6
$ mvn --version
Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f)

2.13.7 ✔️

$ mvn clean compile package -Pnative -Dquarkus.version=2.13.7.Final -Dquarkus.native.additional-build-args=-H:Log=registerResource:,--trace-object-instantiation=java.util.Random,--initialize-at-run-time=io.vertx.ext.auth.impl.jose.JWT,-R:MaxHeapSize=2560m,-H:BuildOutputJSONFile=quarkus-json.json
....
Log: https://karms.biz/pastebin/q-2.13.7-m-22.3.1.0-sdfdjfds.txt
$ ./target/quarkus-runner
Works
$ java -jar target/quarkus-app/quarkus-run.jar 
Works
$ rm -rf target/

2.16.1 ❌

$ mvn clean compile package -Pnative -Dquarkus.version=2.16.1.Final -Dquarkus.native.additional-build-args=-H:Log=registerResource:,--trace-object-instantiation=java.util.Random,--initialize-at-run-time=io.vertx.ext.auth.impl.jose.JWT,-R:MaxHeapSize=2560m,-H:BuildOutputJSONFile=quarkus-json.json
...
Log: https://karms.biz/pastebin/q-2.16.1-m-22.3.1.0-sdfdjfds.txt
$ ./target/quarkus-runner
Works

$ java -jar target/quarkus-app/quarkus-run.jar 
Fails:

The DelayedHandler was closed before any children handlers were configured. Messages will be written to stderr.
2023-02-08 10:44:09,082 DEBUG [org.jboss.logging] (main) Logging Provider: org.jboss.logging.JBossLogManagerProvider

Exception in thread "main" java.lang.reflect.InvocationTargetException
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at io.quarkus.bootstrap.runner.QuarkusEntryPoint.doRun(QuarkusEntryPoint.java:61)
    at io.quarkus.bootstrap.runner.QuarkusEntryPoint.main(QuarkusEntryPoint.java:32)
Caused by: java.lang.ExceptionInInitializerError
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
    at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
    at io.quarkus.runtime.Quarkus.run(Quarkus.java:70)
    at io.quarkus.runtime.Quarkus.run(Quarkus.java:44)
    at io.quarkus.runtime.Quarkus.run(Quarkus.java:124)
    at io.quarkus.runner.GeneratedMain.main(Unknown Source)
    ... 6 more
Caused by: java.lang.RuntimeException: Failed to start quarkus
    at io.quarkus.runner.ApplicationImpl.<clinit>(Unknown Source)
    ... 15 more
Caused by: java.lang.NoClassDefFoundError: org/graalvm/nativeimage/ImageInfo
    at io.quarkus.runtime.ImageMode.current(ImageMode.java:40)
    at io.quarkus.runtime.logging.LoggingSetupRecorder.initializeLoggingForImageBuild(LoggingSetupRecorder.java:495)
    at io.quarkus.deployment.steps.LoggingResourceProcessor$setupLoggingStaticInit2062061316.deploy_0(Unknown Source)
    at io.quarkus.deployment.steps.LoggingResourceProcessor$setupLoggingStaticInit2062061316.deploy(Unknown Source)
    ... 16 more
Caused by: java.lang.ClassNotFoundException: org.graalvm.nativeimage.ImageInfo
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
    at io.quarkus.bootstrap.runner.RunnerClassLoader.loadClass(RunnerClassLoader.java:115)
    at io.quarkus.bootstrap.runner.RunnerClassLoader.loadClass(RunnerClassLoader.java:65)
    ... 20 more

Ad SDK jar: No org.graalvm.sdk.graal-sdk-22.3.0 for 2.16:

$ find -type f | xargs grep ImageInfo
Binary file ./target_Q2.16/quarkus-app/lib/boot/io.quarkus.quarkus-bootstrap-runner-2.16.0.Final.jar matches
Binary file ./target_Q2.16/quarkus-native-image-source-jar/lib/io.quarkus.quarkus-bootstrap-runner-2.16.0.Final.jar matches
Binary file ./target_Q2.16/quarkus-runner matches
Binary file ./target_Q2.13.7/quarkus-app/lib/boot/org.graalvm.sdk.graal-sdk-22.3.0.jar matches
Binary file ./target_Q2.13.7/quarkus-app/lib/boot/io.quarkus.quarkus-bootstrap-runner-2.13.7.Final.jar matches
Binary file ./target_Q2.13.7/quarkus-native-image-source-jar/lib/org.graalvm.sdk.graal-sdk-22.3.0.jar matches
Binary file ./target_Q2.13.7/quarkus-native-image-source-jar/lib/io.quarkus.quarkus-bootstrap-runner-2.13.7.Final.jar matches
Binary file ./target_Q2.13.7/quarkus-runner matches

Output of uname -a or ver

Linux amd64

Output of java -version

17.0.6

GraalVM version (if different from Java)

22.3.1.0

Quarkus version or git rev

2.16.1, 2.13.7

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

Maven 3.6.3

Additional information

No response

@Karm Karm added the kind/bug Something isn't working label Feb 8, 2023
@Karm Karm self-assigned this Feb 8, 2023
@quarkus-bot
Copy link

quarkus-bot bot commented Feb 8, 2023

/cc @galderz (mandrel), @zakkak (mandrel)

@Karm
Copy link
Member Author

Karm commented Feb 8, 2023

Hmm:

2ae0c0e

apache/camel-quarkus#4218

@zakkak
Copy link
Contributor

zakkak commented Feb 8, 2023

So the issue seems to be that you are building a runner jar for native compilation and then try to run it in JVM-mode with HotSpot. I guess running the runner jar makes sense when testing.

I wonder if it would be acceptable to have to use GraalVM in such cases? Probably not, since in the common case it's expected to use a builder image and thus not have GraalVM locally installed making it hard to run the jar with GraalVM instead of HotSpot.

@Karm
Copy link
Member Author

Karm commented Feb 8, 2023

@zakkak I admit my use case is, similarly to apache/camel-quarkus#4218, a testing one, not a production deploy one.

The trouble I perceive is that we would like people to have well tested JVM mode Quarkus app that they can built into a native executable without too many surprises.

Enforcing separate build flows seems like a bad workflow for me (to me too).

I would like to run the build once, getting both runnable jar and a native executable. I can then run tests, see that the behavior of those two apps is adequately similar and then I can deploy the native app.

I don't want to run another build for that, introducing more possible maven entropy...

@Karm
Copy link
Member Author

Karm commented Feb 8, 2023

PR introducing the change (for reference) : #28650

@zakkak
Copy link
Contributor

zakkak commented Feb 8, 2023

I am afraid what you wish for might not be actually what you want :)

we would like people to have well tested JVM mode Quarkus app that they can built into a native executable without too many surprises.

I see where you are coming from, but keep in mind that the runners produced for native compilation are different to the runners produced for JVM-mode use. The main difference is that the ones targeting native compilation come with more native-related stuff included (e.g. substitution classes, reflection configurations, etc.), in the past they also used to be packaged differently (fat jars vs thin jars) not sure if that's still the case.

Enforcing separate build flows seems like a bad workflow for me (to me too).

I would like to run the build once, getting both runnable jar and a native executable. I can then run tests, see that the behavior of those two apps is adequately similar and then I can deploy the native app.

Not sure how we could achieve this without adding bloat to the regular builds or without introducing possibly unnecessary build-time overheads for native builds. cc @geoand @Sanne for feedback

@geoand
Copy link
Contributor

geoand commented Feb 8, 2023

Yeah, we don't really want to do this. As @zakkak mentioned, the jar for JVM mode is as lean as possible and the jar that serves the purpose of being fed into native-image is also tailor made to help with native image compilation.

I personally see no reason we would provide the same artifact for both scenarios and honestly no one has complained in the 3+ years we have been doing things the way we have.

@Karm
Copy link
Member Author

Karm commented Feb 8, 2023

The main difference is that the ones targeting native compilation come with more native-related stuff included (e.g. substitution classes, reflection configurations, etc.), in the past they also used to be packaged differently (fat jars vs thin jars) not sure if that's still the case.

I am cool with having to call a different runnable jar in a different subdir. Btw I am not calling ./target/quarkus-native-image-source-jar/quarkus-runner.jar, I was using ./target/quarkus-app/quarkus-run.jar.

Not sure how we could achieve this without adding bloat to the regular builds or without introducing possibly unnecessary build-time overheads for native builds

I also don't have a PR handy right now, yet it seem to me this is something we should give a second thought to.
Trying to rephrase my babbling story into a single sentence:

I would like to enable users to create a native executable and a runnable jar with a single Maven build.

@Karm
Copy link
Member Author

Karm commented Feb 8, 2023

@geoand

I personally see no reason we would provide the same artifact for both scenarios

I am not asking for having a single jar artifact to be both the runnable one and to be the one fed to native-image. My point is about not having to run another Maven build.

@geoand
Copy link
Contributor

geoand commented Feb 8, 2023

I would like to enable users to create a native executable and a runnable jar with a single Maven build.

It's doable, no doubt. But no one has asked for it, so I would refrain for adding this capability until we have a real need.

@geoand
Copy link
Contributor

geoand commented Feb 8, 2023

Furthermore, this would complicate other things like:

  • Building a container image
  • Running integration tests

as you know have to figure out which artifact to perform these operations for...

@Karm
Copy link
Member Author

Karm commented Feb 8, 2023

@geoand @zakkak O.K., I acquiesce. I will double the builds in my flow, a set for JVM and a set for Native separately.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/mandrel kind/bug Something isn't working triage/wontfix This will not be worked on
Projects
None yet
Development

No branches or pull requests

3 participants