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

Gradle + mixed Kotlin/Java application: @QuarkusTest ignores annotations on classes implemented in Java #13155

Closed
yrodiere opened this issue Nov 6, 2020 · 2 comments · Fixed by #13174
Assignees
Labels
Milestone

Comments

@yrodiere
Copy link
Member

yrodiere commented Nov 6, 2020

Describe the bug
When an application relies on Gradle to compile code implemented in both Kotlin and Java, then any Quarkus test (@QuarkusTest) will ignore annotations on classes implemented in Java.

Only ./gradlew test with @QuarkusTest is affected:

  • ./gradlew quarkusDev works perfectly
  • Maven works perfectly too, be it with ./mvnw test or ./mvnw initialize quarkus:dev.

Expected behavior

I expected annotations on Java classes to be detected.

Actual behavior

Annotations on Java classes are ignored. For example, a bean annotated with @ApplicationScoped will be ignored and attempting to inject it will fail:

                javax.enterprise.inject.spi.DeploymentException: javax.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type io.quarkus.bugs.java.JavaComponent and qualifiers [@Default]
                        - java member: io.quarkus.bugs.KotlinService#javaComponent
                        - declared on CLASS bean [types=[io.quarkus.bugs.KotlinService, java.lang.Object], qualifiers=[@Default, @Any], target=io.quarkus.bugs.KotlinService]

To Reproduce

Reproducer with Gradle: https://github.com/yrodiere/quarkus-bug-mixed-kotlin-java

Run ./gradlew clean test: it fails.

                javax.enterprise.inject.spi.DeploymentException: javax.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type io.quarkus.bugs.java.JavaComponent and qualifiers [@Default]
                        - java member: io.quarkus.bugs.KotlinService#javaComponent
                        - declared on CLASS bean [types=[io.quarkus.bugs.KotlinService, java.lang.Object], qualifiers=[@Default, @Any], target=io.quarkus.bugs.KotlinService]

Run ./gradlew quarkus:dev, then curl http://0.0.0.0:8080/hello: it works.

hello from JavaComponent

See the branch maven on the same repository for a proof that it works with Maven.

Run mvn initialize quarkus:dev (initialize is necessary to add another source directory), then curl http://0.0.0.0:8080/hello: it works.

hello from JavaComponent

Run mvn clean test: it works.

[INFO] BUILD SUCCESS

Configuration
N/A

Environment (please complete the following information):

  • Output of uname -a or ver: Linux yrodiere.redhat 5.8.17-200.fc32.x86_64 #1 SMP Thu Oct 29 18:14:53 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
  • Output of java -version:
openjdk version "11.0.9" 2020-10-20
OpenJDK Runtime Environment AdoptOpenJDK (build 11.0.9+11)
OpenJDK 64-Bit Server VM AdoptOpenJDK (build 11.0.9+11, mixed mode)
  • GraalVM version (if different from Java): N/A
  • Quarkus version or git rev: 1.9.2
  • Build tool (ie. output of mvnw --version or gradlew --version):

Additional context

I believe the culprit is in how QuarkusTestExtension infers the location of classes. What it does:

  • Take the test class, retrieve its location (io.quarkus.test.common.PathTestHelper#getTestClassesLocation)
  • Use a hardcoded map to infer the location of main classes (io.quarkus.test.common.PathTestHelper#getAppClassLocationForTestLocation).

But in the case of Gradle with Kotlinand Java code, the source code is in two different directories (src/main/kotlin and src/main/java), and the compiled classes as well (build/classes/java and build/classes/kotlin). QuarkusTestExtension only uses build/classes/kotlin, which explains the problem.

Regarding the use case, it may seem exotic, but for Kotlin, I don't think it is:

  • Gradle seems rather popular in the Kotlin world, so I'd expect it to be the default choice for Kotlin projects? At the very least, Kotlin projects generated by Intellij IDEA are based on Gradle.
  • That the main annotation processor for Kotlin (kapt) produces Java code by default. So if you write only Kotlin code in a Quarkus application, and you need to generate beans or otherwise annotated classes through an annotation processor, you will be affected.
  • Even if you don't use annotation processors, Java interop, and the ability to mix Java and Kotlin code in the same project, is apparently an important feature of Kotlin.

On example of annotation processors that produce CDI beans: MapStruct, frequently used to map between DTO and entities. It generates "mapper" classes that can be injected using CDI.

@yrodiere yrodiere added the kind/bug Something isn't working label Nov 6, 2020
@quarkusbot
Copy link

/cc @evanchooly
/cc @quarkusio/devtools, @glefloch

@glefloch
Copy link
Member

glefloch commented Nov 6, 2020

Thanks for reporting this @yrodiere. You are right, as maven output all classes into the target/classes directory, there is no problem.
I have a working fix for gradle. I just need to add a test.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants