quarkus: Unable to extract REST API into shared gradle module
Describe the bug
We have a Quarkus service that exposes a rest api and one that consumes the same rest api. Both are submodules of a multi-module gradle project and we use Kotlin.
Since we don’t want to write the DTOs and the rest api interface twice, we added another gradle module where we extracted the rest client interface and the dtos to. Both Quarkus services now have this library module as a dependency. In the service that provides the API, I have now implemented this interface to provide the implementation for the api.
The library code looks like this (also checkout the reproducer below):
@Path("/books")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
interface BookApi {
@GET
fun getBooks(): List<BookDto>
}
data class BookDto(val name: String)
and the server code looks like this
class BookResource : BooksApi {
override fun getBooks(): List<BookDto> {
return listOf(BookDto("Abc"))
}
}
Unfortunately, when you start the server, no resource is loaded and no endpoint is available.
We also tried adding @ApplicationScoped to the BookResource. Then we get warnings:
2023-01-30 18:01:41,134 WARN [io.qua.arc.pro.BeanArchives] (build-39) Failed to index com.arconsis.books.BooksApi: Class does not exist in ClassLoader QuarkusClassLoader:Deployment Class Loader: DEV@68567e20
2023-01-30 18:01:43,021 WARN [io.qua.arc.ComponentsProvider] (Quarkus Main Thread) Unable to load removed bean type [com.arconsis.planconfig.resource.BookResource]: java.lang.NoClassDefFoundError: com/arconsis/books/BooksApi
So it seems the interface is somehow not included in the code. Also the endpoint is not available.
When we add the @Path("/books") annotation to the BooksResource, we get an error like this:
2023-01-30 18:10:12,035 INFO [io.qua.oid.dep.dev.OidcDevConsoleProcessor] (build-17) OIDC Dev Console: discovering the provider metadata at http://localhost:13501/realms/master/.well-known/openid-configuration
2023-01-30 18:10:12,240 WARN [io.qua.arc.pro.BeanArchives] (build-31) Failed to index com.arconsis.books.BooksApi: Class does not exist in ClassLoader QuarkusClassLoader:Deployment Class Loader: DEV@17a7f733
2023-01-30 18:10:12,272 INFO [io.qua.arc.pro.IndexClassLookupUtils] (build-31) Class for name: com.arconsis.books.BooksApi was not found in Jandex index. Please ensure the class is part of the index.
2023-01-30 18:10:14,061 ERROR [io.qua.run.boo.StartupActionImpl] (Quarkus Main Thread) Error running Quarkus: java.lang.reflect.InvocationTargetException
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.runner.bootstrap.StartupActionImpl$1.run(StartupActionImpl.java:104)
at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.ExceptionInInitializerError
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
at io.quarkus.runtime.Quarkus.run(Quarkus.java:70)
at io.quarkus.runtime.Quarkus.run(Quarkus.java:44)
at io.quarkus.runtime.Quarkus.run(Quarkus.java:124)
at io.quarkus.runner.GeneratedMain.main(Unknown Source)
... 6 more
Caused by: java.lang.RuntimeException: Failed to start quarkus
at io.quarkus.runner.ApplicationImpl.<clinit>(Unknown Source)
... 15 more
Caused by: java.lang.NoClassDefFoundError: com/arconsis/books/BooksApi
at java.base/java.lang.ClassLoader.defineClass1(Native Method)
at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1012)
at io.quarkus.bootstrap.classloading.QuarkusClassLoader.loadClass(QuarkusClassLoader.java:497)
at io.quarkus.bootstrap.classloading.QuarkusClassLoader.loadClass(QuarkusClassLoader.java:457)
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:467)
at com.arconsis.books.BookResource_Bean.<init>(Unknown Source)
at io.quarkus.arc.setup.Default_ComponentsProvider.addBeans3(Unknown Source)
at io.quarkus.arc.setup.Default_ComponentsProvider.getComponents(Unknown Source)
at io.quarkus.arc.impl.ArcContainerImpl.<init>(ArcContainerImpl.java:117)
at io.quarkus.arc.Arc.initialize(Arc.java:31)
at io.quarkus.arc.runtime.ArcRecorder.initContainer(ArcRecorder.java:43)
at io.quarkus.deployment.steps.ArcProcessor$generateResources844392269.deploy_0(Unknown Source)
at io.quarkus.deployment.steps.ArcProcessor$generateResources844392269.deploy(Unknown Source)
... 16 more
Caused by: java.lang.ClassNotFoundException: com.arconsis.books.BooksApi
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:520)
at io.quarkus.bootstrap.classloading.QuarkusClassLoader.loadClass(QuarkusClassLoader.java:507)
at io.quarkus.bootstrap.classloading.QuarkusClassLoader.loadClass(QuarkusClassLoader.java:457)
at io.quarkus.bootstrap.classloading.QuarkusClassLoader.loadClass(QuarkusClassLoader.java:507)
at io.quarkus.bootstrap.classloading.QuarkusClassLoader.loadClass(QuarkusClassLoader.java:457)
... 30 more
2023-01-30 18:10:14,064 INFO [io.qua.dep.dev.IsolatedDevModeMain] (main) Attempting to start live reload endpoint to recover from previous Quarkus startup failure
Furthermore, if we create a client like the following:
@RegisterRestClient(configKey = "books-api")
interface BooksClient : BooksApi
it is also not loaded when the application starts.
Expected behavior
We should be able to extract the DTOs and API definiton to a different module to reuse it in resources and clients in multiple projects in order to not duplicate the code.
Actual behavior
The interface of the API seems to get lost and the setup is not working.
How to Reproduce?
Reproducer: 2023-01-31-gradle-multimodule.zip
- Download & Unpack the reproducer
- Start the server by running
./gradlew :server:quarkusDev - The should be an endpoint http://localhost:8080/books. But it is not there. You can test and see the behavior described above.
- Start the client by running
./gradlew :client:quarkusDev - You can test and see the behavior described above.
Output of uname -a or ver
No response
Output of java -version
kotlin 1.7.22
GraalVM version (if different from Java)
No response
Quarkus version or git rev
Tested 2.16.0 and 2.15.3
Build tool (ie. output of mvnw --version or gradlew --version)
gradle
Additional information
This ticket is the result of this Zulip chat here: https://quarkusio.zulipchat.com/#narrow/stream/187030-users/topic/How.20to.20extract.20REST.20API.20into.20shared.20gradle.20module
About this issue
- Original URL
- State: open
- Created a year ago
- Comments: 16 (12 by maintainers)
I will do my best and try to look into it quickly.
Not really any progress on my side. I definitely miss time for now. I will do my best!
Ah, I meant it properly locates the
compileKotlintask in theclientproject, the dev mode still fails due to the issue in the library project.