-
Notifications
You must be signed in to change notification settings - Fork 3k
Description
Describe the bug
Howdy everyone.
Imagine the following project setup (with Gradle):
3 projects on the top level
:runner
-> this is a minimal Quarkus app with REST extension and a single stub endpoint, and it depends on:project-a
, which has a single class, and this project depends on:project-b
, which has a single class and no additional dependencies
Additionally, :project-a
does configure the jar
task in the following way:
jar {
archiveClassifier = "something"
archiveBaseName = "project-a"
}
Expected behavior
My expectation is that when I call an endpoint from the :runner
project, it does not throw and does the work it needs to do.
Actual behavior
When the :runner
is run in dev mode, and the endpoint is called, I get:
2025-05-27 23:06:03,346 ERROR [io.qua.ver.htt.run.QuarkusErrorHandler] (executor-thread-1) HTTP Request to /hello failed, error id: 9064607e-6c5e-45a4-83a2-d3b31c105faa-1: java.lang.NoClassDefFoundError: io/leaf/SomeCLass
at io.blob.Intermediate.someMethod(Intermediate.java:8)
at io.example.ExampleResource.hello(ExampleResource.java:16)
at io.example.ExampleResource$quarkusrestinvoker$hello_df324e1539083188359af68039a7afafb7b77cdb.invoke(Unknown Source)
at org.jboss.resteasy.reactive.server.handlers.InvocationHandler.handle(InvocationHandler.java:29)
at io.quarkus.resteasy.reactive.server.runtime.QuarkusResteasyReactiveRequestContext.invokeHandler(QuarkusResteasyReactiveRequestContext.java:141)
at org.jboss.resteasy.reactive.common.core.AbstractResteasyReactiveContext.run(AbstractResteasyReactiveContext.java:147)
at io.quarkus.vertx.core.runtime.VertxCoreRecorder$15.runWith(VertxCoreRecorder.java:637)
at org.jboss.threads.EnhancedQueueExecutor$Task.doRunWith(EnhancedQueueExecutor.java:2675)
at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2654)
at org.jboss.threads.EnhancedQueueExecutor.runThreadBody(EnhancedQueueExecutor.java:1627)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1594)
at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:11)
at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:11)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:1583)
Caused by: java.lang.ClassNotFoundException: io.leaf.SomeCLass
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:526)
at io.quarkus.bootstrap.classloading.QuarkusClassLoader.loadClass(QuarkusClassLoader.java:576)
at io.quarkus.bootstrap.classloading.QuarkusClassLoader.loadClass(QuarkusClassLoader.java:523)
... 15 more
io.leaf.SomeCLass
is located in :project-b
.
How to Reproduce?
A minimal reproducer can be found in this public repo: https://github.com/reaver585/quarkus-jar-classloading
To reproduce:
- Clone the repo.
./gradlew --console=plain :runner:quarkusDev
curl -X GET --location "http://localhost:8080/hello"
- Observe the exception in the logs.
Output of uname -a
or ver
Darwin TW-MBP-M2 24.4.0 Darwin Kernel Version 24.4.0: Fri Apr 11 18:33:39 PDT 2025; root:xnu-11417.101.15~117/RELEASE_ARM64_T6020 arm64
Output of java -version
openjdk version "21.0.7" 2025-04-15 LTS OpenJDK Runtime Environment Temurin-21.0.7+6 (build 21.0.7+6-LTS) OpenJDK 64-Bit Server VM Temurin-21.0.7+6 (build 21.0.7+6-LTS, mixed mode, sharing)
Quarkus version or git rev
3.22.1
Build tool (ie. output of mvnw --version
or gradlew --version
)
Gradle 8.13
Additional information
The issue stops manifesting if:
- I comment out the jar task completely
- I comment out the
archiveClassifier = "something"
line in the jar config.
So my hunch is that there is some logic that assigns my classes to the wrong classloader based on the presence of archive classifier for the jar. It causes io.blob.Intermediate
class in :project-a
to be loaded via base runtime classloader which then cannot see the io.leaf.SomeCLass
from :project-b
.
If this is indeed a bug, I wouldn't mind help you fix it if you point me in the right direction.
Thanks in advance.