文章目录
- EMT4J使用说明
-
- 使用说明
- 规则修改
-
- 去掉以下规则
- 全部规则
-
- [8-11 规则:](#8-11 规则:)
-
- [1. JDK internal API (JDK内部API)](#1. JDK internal API (JDK内部API))
- [2. System classloader not instance of URLClassLoader](#2. System classloader not instance of URLClassLoader)
- [3. Arrays.asList().toArray return type changed](#3. Arrays.asList().toArray return type changed)
- [4. Get java version](#4. Get java version)
- [5. JPMS require add-exports](#5. JPMS require add-exports)
- [6. JPMS require add-opens](#6. JPMS require add-opens)
- [7. DateFormat incompatible with CLDR](#7. DateFormat incompatible with CLDR)
- [8. NumberFormat incompatible with CLDR](#8. NumberFormat incompatible with CLDR)
- [9. Calendar#getFirstDayOfWeek incompatible with CLDR](#getFirstDayOfWeek incompatible with CLDR)
- [10. java.util.regex.Pattern.compile flags check](#10. java.util.regex.Pattern.compile flags check)
- [11. JVM Option not compatible](#11. JVM Option not compatible)
- [12. Remove CORBA](#12. Remove CORBA)
- [13. Removed API](#13. Removed API)
- [14. Incompatible Jar](#14. Incompatible Jar)
- [15. Deprecated API](#15. Deprecated API)
- [11-17 规则:](#11-17 规则:)
-
- [1. Remove Nashorn](#1. Remove Nashorn)
- [2. Deprecate the Applet API for Removal](#2. Deprecate the Applet API for Removal)
- [3. Remove RMI Activation](#3. Remove RMI Activation)
- [4. Cannot get security class's field](#4. Cannot get security class's field)
- [5. JVM Option not compatible](#5. JVM Option not compatible)
- [6. Incompatible Jar](#6. Incompatible Jar)
- [7. Deprecated API](#7. Deprecated API)
EMT4J使用说明
EMT4J 是一个 Java 版本迁移兼容性检测工具,主要用于识别代码或依赖库在 Java 8→11 和 11→17 升级过程中可能遇到的不兼容问题。它通过预定义规则(如 API 废弃、模块系统限制、JVM 参数变化等)扫描代码或 JAR 包,快速定位潜在风险,帮助开发者提前修复问题,确保迁移后应用正常运行。
- 如下使用EMT4J扫描Jar包后的报告

- 分类目录

使用说明
使用该工具检测之前,建议先把项目中的JDK版本、SpringBoot相关依赖及第三方依赖升级到对应的版本再使用该工具。如果直接使用该工具,会检测出很多低版本依赖的问题。
以下拿 https://github.com/adoptium/emt4j/tree/v0.8.0 版本来改造,因为 master 分支还是个 SNAPSHOT 版本,不是很稳定
1、使用插件的方式运行
- 将以下配置添加到 pom.xml 文件(如果是多模块项目,则添加到根 pom.xml 文件):
xml
<build>
<plugins>
<plugin>
<groupId>org.eclipse.emt4j</groupId>
<artifactId>emt4j-maven-plugin</artifactId>
<version>0.8.0-rules-internal</version>
<executions>
<execution>
<phase>process-test-classes</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
<configuration>
<fromVersion>8</fromVersion>
<toVersion>17</toVersion>
<outputFile>report.html</outputFile>
<!--指定扫描的jar包-->
<files>target/xxx.jar</files>
</configuration>
</plugin>
</plugins>
</build>
- 然后运行以下命令:
bat
mvn process-test-classes
- EMT4J 的报告将在项目目录中生成。
2、直接在项目目录下运行以下命令,无需修改 pom.xml 文件:
前提条件,需要使用对应目标的JDK版本来执行,如执行的是8-17,需要使用17来执行该命令
bat
# 以默认配置运行,默认检测的版本范围是 JDK 8 → JDK 11
mvn process-test-classes org.eclipse.emt4j:emt4j-maven-plugin:0.8.0-rules-internal:check
# 指定JDK8-17范围
mvn process-test-classes org.eclipse.emt4j:emt4j-maven-plugin:0.8.0-rules-internal:check -DfromVersion=8 -DtoVersion=17
bat
# 通过 `-D` 指定输出文件和优先级
mvn process-test-classes org.eclipse.emt4j:emt4j-maven-plugin:0.8.0-rules-internal:check -DoutputFile=xxx-report.html -Dpriority=p1
- 详细的命令介绍和使用,请访问官网:https://github.com/adoptium/emt4j/tree/v0.8.0
规则修改
- 规则文件在:emt4j\emt4j-common\src\main\resources\default\rule

- 对应 xml 扫描规则配置:

- 如果去掉某个规则,直接注释对应的规则,有的规则不只是注释
<rule/>,还需要在对应的 cfg 文件中去掉包路径才不会扫描这个规则

去掉以下规则
1、从JDK 9,java version的schema发生了变化
bash
从JDK 9开始,Java版本号的格式发生了变化:
旧格式(JDK 8及之前):1.x(例如 1.8.0_381)
新格式(JDK 9+):MAJOR.MINOR.SECURITY.PATCH(例如 9.0.1, 11.0.4, 17)
如:
位置: file:/D:/emt4j-0.8.0/admin/xxx/target/xxx.jar!/BOOT-INF/lib/byte-buddy-1.10.22.jar!/net/bytebuddy/ClassFileVersion$VersionLocator$ForLegacyVm.class, 目标: net.bytebuddy.ClassFileVersion$VersionLocator$ForLegacyVm
位于 byte-buddy-1.10.22.jar
问题:这个类使用了旧的版本号格式(1.x)来判断Java版本,在JDK 9+上会失效。
例如:if (System.getProperty("java.version").startsWith("1.8"))
→ 在JDK 9+中,java.version 返回 9.0.1,所以条件永远不成立。
大多都是一些三方包会被扫描到
2、JDK 11中时区数据为CLDR,java.text.DateFormat的使用默认的style进行format时在JDK 8和JDK 11输出不一致
java
DateFormat df = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT);
System.out.println(df.format(new Date()));
JDK 8的输出: Jan 14, 2021 11:17:37 AM ; JDK 11的输出: Jan 14, 2021, 11:16:45 AM 区别在于年份后面,对于JDK 8是空格,但是对于JDK 11是逗号.
| JDK 8 | JDK 11 |
|---|---|
Jan 14, 2021 11:17:37 AM |
Jan 14, 2021, 11:16:45 AM |
| 年份后是空格 | 年份后是逗号 |
bash
如:位置: file:/D:/emt4j-0.8.0/admin/xxx/target/xxx.jar!/BOOT-INF/lib/liquibase-core-4.8.0.jar!/liquibase/dbdoc/HTMLWriter.class, 目标: liquibase.dbdoc.HTMLWriter
修复:
1. 增加 "-Djava.locale.providers=COMPAT"到java选项,从而将默认时区与JDK 8的时区数据保持兼容
2. 在使用DateFormat的时候避免使用默认的locale,而是显式指定Locale.
3、java.util.Calendar.getFirstDayOfWeek对于某些输入返回值在JDK 8和JDK 11不一致
java
Locale locale1 = Locale.forLanguageTag("nl");
System.out.println(new GregorianCalendar(locale1).getFirstDayOfWeek());
JDK 8的输出是2,但是JDK 11的输出是1
| JDK 8 | JDK 11 |
|---|---|
Locale.forLanguageTag("nl") → 星期一(返回 2) |
Locale.forLanguageTag("nl") → 星期日(返回 1) |
| 荷兰语默认使用星期一为一周起始 | CLDR 标准下荷兰语默认使用星期日 |
bash
JDK 11 采用 CLDR 时区数据,而 JDK 8 用旧版数据。Locale 未指定区域时,JDK 11 会按 CLDR 规则处理。
位置: file:/D:/emt4j-0.8.0/admin/xxx/target/xxx.jar!/BOOT-INF/lib/logback-core-1.2.13.jar!/ch/qos/logback/core/util/TimeUtil.class, 目标: ch.qos.logback.core.util.TimeUtil
修复:
1. 增加 "-Djava.locale.providers=COMPAT"到java选项,从而将默认时区与JDK 8的时区数据保持兼容
2. 在上面的场景中实例化Locale时,同时提供语言和区域,而不仅仅只提供语言
4、代码使用了JDK中标记为Deprecated的API
去掉了8-11、11-17中针对过期API的规则。这些只是被弃用了,还没有被删掉,扫描出来的太多了,大多都是一些低版本的三方包,把对应的三方包升级下就行
bash
Deprecated的API后续可能会删除,存在潜在不兼容的风险
修复:参考标记为deprecated的API javadoc的说明替换为相应建议的API
全部规则
8-11 规则:
1. JDK internal API (JDK内部API)
- 作用 :检测使用
sun.*等JDK内部API的情况 - 优先级:p4
- 说明:JDK 9+ 移除了内部API,使用会导致兼容性问题
2. System classloader not instance of URLClassLoader
- 作用 :检测系统类加载器是否仍是
URLClassLoader的子类 - 优先级:p1
- 说明 :JDK 9+ 系统类加载器不再是
URLClassLoader的子类
3. Arrays.asList().toArray return type changed
- 作用 :检测
Arrays.asList().toArray()返回类型变化 - 优先级:p1
- 说明 :JDK 9+ 中返回类型从
Object[]变为特定类型数组
4. Get java version
- 作用:检测获取Java版本的代码
- 优先级:p1
- 说明:JDK 9+ 中Java版本获取方式有变化
5. JPMS require add-exports
- 作用 :检测需要添加
add-exports的模块系统代码 - 优先级:p3
- 说明:JDK 9+ 引入模块系统,需要显式导出包
6. JPMS require add-opens
- 作用 :检测需要添加
add-opens的模块系统代码 - 优先级:p3
- 说明:JDK 9+ 引入模块系统,需要显式打开包
7. DateFormat incompatible with CLDR
- 作用 :检测
DateFormat在CLDR区域设置下的不兼容问题 - 优先级:p3
- 说明:JDK 11 使用 CLDR 时区数据,与 JDK 8 不兼容
8. NumberFormat incompatible with CLDR
- 作用 :检测
NumberFormat在CLDR区域设置下的不兼容问题 - 优先级:p3
- 说明:JDK 11 使用 CLDR 时区数据,与 JDK 8 不兼容
9. Calendar#getFirstDayOfWeek incompatible with CLDR
- 作用 :检测
Calendar#getFirstDayOfWeek在CLDR区域设置下的不兼容问题 - 优先级:p3
- 说明:JDK 11 使用 CLDR 时区数据,与 JDK 8 不兼容
10. java.util.regex.Pattern.compile flags check
- 作用 :检测
Pattern.compile()在JDK 11中添加的标志检查 - 优先级:p1
- 说明 :JDK 11 中
Pattern.compile()添加了标志检查
11. JVM Option not compatible
- 作用:检测不兼容的JVM选项
- 优先级:p1
- 说明:JDK 8 和 JDK 11 的JVM选项有变化
12. Remove CORBA
- 作用:检测使用CORBA的代码
- 优先级:p4
- 说明:CORBA在JDK 11中已被移除
13. Removed API
- 作用:检测已移除的API
- 优先级:p1
- 说明:JDK 11中移除了部分API
14. Incompatible Jar
- 作用:检测不兼容的JAR包
- 优先级:p1
- 说明:某些JAR包在JDK 11中不兼容
15. Deprecated API
- 作用:检测已废弃的API
- 优先级:p4
- 说明:JDK 11中废弃了部分API
11-17 规则:
1. Remove Nashorn
- 作用:检测使用Nashorn的代码
- 优先级:p3
- 说明:Nashorn在JDK 11中已移除,在JDK 17中完全移除
2. Deprecate the Applet API for Removal
- 作用:检测使用Applet API的代码
- 优先级:p4
- 说明:Applet API在JDK 11中已废弃,在JDK 17中将被移除
3. Remove RMI Activation
- 作用:检测使用RMI Activation的代码
- 优先级:p4
- 说明:RMI Activation在JDK 11中已被移除
4. Cannot get security class's field
- 作用:检测无法获取安全类字段的代码
- 优先级:p1
- 说明:JDK 11+ 中安全类的字段访问被限制
5. JVM Option not compatible
- 作用:检测不兼容的JVM选项
- 优先级:p1
- 说明:JDK 11 和 JDK 17 的JVM选项有变化
6. Incompatible Jar
- 作用:检测不兼容的JAR包
- 优先级:p1
- 说明:某些JAR包在JDK 17中不兼容
7. Deprecated API
- 作用:检测已废弃的API
- 优先级:p4
- 说明:JDK 17中废弃了部分API