帮助中心/最新通知

质量为本、客户为根、勇于拼搏、务实创新

< 返回文章列表

【开发相关】EMT4J定制规则版:Java 8→17迁移兼容性检测与规则优化实战

发表时间:2025-01-16 01:32:56 小编:主机乐-Yutio

目录

  • EMT4J使用说明
  •       使用说明
  •       规则修改
  •             去掉以下规则
  •             全部规则
  •                   8-11 规则:
  •                   标题 1. JDK internal API (JDK内部API)
  •                   2. System classloader not instance of URLClassLoader
  •                   3. Arrays.asList().toArray return type changed
  •                   4. Get java version
  •                   5. JPMS require add-exports
  •                   6. JPMS require add-opens
  •                   7. DateFormat incompatible with CLDR
  •                   8. NumberFormat incompatible with CLDR
  •                   9. Calendar#getFirstDayOfWeek incompatible with CLDR
  •                   10. java.util.regex.Pattern.compile flags check
  •                   11. JVM Option not compatible
  •                   12. Remove CORBA
  •                   13. Removed API
  •                   14. Incompatible Jar
  •                   15. Deprecated API
  •                   11-17 规则:
  •                   1. Remove Nashorn
  •                   2. Deprecate the Applet API for Removal
  •                   3. Remove RMI Activation
  •                   4. Cannot get security class's field
  •                   5. JVM Option not compatible
  •                   6. Incompatible Jar
  •                   7. Deprecated API
  • EMT4J使用说明

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

    EMT4J——Java版本迁移检测工具

    • 如下使用EMT4J扫描Jar包后的报告

    在这里插入图片描述

    • 分类目录

    在这里插入图片描述

    使用说明

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

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

    1、使用插件的方式运行

    • 将以下配置添加到 pom.xml 文件(如果是多模块项目,则添加到根 pom.xml 文件):

    展开
    代码语言: XML
    自动换行
    自动换行
    AI代码解释
    <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>
    
    • 然后运行以下命令:

    展开
    代码语言: TXT
    自动换行
    自动换行
    AI代码解释
    mvn process-test-classes
    
    • EMT4J 的报告将在项目目录中生成。

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

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

    展开
    代码语言: TXT
    自动换行
    自动换行
    AI代码解释
    # 以默认配置运行,默认检测的版本范围是 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
    
    展开
    代码语言: TXT
    自动换行
    自动换行
    AI代码解释
    # 通过 `-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

    在这里插入图片描述

    • 对应 xml 扫描规则配置:

    在这里插入图片描述

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

    在这里插入图片描述

    去掉以下规则

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

    展开
    代码语言: Bash
    自动换行
    自动换行
    AI代码解释
    从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
    自动换行
    自动换行
    AI代码解释
    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 8JDK 11
    Jan 14, 2021 11:17:37 AMJan 14, 2021, 11:16:45 AM
    年份后是空格年份后是逗号
    展开
    代码语言: Bash
    自动换行
    自动换行
    AI代码解释
    如:位置: 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
    自动换行
    自动换行
    AI代码解释
    Locale locale1 = Locale.forLanguageTag("nl"); 
    System.out.println(new GregorianCalendar(locale1).getFirstDayOfWeek()); 
    JDK 8的输出是2,但是JDK 11的输出是1
    
    JDK 8JDK 11
    Locale.forLanguageTag("nl") → 星期一(返回 2)Locale.forLanguageTag("nl") → 星期日(返回 1)
    荷兰语默认使用星期一为一周起始CLDR 标准下荷兰语默认使用星期日
    展开
    代码语言: Bash
    自动换行
    自动换行
    AI代码解释
    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
    自动换行
    自动换行
    AI代码解释
    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


    联系我们
    返回顶部