Quarkus and Maven multi-modules pitfalls
Building an application using Quarkus with Maven multi-modules requires a few tricks due to its native traits, let's try to avoid the main pitalls.
2024-12-01 at 8:53PM
# Maven Multi-modules pitfalls with Quarkus
Quarkus offers multiple
guides
to help out starting off on the right track. However it lacks an actual production-like folder structure and its setup. With Maven, I kind of like and got the habit of splitting my code in domain layer. It helps me reducing the cognitive load but also forces me to decouple my code.
# Code structure
Let's consider the following Maven module structure
<modules>
<module>component</module> <!-- main module (deployable) -->
<module>model</module> <!-- domain model layer -->
<module>service</module> <!-- service layer -->
<module>client</module> <!-- external communication (e.g. HTTP clients) -->
</modules>
# Pitfalls
When you develop on Quarkus you will soon learn that there are different
running
mode.
- quarkus:dev hot reload
- uber-jar (JVM)
- native (GraalVM)
If your application works flawlessly in dev unfortunately it doesn't guarantee that it will perform the same in native and it is similarly the same between mono and multi-modules.
# quarkus-maven-module
If
quarkus-maven-module
is defined on the parent pom.xml you may encounter errors at build time in
-Pnative
mode.
blog
├── model
│ ├── src
│ │ │── main
| └── pom.xml
| ...
└── pom.xml <!-- defines quarkus-maven-module plugin -->
quarkus-maven-module
is doing a whole lot of magic and if this plugin is applied on a module that is actually not pulling any quarkus modules it will
complain on the docs generation
.
[1/7] Initializing...
Error: Feature io.quarkus.runtime.graal.DisableLoggingFeature class not found on the classpath. Ensure that the name is correct and that the class is on the classpath.
com.oracle.svm.core.util.UserError$UserException: Feature io.quarkus.runtime.graal.DisableLoggingFeature class not found on the classpath. Ensure that the name is correct and that the class is on the classpath.
at org.graalvm.nativeimage.builder/com.oracle.svm.core.util.UserError.abort(UserError.java:73)
at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.FeatureHandler.registerFeatures(FeatureHandler.java:175)
at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.NativeImageGenerator.setupNativeImage(NativeImageGenerator.java:852)
at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.NativeImageGenerator.doRun(NativeImageGenerator.java:575)
at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.NativeImageGenerator.run(NativeImageGenerator.java:535)
at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.NativeImageGeneratorRunner.buildImage(NativeImageGeneratorRunner.java:403)
at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.NativeImageGeneratorRunner.build(NativeImageGeneratorRunner.java:580)
at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.NativeImageGeneratorRunner.main(NativeImageGeneratorRunner.java:128)
One way would be to pull
quarkus-maven-module
plugin from the parent to the concerned modules, another alternative would be to disable it where not required.
// parent > pom.xml
<properties>
...
<skip.quarkus.build>false</skip.quarkus.build>
...
</properties>
<plugin>
<groupId>io.quarkus.platform</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
...
<configuration>
<skip>${skip.quarkus.build}</skip>
</configuration>
</plugin>
// parent > model > pom.xml
<properties>
<skip.quarkus.build>true</skip.quarkus.build>
</properties>
# CDI in quarkus:dev
JRebel, spring-boot-devtools or the good old Play! Framework no one gets close to the flawless developer experience in Quarkus. Instantaneous hot reload, blazing start up speed and on top of that a seemless integration with its web-stack (Qute).
However, in multi-modules obviously the scanning becomes much more complex and the dependency injection might become hectic or not work at all.
To ease the
discovery of beans
a simple and not too costly solution is to introduce
jandex-maven-plugin
which will automagically generate an index for our beans that Quarkus can rely on.
<plugin>
<groupId>io.smallrye</groupId>
<artifactId>jandex-maven-plugin</artifactId>
<version>${jandex-plugin.version}</version>
<executions>
<execution>
<id>make-index</id>
<goals>
<goal>jandex</goal>
</goals>
</execution>
</executions>
</plugin>
# Want to have a look?
Want to have a better look at how things have been wired up on gdevxy.ch, take a glimpse on
Github
!