升级java17 springboot3 解决编译运行中的反射/使用JDK内部类导致模块报错问题

3,039 阅读1分钟

编译问题:

because module java.base does not export sun.reflect.generics.parser to unnamed module
对具体使用了java内部类的子包添加如下插件和参数,使其在编译期间暴露内部类

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-compiler-plugin</artifactId>
  <configuration>
    <compilerArgs>
      <arg>--add-exports</arg>
      <arg>java.base/sun.reflect.annotation=ALL-UNNAMED</arg>
      <arg>--add-exports</arg>
      <arg>java.base/sun.reflect.generics.visitor=ALL-UNNAMED</arg>
      <arg>--add-exports</arg>
      <arg>java.base/sun.reflect.generics.tree=ALL-UNNAMED</arg>
      <arg>--add-exports</arg>
      <arg>java.base/sun.reflect.generics.scope=ALL-UNNAMED</arg>
      <arg>--add-exports</arg>
      <arg>java.base/sun.reflect.generics.parser=ALL-UNNAMED</arg>
      <arg>--add-exports</arg>
      <arg>java.base/sun.reflect.generics.factory=ALL-UNNAMED</arg>
    </compilerArgs>
  </configuration>
</plugin>

exporting a package from system module java.base is not allowed with --release
github.com/spring-proj…
sprinboot3.1之后,添加了replace参数,而replace参数无法和--add-exports一起使用,所以还要在POM中添加:

 <properties>
        <maven.compiler.release></maven.compiler.release>
        <maven.compiler.source>${java.version}</maven.compiler.source>
        <maven.compiler.target>${java.version}</maven.compiler.target>
 </properties>

或者在maven-compiler-plugin中直接加入该三个参数

对于运行时反射/JDK内部类访问问题推荐使用如下方法避开 --add-opens

摆脱 --add-opens,使用 Unsafe 突破 Java17 强封装

或者继续使用如下方法:

IDEA 测试运行

IDEA运行测试时在设置——构建、执行、部署——构建工具——Maven——正在运行的测试中

会读取maven-surefire-pluginargLine参数,可以在在POM properties中添加:

 <properties>
        <argLine>
            -Dfile.encoding=UTF-8
            -Dsun.jnu.encoding=UTF-8
            --add-opens=java.base/java.util=ALL-UNNAMED
            --add-opens=java.base/java.lang=ALL-UNNAMED
            --add-opens=java.base/java.lang.invoke=ALL-UNNAMED
            --add-opens=java.base/java.lang.reflect=ALL-UNNAMED
            --add-opens=java.base/sun.reflect.annotation=ALL-UNNAMED
            --add-opens=java.base/sun.reflect.generics.visitor=ALL-UNNAMED
            --add-opens=java.base/sun.reflect.generics.tree=ALL-UNNAMED
            --add-opens=java.base/sun.reflect.generics.scope=ALL-UNNAMED
            --add-opens=java.base/sun.reflect.generics.parser=ALL-UNNAMED
            --add-opens=java.base/sun.reflect.generics.factory=ALL-UNNAMED
        </argLine>
 </properties>

或者添加

  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <configuration>
      <argLine>--add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED</argLine>
    </configuration>
  </plugin>

IDEA 运行

很遗憾没有发现通过项目内配置影响IDEA运行的简单方法,它甚至不遵循spring的启动配置,只能通过编辑IDEA运行配置配置运行参数,并保存为项目文件的方式复用

image.png

正式运行

在POM添加该插件使得修改MANIFES.MF的内容,使得springboot jar启动时能够添加-add-opens参数

<!--https://stackoverflow.com/questions/70196098/how-can-i-specify-add-opens-from-a-project-level-and-make-sure-it-is-taken-int-->
<!-- 修改 MANIFEST.MF 的插件 -->
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-jar-plugin</artifactId>
  <configuration>
    <archive>
      <manifestEntries>
        <!-- 通过在MANIFEST.MF文件中加入Add-Opens参数达到不带参jar启动与带参启动相同的效果  -->
        <Add-Opens>java.base/java.util java.base/java.lang java.base/java.lang.invoke java.base/java.lang.reflect java.base/sun.reflect.annotation java.base/sun.reflect.generics.visitor java.base/sun.reflect.generics.tree java.base/sun.reflect.generics.scope java.base/sun.reflect.generics.parser java.base/sun.reflect.generics.factory</Add-Opens>
      </manifestEntries>
    </archive>
  </configuration>
</plugin>

在POM提添加使其能够通过maven的 mvn spring-boot:run启动

<pluginManagement>
  <plugins>
    <plugin>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-maven-plugin</artifactId>
      <version>${spring-boot.version}</version>
      <configuration>
        <jvmArguments>${argLine}</jvmArguments>
      </configuration>
    </plugin>
  </plugins>
</pluginManagement>