I've recently moved to Java 17 and with it came a couple restrictions requiring me to use --add-opens
because of one dependency when running my application.
I need to add this when the java -jar
command is ran. For now I found these solutions:
java --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/sun.util.calendar=ALL-UNNAMED -jar my.jar
pom.xml
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestEntries>
<Add-Opens>java.base/sun.util.calendar java.base/java.util</Add-Opens>
</manifestEntries>
</archive>
</configuration>
</plugin>
Both work fine for production apparently. However when running my app through IntelliJ, it's not picking up the options which is normal I guess. I have to set them in my run configuration (which is also committed to my project by the way) as VM arguments.
I'm looking for a way to ensure consistency automatically and not have to maintain in parallel two places where I declare my add-opens.
EDIT: I'm wondering if something is doable with argfiles. Like have an argfile inside my project that would be referenced in the jar and that could be referenced in an y run configuration. I haven't found much evidence yet but that's the path I'm currently pursuing.
EDIT 2: I added an addopens
file at the root of my project and can now reference this from the various points where I need it. For tests, I added this and it worked out of the box with IntelliJ tests AND maven tests together:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<!-- This adds the options contained in the addopens file to the test JVM arguments -->
<argLine>@addopens @{argLine}</argLine>
</configuration>
</plugin>
I also can ship that addopens
file in my docker to use in production. I still need to add to my Run configuration in IntteliJ the @addopens
manually.
I add here the current solution I'm using.
My context is that Spring-Boot generates the final executable through a org.springframework.boot:spring-boot-maven-plugin:repackage
goal, on Maven install phase.
The idea is to ask for an org.apache.maven.plugins:maven-jar-plugin:jar
execution before it, where Add-Exports
and Add-Opens
are added to the MANIFEST.MF
.
package
phaseid
of that execution should be <id>default-jar</id>
to override Spring-Boot execution of the jar plugin it already does.=ALL-UNNAMED
ending the --add-opens
or --add-exports
arguments in the command line shall disappear in the manifest entries. Else, they won't be taken into account at execution time.<!-- Modifier le MANIFEST.MF pour y ajouter les add-opens, add-exports -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<id>default-jar</id>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<archive>
<manifestEntries>
<Add-Exports>java.base/sun.nio.ch</Add-Exports>
<Add-Opens>java.base/java.util java.base/java.io java.base/java.nio java.base/java.lang java.base/java.lang.invoke java.base/sun.security.util java.base/sun.security.action</Add-Opens>
</manifestEntries>
</archive>
</configuration>
</execution>
</executions>
</plugin>
<!-- Générer l'application finale (un fat jar) -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<!-- Créer le fat jar exécutable de l'application -->
<execution>
<id>executable-jar</id>
<phase>install</phase>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<executable>true</executable>
</configuration>
</execution>
</executions>
</plugin>
This produces this MANIFEST.MF
:
Manifest-Version: 1.0
Created-By: Maven JAR Plugin 3.2.2
Build-Jdk-Spec: 17
Implementation-Title: Application-Backend métier : Services d'enrichiss
ement Open Data
Implementation-Version: 0.0.12-SNAPSHOT
Add-Exports: java.base/sun.nio.ch
Add-Opens: java.base/java.util java.base/java.io java.base/java.nio java
.base/java.lang java.base/java.lang.invoke java.base/sun.security.util
java.base/sun.security.action
Main-Class: org.springframework.boot.loader.JarLauncher
Start-Class: fr.ecoemploi.run.Application
Spring-Boot-Version: 2.7.9
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Spring-Boot-Classpath-Index: BOOT-INF/classpath.idx
Spring-Boot-Layers-Index: BOOT-INF/layers.idx
And I can now substitute
java --add-exports java.base/sun.nio.ch=ALL-UNNAMED \
--add-opens java.base/java.util=ALL-UNNAMED \
--add-opens java.base/java.io=ALL-UNNAMED \
--add-opens java.base/java.nio=ALL-UNNAMED \
--add-opens java.base/java.lang=ALL-UNNAMED \
--add-opens java.base/java.lang.invoke=ALL-UNNAMED \
--add-opens java.base/sun.security.util=ALL-UNNAMED \
--add-opens java.base/sun.security.action=ALL-UNNAMED \
-jar target/application-metier-et-gestion.jar
by a:
java -jar target/application-metier-et-gestion.jar
Which is far more convenient for distribution to end users, and will avoid them to change all their command lines, services to run java jars.
Follow steps: edit run/debug configuration -> add the below option in VM options:
--add-opens java.base/java.lang=ALL-UNNAMED
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With