dev mode is not working in a gradle multimodule setup when kotlin code is used #35577
Description
Describe the bug
I am in a multi-module gradle project.
:core-lib
shared 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
:app1
quarkus app- contains a Rest endpoint using
@Inject
to 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 kordamp/jandex-gradle-plugin#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.
Activity