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