quarkusio / quarkus

Quarkus: Supersonic Subatomic Java.
https://quarkus.io
Apache License 2.0
13.84k stars 2.7k forks source link

Native image classpath folder structure behaves differently at runtime #44478

Closed watermelonjam closed 1 week ago

watermelonjam commented 1 week ago

Describe the bug

I'm using the Thread.currentThread().getContextClassLoader() to load resources from the classpath at runtime. Works fine as java, but a native image run detects the top level folder but behaves as if it's empty. I'm using quarkus.native.resources.includes to include the resources... and dumping the contents of the native binary using strings shows that the expected resource files are in there somewhere. I've created a minimal reproducer showing unit test pass, integration test fail for the same test.

Expected behavior

Native image should be able to load the same resources as in JRE when those resources are included using quarkus.native.resources.includes.

Actual behavior

Native image class loader detects the folder, not the resources in it.

How to Reproduce?

https://github.com/watermelonjam/native-classpath-reproducer

Output of uname -a or ver

Linux kenny.extr.io 4.18.0-553.22.1.el8_10.x86_64 #1 SMP Wed Sep 11 18:02:00 EDT 2024 x86_64 x86_64 x86_64 GNU/Linux

Output of java -version

openjdk version "17.0.13" 2024-10-15 LTS OpenJDK Runtime Environment (Red_Hat-17.0.13.0.11-1) (build 17.0.13+11-LTS) OpenJDK 64-Bit Server VM (Red_Hat-17.0.13.0.11-1) (build 17.0.13+11-LTS, mixed mode, sharing)

Quarkus version or git rev

3.16.2

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

Maven home: /home/arnoldd/apache-maven-3.8.3 Java version: 17.0.13, vendor: Red Hat, Inc., runtime: /usr/lib/jvm/java-17-openjdk-17.0.13.0.11-3.el8.x86_64 Default locale: en_US, platform encoding: UTF-8 OS name: "linux", version: "4.18.0-553.22.1.el8_10.x86_64", arch: "amd64", family: "unix"

Additional information

No response

quarkus-bot[bot] commented 1 week ago

/cc @zakkak (native-image)

zakkak commented 1 week ago

@watermelonjam the reproducer seems to fail in JVM-mode as well if you change the package type to uber-jar. So this doesn't look like a native issue per se. The following fails as well:

mvn clean package -Dquarkus.package.type=uber-jar
java -jar target/native-classpath-reproducer-1.0.0-SNAPSHOT-runner.jar
curl http://0.0.0.0:8080/greet # from another terminal

I also created a reproducer without Quarkus to demonstrate the issue:

cd /tmp
git clone --branch2024-11-14-directory-resource https://github.com/zakkak/issue-reproducers reproducers
cd reproducers
mvn package
# run in JVM
$JAVA_HOME/java \
  -jar target/reproducer-1.0-SNAPSHOT.jar

Please have a look at https://stackoverflow.com/questions/18758105/how-can-i-count-the-number-of-files-in-a-folder-within-a-jar/18758724#18758724 for more info on why this is happening.

watermelonjam commented 1 week ago

Thanks for the quick diagnosis.

The linked Stack Overflow answer suggests "A better solution would be to generate some kind of 'resource lookup' file at build time". A fine suggestion, so I used a Maven resource list plugin for that. Uber jar works now, as does the native image.

zakkak commented 4 days ago

@watermelonjam you are welcome. Thanks for coming back and documenting the solution you came up with for future reference.