EMT4J定制规则版:Java 8→17迁移兼容性检测与规则优化实战

简介: EMT4J是一款Java版本迁移兼容性检测工具,支持从Java 8→11和11→17的升级检查。通过预设规则扫描代码或JAR包,识别API废弃、模块系统、JVM参数等潜在不兼容问题,生成可视化报告,帮助开发者提前修复风险,确保应用平稳迁移。

EMT4J使用说明

EMT4J 是一个 Java 版本迁移兼容性检测工具,主要用于识别代码或依赖库在 Java 8→1111→17 升级过程中可能遇到的不兼容问题。它通过预定义规则(如 API 废弃、模块系统限制、JVM 参数变化等)扫描代码或 JAR 包,快速定位潜在风险,帮助开发者提前修复问题,确保迁移后应用正常运行。

image.png

  • 分类目录

image.png

使用说明

使用该工具检测之前,建议先把项目中的JDK版本、SpringBoot相关依赖及第三方依赖升级到对应的版本再使用该工具。如果直接使用该工具,会检测出很多低版本依赖的问题。

以下拿 https://github.com/adoptium/emt4j/tree/v0.8.0 版本来改造,因为 master 分支还是个 SNAPSHOT 版本,不是很稳定

1、使用插件的方式运行

  • 将以下配置添加到 pom.xml 文件(如果是多模块项目,则添加到根 pom.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>
  • 然后运行以下命令:
mvn process-test-classes
  • EMT4J 的报告将在项目目录中生成。

2、直接在项目目录下运行以下命令,无需修改 pom.xml 文件:

前提条件,需要使用对应目标的JDK版本来执行,如执行的是8-17,需要使用17来执行该命令

# 以默认配置运行,默认检测的版本范围是 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
# 通过 `-D` 指定输出文件和优先级
mvn process-test-classes org.eclipse.emt4j:emt4j-maven-plugin:0.8.0-rules-internal:check -DoutputFile=xxx-report.html -Dpriority=p1

规则修改

  • 规则文件在:emt4j\emt4j-common\src\main\resources\default\rule

image.png

  • 对应 xml 扫描规则配置:

image.png

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

image.png

去掉以下规则

1、从JDK 9,java version的schema发生了变化

从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输出不一致

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
年份后是空格 年份后是逗号
如:位置: 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不一致

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 标准下荷兰语默认使用星期日
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的规则。这些只是被弃用了,还没有被删掉,扫描出来的太多了,大多都是一些低版本的三方包,把对应的三方包升级下就行

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
目录
相关文章
|
6月前
|
安全 Java Linux
EMT4J——Java版本迁移检测工具
EMT4J是JDK版本升级检测工具,支持Java 8至17的迁移分析,扫描项目依赖并生成兼容性报告,帮助开发者提前发现API变更、废弃方法等问题,适用于Windows与Linux环境,提升升级效率。
425 4
|
Python
python自动生成含样式的Excel表格数据案例
python自动生成含样式的Excel表格数据案例
683 1
|
1月前
|
人工智能 自然语言处理 安全
Claude Code 全攻略:命令大全 + 实战工作流(建议收藏)
本文介绍了Claude Code终端AI助手的使用指南,主要内容包括:1)常用命令如版本查看、项目启动和更新;2)三种工作模式切换及界面说明;3)核心功能指令速查表,包含初始化、压缩对话、清除历史等操作;4)详细解析了/init、/help、/clear、/compact、/memory等关键命令的使用场景和语法。文章通过丰富的界面截图和场景示例,帮助开发者快速掌握如何通过命令行和交互界面高效使用Claude Code进行项目开发,特别强调了CLAUDE.md文件作为项目知识库的核心作用。
29820 66
Claude Code 全攻略:命令大全 + 实战工作流(建议收藏)
|
SQL 存储 大数据
Presto全网最佳学习资料汇总
Presto这几年在国内使用的越来越广泛,成为企业中必备的Adhoc/BI报表/轻量级ETL引擎,国内公司比如阿里巴巴、滴滴、头条、京东、小米都有几百数上千台的Presto集群,这主要还是由Presto优秀的特性使然(下文详细说明)。为了方便咱们中国的Presto使用者、爱好者学习使用Presto,我把Presto周边的资料做了一个搜集整理,方便大家查阅。
Presto全网最佳学习资料汇总
|
SQL 存储 关系型数据库
异构数据库、异构数据源、分布式数据库三者的辨析区别
异构数据库系统是相关的多个数据库系统的集合,可以实现数据的共享和透明访问,每个数据库系统在加入异构数据库系统之前本身就已经存在,拥有自己的DMBS。异构数据库的各个组成部分具有自身的自治性,实现数据共享的同时,每个数据库系统仍保有自己的应用特性、完整性控制和安全性控制。
|
开发工具 git C++
『实用教程』使用Visual Studio自带的Git管理回滚代码版本
使用Visual Studio自带的Git管理回滚代码版本
2785 0
『实用教程』使用Visual Studio自带的Git管理回滚代码版本
|
3月前
|
存储 人工智能 搜索推荐
AI Agent 记忆系统:从短期到长期的技术架构与实践
本文系统阐述AI Agent记忆系统的核心技术:短期记忆(会话级上下文管理)与长期记忆(跨会话知识沉淀)。涵盖上下文工程策略(压缩、卸载、隔离)、Record/Retrieve架构、主流框架(ADK/LangChain/AgentScope)实现差异,及Mem0等开源方案集成,并探讨MaaS、多模态记忆等前沿趋势。(239字)
AI Agent 记忆系统:从短期到长期的技术架构与实践
|
8月前
|
消息中间件 NoSQL Java
spring boot2升级boot3指南
本文介绍了如何将Spring Boot 2.x升级至Spring Boot 3.x,涵盖使用OpenRewrite自动化重构工具进行代码转换、依赖版本升级、配置属性调整及常见问题处理等内容,帮助开发者高效完成升级工作。
2731 7
|
6月前
|
机器学习/深度学习 人工智能 前端开发
终端里的 AI 编程助手:OpenCode 使用指南
OpenCode 是开源的终端 AI 编码助手,支持 Claude、GPT-4 等模型,可在命令行完成代码编写、Bug 修复、项目重构。提供原生终端界面和上下文感知能力,适合全栈开发者和终端用户使用。
51913 11