Search code examples
javajava-11java-17java-module

Is there an alternative to --add-opens command line parameters for just ported applications to a newer Java?


Is there an alternative to --add-opens command line parameters for just ported applications to a newer Java?

To make our venerable monolithic application make to run on Java 11 and Java 17, I had to add several --add-opens. I would like to keep the application non-modular/monolithic for the time being.

To make it run I have to add a rather lengthy list of --add-opens to our already long list of VM parameters. Example:

--add-opens java.base/java.lang=ALL-UNNAMED
--add-opens java.base/java.util=ALL-UNNAMED
--add-opens java.base/java.net=ALL-UNNAMED
--add-opens java.base/java.io=ALL-UNNAMED
--add-opens java.base/java.text=ALL-UNNAMED
--add-opens java.base/java.time=ALL-UNNAMED
--add-opens java.desktop/java.awt=ALL-UNNAMED
--add-opens java.desktop/java.swing=ALL-UNNAMED
--add-opens java.desktop/java.swing.table=ALL-UNNAMED
--add-opens java.desktop/java.swing.plaf.basic=ALL-UNNAMED
...

And the list goes on and on. It works, but it's unwieldy. We already have many command line parameters, VM and program arguments. I'm afraid we can hit CLI limits at some point somewhere. All those arguments also make it more fiddly to start the app from an IDE.

Is there an alternative?
I there something like module-info.java file to declare openings globally, for non-modular project? A file I can keep inside project, inside produced JAR?

UPDATE 2024-05-18
I should not feel too bad about our project. For comparison, this is how many add-opes the latest IntelliJ 2024.1 has:

/home/espinosa/bin/idea-IC-241.15989.150/jbr/bin/java
 -classpath ......
....
 -Didea.platform.prefix=Idea
 -Dsplash=true
 -Daether.connector.resumeDownloads=false
 --add-opens=java.base/java.io=ALL-UNNAMED
 --add-opens=java.base/java.lang=ALL-UNNAMED
 --add-opens=java.base/java.lang.ref=ALL-UNNAMED
 --add-opens=java.base/java.lang.reflect=ALL-UNNAMED
 --add-opens=java.base/java.net=ALL-UNNAMED
 --add-opens=java.base/java.nio=ALL-UNNAMED
 --add-opens=java.base/java.nio.charset=ALL-UNNAMED
 --add-opens=java.base/java.text=ALL-UNNAMED
 --add-opens=java.base/java.time=ALL-UNNAMED
 --add-opens=java.base/java.util=ALL-UNNAMED
 --add-opens=java.base/java.util.concurrent=ALL-UNNAMED
 --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED
 --add-opens=java.base/java.util.concurrent.locks=ALL-UNNAMED
 --add-opens=java.base/jdk.internal.vm=ALL-UNNAMED
 --add-opens=java.base/sun.nio.ch=ALL-UNNAMED
 --add-opens=java.base/sun.nio.fs=ALL-UNNAMED
 --add-opens=java.base/sun.security.ssl=ALL-UNNAMED
 --add-opens=java.base/sun.security.util=ALL-UNNAMED
 --add-opens=java.base/sun.net.dns=ALL-UNNAMED
 --add-opens=java.desktop/com.sun.java.swing.plaf.gtk=ALL-UNNAMED
 --add-opens=java.desktop/java.awt=ALL-UNNAMED
 --add-opens=java.desktop/java.awt.dnd.peer=ALL-UNNAMED
 --add-opens=java.desktop/java.awt.event=ALL-UNNAMED
 --add-opens=java.desktop/java.awt.image=ALL-UNNAMED
 --add-opens=java.desktop/java.awt.peer=ALL-UNNAMED
 --add-opens=java.desktop/java.awt.font=ALL-UNNAMED
 --add-opens=java.desktop/javax.swing=ALL-UNNAMED
 --add-opens=java.desktop/javax.swing.plaf.basic=ALL-UNNAMED
 --add-opens=java.desktop/javax.swing.text=ALL-UNNAMED
 --add-opens=java.desktop/javax.swing.text.html=ALL-UNNAMED
 --add-opens=java.desktop/sun.awt.X11=ALL-UNNAMED
 --add-opens=java.desktop/sun.awt.datatransfer=ALL-UNNAMED
 --add-opens=java.desktop/sun.awt.image=ALL-UNNAMED
 --add-opens=java.desktop/sun.awt=ALL-UNNAMED
 --add-opens=java.desktop/sun.font=ALL-UNNAMED
 --add-opens=java.desktop/sun.java2d=ALL-UNNAMED
 --add-opens=java.desktop/sun.swing=ALL-UNNAMED
 --add-opens=java.desktop/com.sun.java.swing=ALL-UNNAMED
 --add-opens=jdk.attach/sun.tools.attach=ALL-UNNAMED
 --add-opens=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED
 --add-opens=jdk.internal.jvmstat/sun.jvmstat.monitor=ALL-UNNAMED
 --add-opens=jdk.jdi/com.sun.tools.jdi=ALL-UNNAMED com.intellij.idea.Main

This is from the Linux version, the Windows version does the same, it only hides that better; they use a binary exe wrapper there, you have to check the logs.


Solution

  • If you are producing an executable jar file, you could use the Add-Opens manifest attribute. When running the app using java -jar <jar file> that should avoid having to pass all the flags. See: https://openjdk.org/jeps/261#Packaging:-Modular-JAR-files

    The java executable also supports expanding command line flags from a file using @:

    java @options org.main.Main
    

    The lines in the options file will be 'expanded' into the command line. So, you could put the needed options into a file that you add to the project, and then use it with @. I'm not sure if your IDE will support that though (though, arguably you could also check your IDE run configuration into the project).

    In general though, you should try to reduce the reflective access to JDK internals, so that you don't need these flags in the first place. This will also give you better portability between JDK versions.