quarkus: dev mode is not working in a gradle multimodule setup when kotlin code is used
Describe the bug
I am in a multi-module gradle project.
:core-libshared lib- contains java and kotlin code (classes annotated with
@ApplicationScoped) - jandex plugin is configured
- kotlin for quarkus is configured (incl. the allopen plugin)
- contains java and kotlin code (classes annotated with
:app1quarkus app- contains a Rest endpoint using
@Injectto get the services from thecore-lib
- contains a Rest endpoint using
In a real setup there are more modules (multiple shared modules, and multiple quarkus app that achieve different tasks of a more complex system)
Building the app and running it with java -jar app1/build/quarkus-app/quarkus-run.jar runs perfectly fine.
Running with dev mode ./gradlew app1:quarkusDev is failing:
jakarta.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type org.acme.core.kt.ConfigService and qualifiers [@Default]
- java member: org.acme.app1.App1Controller#config
- declared on CLASS bean [types=[org.acme.app1.App1Controller, java.lang.Object], qualifiers=[@Default, @Any], target=org.acme.app1.App1Controller]
at io.quarkus.arc.processor.Beans.resolveInjectionPoint(Beans.java:477)
at io.quarkus.arc.processor.BeanInfo.init(BeanInfo.java:624)
at io.quarkus.arc.processor.BeanDeployment.init(BeanDeployment.java:299)
...
(complete trace at the bottom of this message)
The error is similar to when the jandex plugin in not running in core-lib (from the docs: Working with multi-module gradle projects).
But this is not the case here. Jandex is configured and is working.
Also a work-around for https://github.com/kordamp/jandex-gradle-plugin/issues/24 is in place.
But what is wired is that:
./gradlew (clean) build
java -jar app1/build/quarkus-app/quarkus-run.jar
works perfectly.
Also when we build the docker image of the quarkus app, everything is working correctly.
And the issue is only present when the core-lib module contains kotlin code. With only java code everything works as expected.
This is only a dev-mode issue.
How to Reproduce?
See repository: https://github.com/jmini/quarkus_issue35577
Output of uname -a or ver
22.3.0 Darwin Kernel Version 22.3.0: Mon Jan 30 20:42:11 PST 2023; root:xnu-8792.81.3~2/RELEASE_X86_64 x86_64
macOS, but it doesn’t matter.
We observe the same on Linux.
Output of java -version
openjdk version "17.0.5" 2022-10-18
OpenJDK Runtime Environment Temurin-17.0.5+8 (build 17.0.5+8)
OpenJDK 64-Bit Server VM Temurin-17.0.5+8 (build 17.0.5+8, mixed mode, sharing)
GraalVM version (if different from Java)
not relevant
Quarkus version or git rev
3.3.0 (reproducible as well with lower versions)
Build tool (ie. output of mvnw --version or gradlew --version)
------------------------------------------------------------
Gradle 8.1.1
------------------------------------------------------------
Build time: 2023-04-21 12:31:26 UTC
Revision: 1cf537a851c635c364a4214885f8b9798051175b
Kotlin: 1.8.10
Groovy: 3.0.15
Ant: Apache Ant(TM) version 1.10.11 compiled on July 10 2021
JVM: 17.0.5 (Eclipse Adoptium 17.0.5+8)
OS: Mac OS X 13.2.1 x86_64
Additional information
Complete error when running `./gradlew app1:quarkusDev`
2023-08-26 13:38:06,883 INFO [io.qua.dep.dev.IsolatedDevModeMain] (main) Attempting to start live reload endpoint to recover from previous Quarkus startup failure
> :ap2023-08-26 13:38:07,507 ERROR [io.qua.dep.dev.IsolatedDevModeMain] (main) Failed to start quarkus: java.lang.RuntimeException: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
[error]: Build step io.quarkus.arc.deployment.ArcProcessor#validate threw an exception: jakarta.enterprise.inject.spi.DeploymentException: jakarta.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type org.acme.core.kt.ConfigService and qualifiers [@Default]
- java member: org.acme.app1.App1Controller#config
- declared on CLASS bean [types=[org.acme.app1.App1Controller, java.lang.Object], qualifiers=[@Default, @Any], target=org.acme.app1.App1Controller]
at io.quarkus.arc.processor.BeanDeployment.processErrors(BeanDeployment.java:1447)
at io.quarkus.arc.processor.BeanDeployment.init(BeanDeployment.java:311)
at io.quarkus.arc.processor.BeanProcessor.initialize(BeanProcessor.java:158)
at io.quarkus.arc.deployment.ArcProcessor.validate(ArcProcessor.java:469)
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.deployment.ExtensionLoader$3.execute(ExtensionLoader.java:858)
at io.quarkus.builder.BuildContext.run(BuildContext.java:282)
at org.jboss.threads.ContextHandler$1.runWith(ContextHandler.java:18)
at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2513)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1538)
at java.base/java.lang.Thread.run(Thread.java:833)
at org.jboss.threads.JBossThread.run(JBossThread.java:501)
Caused by: jakarta.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type org.acme.core.kt.ConfigService and qualifiers [@Default]
- java member: org.acme.app1.App1Controller#config
- declared on CLASS bean [types=[org.acme.app1.App1Controller, java.lang.Object], qualifiers=[@Default, @Any], target=org.acme.app1.App1Controller]
at io.quarkus.arc.processor.Beans.resolveInjectionPoint(Beans.java:477)
at io.quarkus.arc.processor.BeanInfo.init(BeanInfo.java:624)
at io.quarkus.arc.processor.BeanDeployment.init(BeanDeployment.java:299)
... 13 more
at io.quarkus.runner.bootstrap.AugmentActionImpl.runAugment(AugmentActionImpl.java:336)
at io.quarkus.runner.bootstrap.AugmentActionImpl.createInitialRuntimeApplication(AugmentActionImpl.java:253)
at io.quarkus.runner.bootstrap.AugmentActionImpl.createInitialRuntimeApplication(AugmentActionImpl.java:60)
at io.quarkus.deployment.dev.IsolatedDevModeMain.firstStart(IsolatedDevModeMain.java:82)
at io.quarkus.deployment.dev.IsolatedDevModeMain.accept(IsolatedDevModeMain.java:423)
at io.quarkus.deployment.dev.IsolatedDevModeMain.accept(IsolatedDevModeMain.java:55)
at io.quarkus.bootstrap.app.CuratedApplication.runInCl(CuratedApplication.java:138)
at io.quarkus.bootstrap.app.CuratedApplication.runInAugmentClassLoader(CuratedApplication.java:93)
at io.quarkus.deployment.dev.DevModeMain.start(DevModeMain.java:131)
at io.quarkus.deployment.dev.DevModeMain.main(DevModeMain.java:62)
Caused by: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
[error]: Build step io.quarkus.arc.deployment.ArcProcessor#validate threw an exception: jakarta.enterprise.inject.spi.DeploymentException: jakarta.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type org.acme.core.kt.ConfigService and qualifiers [@Default]
- java member: org.acme.app1.App1Controller#config
- declared on CLASS bean [types=[org.acme.app1.App1Controller, java.lang.Object], qualifiers=[@Default, @Any], target=org.acme.app1.App1Controller]
at io.quarkus.arc.processor.BeanDeployment.processErrors(BeanDeployment.java:1447)
at io.quarkus.arc.processor.BeanDeployment.init(BeanDeployment.java:311)
at io.quarkus.arc.processor.BeanProcessor.initialize(BeanProcessor.java:158)
at io.quarkus.arc.deployment.ArcProcessor.validate(ArcProcessor.java:469)
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.deployment.ExtensionLoader$3.execute(ExtensionLoader.java:858)
at io.quarkus.builder.BuildContext.run(BuildContext.java:282)
at org.jboss.threads.ContextHandler$1.runWith(ContextHandler.java:18)
at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2513)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1538)
at java.base/java.lang.Thread.run(Thread.java:833)
at org.jboss.threads.JBossThread.run(JBossThread.java:501)
Caused by: jakarta.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type org.acme.core.kt.ConfigService and qualifiers [@Default]
- java member: org.acme.app1.App1Controller#config
- declared on CLASS bean [types=[org.acme.app1.App1Controller, java.lang.Object], qualifiers=[@Default, @Any], target=org.acme.app1.App1Controller]
at io.quarkus.arc.processor.Beans.resolveInjectionPoint(Beans.java:477)
at io.quarkus.arc.processor.BeanInfo.init(BeanInfo.java:624)
at io.quarkus.arc.processor.BeanDeployment.init(BeanDeployment.java:299)
... 13 more
at io.quarkus.builder.Execution.run(Execution.java:123)
at io.quarkus.builder.BuildExecutionBuilder.execute(BuildExecutionBuilder.java:79)
at io.quarkus.deployment.QuarkusAugmentor.run(QuarkusAugmentor.java:160)
at io.quarkus.runner.bootstrap.AugmentActionImpl.runAugment(AugmentActionImpl.java:332)
... 9 more
Caused by: jakarta.enterprise.inject.spi.DeploymentException: jakarta.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type org.acme.core.kt.ConfigService and qualifiers [@Default]
- java member: org.acme.app1.App1Controller#config
- declared on CLASS bean [types=[org.acme.app1.App1Controller, java.lang.Object], qualifiers=[@Default, @Any], target=org.acme.app1.App1Controller]
at io.quarkus.arc.processor.BeanDeployment.processErrors(BeanDeployment.java:1447)
at io.quarkus.arc.processor.BeanDeployment.init(BeanDeployment.java:311)
at io.quarkus.arc.processor.BeanProcessor.initialize(BeanProcessor.java:158)
at io.quarkus.arc.deployment.ArcProcessor.validate(ArcProcessor.java:469)
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.deployment.ExtensionLoader$3.execute(ExtensionLoader.java:858)
at io.quarkus.builder.BuildContext.run(BuildContext.java:282)
at org.jboss.threads.ContextHandler$1.runWith(ContextHandler.java:18)
at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2513)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1538)
at java.base/java.lang.Thread.run(Thread.java:833)
at org.jboss.threads.JBossThread.run(JBossThread.java:501)
Caused by: jakarta.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type org.acme.core.kt.ConfigService and qualifiers [@Default]
- java member: org.acme.app1.App1Controller#config
- declared on CLASS bean [types=[org.acme.app1.App1Controller, java.lang.Object], qualifiers=[@Default, @Any], target=org.acme.app1.App1Controller]
at io.quarkus.arc.processor.Beans.resolveInjectionPoint(Beans.java:477)
at io.quarkus.arc.processor.BeanInfo.init(BeanInfo.java:624)
at io.quarkus.arc.processor.BeanDeployment.init(BeanDeployment.java:299)
... 13 more
I have tried to inspect the generated jandex file in core-lib (using a jbang script) and it looks OK (my classes and its annotation are present)
Script to inspect the jandex index
///usr/bin/env jbang "$0" "$@" ; exit $?
//DEPS io.smallrye:jandex:3.1.2
//JAVA 17
import java.io.FileInputStream;
import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.Index;
import org.jboss.jandex.IndexReader;
public class JandexMain {
public static void main(String[] args) throws Exception {
try (FileInputStream input = new FileInputStream("core-lib/build/resources/main/META-INF/jandex.idx")) {
IndexReader reader = new IndexReader(input);
Index index = reader.read();
// java.util.Collection<ClassInfo> knownClasses = index.getKnownClasses();
// System.out.println(knownClasses.size());
// for (ClassInfo classInfo : knownClasses) {
// System.out.println(classInfo.name());
// }
System.out.println("--- org.acme.core.CoreProcessor");
ClassInfo reportingService = index.getClassByName("org.acme.core.CoreProcessor");
for (AnnotationInstance a : reportingService.annotations()) {
System.out.println(a.name());
}
System.out.println("--- org.acme.core.kt.ConfigService");
ClassInfo foo = index.getClassByName("org.acme.core.kt.ConfigService");
for (AnnotationInstance a : foo.annotations()) {
System.out.println(a.name());
}
}
}
}
Also when look at the trace logs of the Annotation Transformers (see docs), configured with:
quarkus.log.category."io.quarkus.arc.processor".min-level=TRACE
quarkus.log.category."io.quarkus.arc.processor".level=TRACE
I see only the line for the class written in java:
2023-08-26 13:56:06,883 TRACE [io.qua.arc.pro.BeanDeployment] (build-17) Created CLASS bean [types=[java.lang.Object, org.acme.core.CoreProcessor], qualifiers=[@Default, @Any], target=org.acme.core.CoreProcessor]
Nothing for the class written in Kotin, so it makes sense that it can not be injected later on.
About this issue
- Original URL
- State: open
- Created 10 months ago
- Comments: 22 (21 by maintainers)
Commits related to this issue
- Make sure all the ClassesDirs are added to sourceDirs Fixes #35577 — committed to jmini/quarkus by jmini 10 months ago
- Make sure all the ClassesDirs are added to sourceDirs Fixes #35577 — committed to jmini/quarkus by jmini 10 months ago
- Make sure all the ClassesDirs are added to sourceDirs Fixes #35577 — committed to jmini/quarkus by jmini 10 months ago
- Make sure all the ClassesDirs are added to sourceDirs Fixes #35577 — committed to jmini/quarkus by jmini 10 months ago
@jmini yes you are right, the path
build/classes/kotlin/mainis missing. I’m looking on how we could detect the kotlin folder to add it.We might want to consider both, depending on the scope of the big change and how the small hack would look like. If a small hack looks like a quick reasonable change that would unblock people, let’s consider that first and work on a bigger and proper change to fix it. I’ll be interested in collaborating on that.
Gradle ITs are in https://github.com/quarkusio/quarkus/tree/main/integration-tests/gradle. Given that the Quarkus project is Maven a project, Gradle ITs are actually launched from Maven. Meaning to run Gradle ITs from that module you could execute
mvn clean testto run all the tests ormvn clean test -Dtest=<test-class-name>to run a specific test.The test projects are located under
main/resourcesand copied totarget/classesand then also pre-processed as part of the test setup to set the appropriate Quarkus version matching the one in the main project.Are there any updates on this issue? This is quite a pain in a bigger project.