How to build two distinct Quarkus runner JARs in a single Maven build (one for crypto-soft, one for crypto-hsm)
I'm using Quarkus in a multi-module Maven project. I need to produce two separate Quarkus runner JARs in a single reactor build:
quarkus-service-soft-runner.jar Uber-jar (Quarkus runner) Includes only quarkus-crypto-soft (not crypto-hsm)
quarkus-service-hsm-runner.jar Uber-jar (Quarkus runner) Includes only quarkus-crypto-hsm (not crypto-soft)
Context:
The parent POM runs quarkus-maven-plugin with goals build, generate-code, generate-code-tests.
<plugin>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<version>3.27.1.redhat-00001</version>
<extensions>true</extensions>
<executions>
<execution>
<goals>
<goal>build</goal>
<goal>generate-code</goal>
<goal>generate-code-tests</goal>
</goals>
</execution>
</executions>
</plugin>
The service module declares dependencies including acs-quarkus-crypto-soft and acs-quarkus-crypto-hsm.
I attempted two approaches:
-
Use two maven-assembly-plugin executions with jar-with-dependencies and dependencySet/excludes to create two fat JARs. This produced non-Quarkus runner jars which will not work .
-
Use two Quarkus plugin executions (profiles) in the service module with finalName and quarkus.package.type uber-jar, but I hit issues: Some configurations threw “Element quarkus.package.type is not allowed here” or “Element excludes is not allowed here”. The parent plugin’s codegen (generate-code) sometimes runs before the runner jars exist, causing failures.
This is how I am implementing the second approach and then through maven build I am activating one profile and in pom I am activating the other by default. Also I have tried activating the both through maven build
<profile>
<id>crypto-soft</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<dependencies>
<dependency>
<groupId>com.crypto</groupId>
<artifactId>crypto-soft</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>build</goal>
</goals>
<phase>package</phase>
<configuration>
<finalName>quarkus-service-soft-runner</finalName>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>crypto-hsm</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<dependencies>
<dependency>
<groupId>com.crypto</groupId>
<artifactId>crypto-hsm</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>build</goal>
</goals>
<phase>package</phase>
<configuration>
<finalName>quarkus-service-hsm-runner</finalName>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
When I am build my module it is giving me below error
Quarkus code generation phase has failed
And if I tried something like below directly in plugin without using profile in quarkus it is doing the build twice and creating jars:
<plugins>
<plugin>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<executions>
<execution>
<id>soft-war</id>
<phase>package</phase>
<goals>
<goal>build</goal>
</goals>
<configuration>
<finalName>quarkus-service-soft-runner</finalName>
</configuration>
</execution>
<execution>
<phase>package</phase>
<id>hsm-war</id>
<goals>
<goal>build</goal>
</goals>
<configuration>
<finalName>quarkus-service-hsm-runner</finalName>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
In JBOSS we are using below plugin to achieve the same and now we are doing migration to Quarkus :
<plugin>
<artifactId>maven-war-plugin</artifactId>
<executions>
<!-- First execution: HSM variant (default one) -->
<execution>
<id>hsm-war</id>
<phase>package</phase>
<goals>
<goal>war</goal>
</goals>
<configuration>
<!-- Exclude the soft jar from this WAR -->
<packagingExcludes>
**/acs-crypto-soft*.jar,
WEB-INF/lib/acs-crypto-soft*.jar
</packagingExcludes>
</configuration>
</execution>
<!-- Second execution: Soft variant -->
<execution>
<id>soft-war</id>
<phase>package</phase>
<goals>
<goal>war</goal>
</goals>
<configuration>
<!-- This classifier will create: xxx-soft.war -->
<classifier>soft</classifier>
<!-- Exclude the hsm related jars from this WAR -->
<packagingExcludes>
**/acs-crypto-hsm*.jar,
WEB-INF/lib/acs-crypto-hsm*.jar,
WEB-INF/lib/crypt2pay*.jar,
WEB-INF/lib/crys-hsm*.jar,
</packagingExcludes>
</configuration>
</execution>
</executions>
</plugin>
I want a single, clean, Quarkus-friendly solution that produces two runnable Quarkus Uber-Jars in one build, without requiring workarounds or changing the parent’s codegen flow.
/cc @quarkusio/devtools (maven)
can some one please check if they have insights on this? Let me know if you need anything from my end.
There is this trick https://quarkus.io/guides/maven-tooling#maven-multi-build Not very elegant, but it's tricky to build multiple apps with different dependencies from the same module.
I guess, another approach would be to create a common parent POM with all the common dependencies and the plugin configuration in the pluginManagement.
Then create two application modules inheriting from the common parent POM, adding application-specific dependencies and config.
I think i would recommend the parent and two modules approach. While we can assemble multiple applications from the same module with slightly different dependencies, the test classpath will include all the optional dependencies, which is something to be aware of.
I think i would recommend the parent and two modules approach. While we can assemble multiple applications from the same module with slightly different dependencies, the test classpath will include all the optional dependencies, which is something to be aware of.
Actually I need to do the two jar creation for all of my services and this is the first service which I have started so if i use this approach I need to create two modules for each of my services right?
There is this trick https://quarkus.io/guides/maven-tooling#maven-multi-build Not very elegant, but it's tricky to build multiple apps with different dependencies from the same module.
I guess, another approach would be to create a common parent POM with all the common dependencies and the plugin configuration in the
pluginManagement. Then create two application modules inheriting from the common parent POM, adding application-specific dependencies and config.
I tried with this approach as well but it is not filtering the jar. Both dependency is getting included in both war and Also 2 build one for each is executed. Can you please comment what is wrong with this approach.
<dependency>
<groupId>com.crypto</groupId>
<artifactId>quarkus-crypto-soft</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.crypto</groupId>
<artifactId>quarkus-crypto-hsm</artifactId>
<optional>true</optional>
</dependency>
<plugin>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<executions>
<execution>
<id>soft-war</id>
<phase>package</phase>
<goals>
<goal>build</goal>
</goals>
<configuration>
<properties>
<quarkus.package.jar.filter-optional-dependencies>true</quarkus.package.jar.filter-optional-dependencies>
<quarkus.package.jar.included-optional-dependencies>com.crypto:quarkus-crypto-soft::jar</quarkus.package.jar.included-optional-dependencies>
<quarkus.package.jar.type>uber-jar</quarkus.package.jar.type>
<quarkus.package.output-name>quarkus-service-soft-runner</quarkus.package.output-name>
</properties>
</configuration>
</execution>
<execution>
<phase>package</phase>
<id>hsm-war</id>
<goals>
<goal>build</goal>
</goals>
<configuration>
<properties>
<quarkus.package.jar.filter-optional-dependencies>true</quarkus.package.jar.filter-optional-dependencies>
<quarkus.package.jar.included-optional-dependencies>com.crypto:quarkus-crypto-hsm::jar</quarkus.package.jar.included-optional-dependencies>
<quarkus.package.jar.type>uber-jar</quarkus.package.jar.type>
<quarkus.package.output-name>quarkus-service-hsm-runner</quarkus.package.output-name>
</properties>
</configuration>
</execution>
</executions>
</plugin>
I'll need to look into this. We do have a test for this here https://github.com/quarkusio/quarkus/tree/main/integration-tests/maven/src/test/resources-filtered/projects/multi-build-mode
I'll need to look into this. We do have a test for this here https://github.com/quarkusio/quarkus/tree/main/integration-tests/maven/src/test/resources-filtered/projects/multi-build-mode
I checked this URL and the example I have tried is almost the same to the above URL Whenever you get time if you can just have a look and let me know if anything is missing in the example.
Thank you
@SnehBratJha could you also try adding an equivalent of
<quarkus.package.output-directory>fast-foo-quarkus-app</quarkus.package.output-directory>
to every execution?
@SnehBratJha could you also try adding an equivalent of
<quarkus.package.output-directory>fast-foo-quarkus-app</quarkus.package.output-directory>to every execution?
I tried this as well <quarkus.package.output-directory>post-quarkus</quarkus.package.output-directory>
Jar is created at this place but with same issue both the dependency are present. :(
Just to make sure, did you configure different output directories for each application?
Just to make sure, did you configure different output directories for each application?
Yes for both execution different output directory
<plugin>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<executions>
<execution>
<id>soft-war</id>
<phase>package</phase>
<goals>
<goal>build</goal>
<goal>generate-code</goal>
<goal>generate-code-tests</goal>
</goals>
<configuration>
<properties>
<quarkus.package.output-directory>postgresql-quarkus</quarkus.package.output-directory>
<quarkus.package.jar.filter-optional-dependencies>true</quarkus.package.jar.filter-optional-dependencies>
<quarkus.package.jar.included-optional-dependencies>com.worldline.acs:acs-quarkus-crypto-soft::jar</quarkus.package.jar.included-optional-dependencies>
<quarkus.package.output-name>acs-quarkus-authentication-service-soft-runner</quarkus.package.output-name>
</properties>
</configuration>
</execution>
<execution>
<phase>package</phase>
<id>hsm-war</id>
<goals>
<goal>build</goal>
</goals>
<configuration>
<properties>
<quarkus.package.output-directory>post-quarkus</quarkus.package.output-directory>
<quarkus.package.jar.filter-optional-dependencies>true</quarkus.package.jar.filter-optional-dependencies>
<quarkus.package.jar.included-optional-dependencies>com.worldline.acs:acs-quarkus-crypto-hsm::jar</quarkus.package.jar.included-optional-dependencies>
<quarkus.package.output-name>acs-quarkus-authentication-service-hsm-runner</quarkus.package.output-name>
</properties>
</configuration>
</execution>
</executions>
</plugin>
@SnehBratJha it seems to work for me. I guess I'd need a reproducer to investigate it further. Here is the configuration I used to test it.
<properties>
<compiler-plugin.version>3.14.1</compiler-plugin.version>
<maven.compiler.release>17</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
<quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
<quarkus.platform.version>3.30.3</quarkus.platform.version>
<skipITs>true</skipITs>
<surefire-plugin.version>3.5.4</surefire-plugin.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>${quarkus.platform.artifact-id}</artifactId>
<version>${quarkus.platform.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>commons-math</groupId>
<artifactId>commons-math</artifactId>
<version>1.2</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.21.0</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-rest</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<version>${quarkus.platform.version}</version>
<extensions>true</extensions>
<executions>
<execution>
<id>commons-math</id>
<goals>
<goal>build</goal>
</goals>
<configuration>
<properties>
<quarkus.package.output-directory>commons-math-app</quarkus.package.output-directory>
<quarkus.package.jar.filter-optional-dependencies>true</quarkus.package.jar.filter-optional-dependencies>
<quarkus.package.jar.included-optional-dependencies>commons-math:commons-math</quarkus.package.jar.included-optional-dependencies>
<quarkus.package.jar.type>uber-jar</quarkus.package.jar.type>
<quarkus.package.output-name>commons-math</quarkus.package.output-name>
</properties>
</configuration>
</execution>
<execution>
<id>commons-io</id>
<goals>
<goal>build</goal>
</goals>
<configuration>
<properties>
<quarkus.package.output-directory>commons-io-app</quarkus.package.output-directory>
<quarkus.package.jar.filter-optional-dependencies>true</quarkus.package.jar.filter-optional-dependencies>
<quarkus.package.jar.included-optional-dependencies>commons-io:commons-io</quarkus.package.jar.included-optional-dependencies>
<quarkus.package.jar.type>uber-jar</quarkus.package.jar.type>
<quarkus.package.output-name>commons-io</quarkus.package.output-name>
</properties>
</configuration>
</execution>
</executions>
</plugin>
In my case those two dependency crypto hsm and crypto soft is my internal project modules. Is it possible because of that it is not working because in your example commons io and commons math are external library?
No, seems to work for me.
Might be because the dependency which I wanted to include is my project internal modules(dependency) and the one which you have used in your example are the external library(dependency). It seems this solution is not working for me I will check more on this and will post the answer if I get. Meanwhile I will be using profile to create two different jars in two different build.
Might be because the dependency which I wanted to include is my project internal modules(dependency) and the one which you have used in your example are the external library(dependency).
No, I tried that. If you like you could create a reproducer for me to try.