You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Launch4j Maven插件打包Java客户端遇InaccessibleObjectException的咨询

Java客户端打包exe后的反射访问异常处理

问题背景

我是Java新手,开发了一个连接WildFly实例的客户端应用,在IDE中运行正常。用akathist-launch4j-maven-plugin和maven-shade-plugin打包成.exe文件(不想用安装程序所以没选jpackage)后,运行到调用java.util.AbstractMap()时抛出异常:

Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make protected java.util.AbstractMap() accessible: module java.base does not "opens java.util" to unnamed module @7e32c033

通过相关资料了解到,给JVM传--add-opens java.base/java.lang=ALL-UNNAMED可能解决问题,之前已经给shade插件加了排除过滤器处理签名jar的问题。现在想问两个问题:
a) 这种解决方式是否正确?
b) 若正确,如何修改POM文件添加该参数?

附原POM插件片段:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>3.4.1</version>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>shade</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <filters>
            <filter>
                <artifact>*:*</artifact>
                <excludes>
                    <exclude>META-INF/*.SF</exclude>
                    <exclude>META-INF/*.DSA</exclude>
                    <exclude>META-INF/*.RSA</exclude>
                </excludes>
            </filter>
        </filters>              
        <shadedArtifactAttached>true</shadedArtifactAttached>
        <shadedClassifierName>shaded</shadedClassifierName>
        <transformers>
            <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                <mainClass>de/cni/client/gui/pages/main/StartApplication</mainClass>                        
            </transformer>
        </transformers>
    </configuration>
</plugin>                                
<plugin>
    <groupId>com.akathist.maven.plugins.launch4j</groupId>
    <artifactId>launch4j-maven-plugin</artifactId>
    <version>2.4.1</version>
    <executions>
        <execution>
            <id>l4j-clui</id>
            <phase>package</phase>
            <goals>
                <goal>launch4j</goal>
            </goals>
            <configuration>
                <headerType>console</headerType>
                <jar>${project.build.directory}/${project.artifactId}-${project.version}-shaded.jar</jar>
                <outfile>${project.build.directory}/app-client.exe</outfile>
                <classPath>
                    <mainClass>[..]/client/gui/pages/main/StartApplication</mainClass>
                    <preCp>anything</preCp>
                </classPath>                                
              <jre>
                <path>${java.home}/bin</path>
                <minVersion>17.0.2</minVersion>
                <maxVersion></maxVersion>
                <requiresJdk>true</requiresJdk>
                <requires64Bit>true</requires64Bit>     
              </jre>
            </configuration>
        </execution>
    </executions>
</plugin>

补充:发布问题一小时后,我尝试在launch4j插件的<jre>节点中添加如下配置,程序能正常运行,但觉得有更优方案:

<opts>
    <opt>--add-opens java.base/java.util=ALL-UNNAMED</opt>
    <opt>--add-opens java.base/java.util.concurrent=ALL-UNNAMED</opt>
</opts>

解决方案

a) 这种解决方式是否正确?

正确且必要。原因如下:

  • Java 9及以后的模块系统(JPMS)默认限制了对JDK内部API的反射访问,目的是提升安全性和封装性。
  • 用shade插件打包后的jar属于「未命名模块」(unnamed module),而java.util.AbstractMap的protected构造方法被反射调用时,JPMS默认不允许未命名模块访问java.base模块的java.util包内部成员,因此抛出InaccessibleObjectException。
  • 你后来调整的--add-opens java.base/java.util=ALL-UNNAMED比最初看到的java.lang更精准,完全匹配错误信息中提到的包,是正确的参数。

b) 如何修改POM文件添加该参数?

最适合exe场景的方式就是你自己尝试的在launch4j插件的<jre>节点中添加<opts>配置,修改后的launch4j插件配置如下:

<plugin>
    <groupId>com.akathist.maven.plugins.launch4j</groupId>
    <artifactId>launch4j-maven-plugin</artifactId>
    <version>2.4.1</version>
    <executions>
        <execution>
            <id>l4j-clui</id>
            <phase>package</phase>
            <goals>
                <goal>launch4j</goal>
            </goals>
            <configuration>
                <headerType>console</headerType>
                <jar>${project.build.directory}/${project.artifactId}-${project.version}-shaded.jar</jar>
                <outfile>${project.build.directory}/app-client.exe</outfile>
                <classPath>
                    <mainClass>de/cni/client/gui/pages/main/StartApplication</mainClass>
                    <preCp>anything</preCp>
                </classPath>                                
              <jre>
                <path>${java.home}/bin</path>
                <minVersion>17.0.2</minVersion>
                <maxVersion></maxVersion>
                <requiresJdk>true</requiresJdk>
                <requires64Bit>true</requires64Bit>
                <!-- 添加JVM参数 -->
                <opts>
                    <opt>--add-opens java.base/java.util=ALL-UNNAMED</opt>
                    <opt>--add-opens java.base/java.util.concurrent=ALL-UNNAMED</opt>
                </opts>
              </jre>
            </configuration>
        </execution>
    </executions>
</plugin>

另外,如果你希望直接运行shaded jar时也带这些参数,可以在maven-shade-plugin的ManifestResourceTransformer中添加manifestEntries配置JVM参数,但对于exe场景,launch4j的方式更直接,因为exe会自动把这些参数传给启动的JVM。


优化建议

虽然当前方法能解决问题,但可以进一步排查根源:

  • 检查代码或依赖的WildFly客户端库是否在JPMS环境下没有适配,导致反射调用JDK内部API。
  • 尝试升级WildFly客户端依赖的版本,很多主流库在Java 9+已经做了JPMS适配,可能不需要手动添加--add-opens参数,这才是更优的长期解决方案。

内容的提问来源于stack exchange,提问作者derYak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 05:00:44