java-migration

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Java Migration Skill

Java版本迁移指南

Step-by-step guide for upgrading Java projects between major versions.
Java项目跨大版本升级的分步指南。

When to Use

适用场景

  • User says "upgrade to Java 25" / "migrate from Java 8" / "update Java version"
  • Modernizing legacy projects
  • Spring Boot 2.x → 3.x → 4.x migration
  • Preparing for LTS version adoption
  • 用户提及“升级到Java 25” / “从Java 8迁移” / “更新Java版本”
  • 遗留项目现代化改造
  • Spring Boot 2.x → 3.x → 4.x迁移
  • 为采用LTS版本做准备

Migration Paths

迁移路径

Java 8 (LTS) → Java 11 (LTS) → Java 17 (LTS) → Java 21 (LTS) → Java 25 (LTS)
     │              │               │              │               │
     └──────────────┴───────────────┴──────────────┴───────────────┘
                         Always migrate LTS → LTS

Java 8 (LTS) → Java 11 (LTS) → Java 17 (LTS) → Java 21 (LTS) → Java 25 (LTS)
     │              │               │              │               │
     └──────────────┴───────────────┴──────────────┴───────────────┘
                         始终采用LTS版本间的迁移

Quick Reference: What Breaks

快速参考:哪些内容会受影响

From → ToMajor Breaking Changes
8 → 11Removed
javax.xml.bind
, module system, internal APIs
11 → 17Sealed classes (preview→final), strong encapsulation
17 → 21Pattern matching changes,
finalize()
deprecated for removal
21 → 25Security Manager removed, Unsafe methods removed, 32-bit dropped

版本跨度主要破坏性变更
8 → 11移除
javax.xml.bind
、模块系统、内部API
11 → 17密封类(预览版→正式版)、强封装机制
17 → 21模式匹配变更、
finalize()
标记为待移除
21 → 25移除Security Manager、移除Unsafe方法、不再支持32位平台

Migration Workflow

迁移流程

Step 1: Assess Current State

步骤1:评估当前状态

bash
undefined
bash
undefined

Check current Java version

检查当前Java版本

java -version
java -version

Check compiler target in Maven

检查Maven中的编译目标版本

grep -r "maven.compiler" pom.xml
grep -r "maven.compiler" pom.xml

Find usage of removed APIs

查找已移除API的使用情况

grep -r "sun." --include=".java" src/ grep -r "javax.xml.bind" --include=".java" src/
undefined
grep -r "sun." --include=".java" src/ grep -r "javax.xml.bind" --include=".java" src/
undefined

Step 2: Update Build Configuration

步骤2:更新构建配置

Maven:
xml
<properties>
    <java.version>21</java.version>
    <maven.compiler.source>${java.version}</maven.compiler.source>
    <maven.compiler.target>${java.version}</maven.compiler.target>
</properties>

<!-- Or with compiler plugin -->
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.12.1</version>
    <configuration>
        <release>21</release>
    </configuration>
</plugin>
Gradle:
groovy
java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(21)
    }
}
Maven:
xml
<properties>
    <java.version>21</java.version>
    <maven.compiler.source>${java.version}</maven.compiler.source>
    <maven.compiler.target>${java.version}</maven.compiler.target>
</properties>

<!-- 或使用编译器插件 -->
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.12.1</version>
    <configuration>
        <release>21</release>
    </configuration>
</plugin>
Gradle:
groovy
java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(21)
    }
}

Step 3: Fix Compilation Errors

步骤3:修复编译错误

Run compile and fix errors iteratively:
bash
mvn clean compile 2>&1 | head -50
运行编译并逐步修复错误:
bash
mvn clean compile 2>&1 | head -50

Step 4: Run Tests

步骤4:运行测试

bash
mvn test
bash
mvn test

Step 5: Check Runtime Warnings

步骤5:检查运行时警告

bash
undefined
bash
undefined

Run with illegal-access warnings

开启非法访问警告运行

java --illegal-access=warn -jar app.jar

---
java --illegal-access=warn -jar app.jar

---

Java 8 → 11 Migration

Java 8 → 11 迁移

Removed APIs

已移除的API

RemovedReplacement
javax.xml.bind
(JAXB)
Add dependency:
jakarta.xml.bind-api
+
jaxb-runtime
javax.activation
Add dependency:
jakarta.activation-api
javax.annotation
Add dependency:
jakarta.annotation-api
java.corba
No replacement (rarely used)
java.transaction
Add dependency:
jakarta.transaction-api
sun.misc.Base64*
Use
java.util.Base64
sun.misc.Unsafe
(partially)
Use
VarHandle
where possible
已移除API替代方案
javax.xml.bind
(JAXB)
添加依赖:
jakarta.xml.bind-api
+
jaxb-runtime
javax.activation
添加依赖:
jakarta.activation-api
javax.annotation
添加依赖:
jakarta.annotation-api
java.corba
无替代方案(极少使用)
java.transaction
添加依赖:
jakarta.transaction-api
sun.misc.Base64*
使用
java.util.Base64
sun.misc.Unsafe
(部分)
尽可能使用
VarHandle

Add Missing Dependencies (Maven)

添加缺失的依赖(Maven)

xml
<!-- JAXB (if needed) -->
<dependency>
    <groupId>jakarta.xml.bind</groupId>
    <artifactId>jakarta.xml.bind-api</artifactId>
    <version>4.0.1</version>
</dependency>
<dependency>
    <groupId>org.glassfish.jaxb</groupId>
    <artifactId>jaxb-runtime</artifactId>
    <version>4.0.4</version>
    <scope>runtime</scope>
</dependency>

<!-- Annotation API -->
<dependency>
    <groupId>jakarta.annotation</groupId>
    <artifactId>jakarta.annotation-api</artifactId>
    <version>2.1.1</version>
</dependency>
xml
<!-- JAXB(如果需要) -->
<dependency>
    <groupId>jakarta.xml.bind</groupId>
    <artifactId>jakarta.xml.bind-api</artifactId>
    <version>4.0.1</version>
</dependency>
<dependency>
    <groupId>org.glassfish.jaxb</groupId>
    <artifactId>jaxb-runtime</artifactId>
    <version>4.0.4</version>
    <scope>runtime</scope>
</dependency>

<!-- 注解API -->
<dependency>
    <groupId>jakarta.annotation</groupId>
    <artifactId>jakarta.annotation-api</artifactId>
    <version>2.1.1</version>
</dependency>

Module System Issues

模块系统问题

If using reflection on JDK internals, add JVM flags:
bash
--add-opens java.base/java.lang=ALL-UNNAMED
--add-opens java.base/java.util=ALL-UNNAMED
Maven Surefire:
xml
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <configuration>
        <argLine>
            --add-opens java.base/java.lang=ALL-UNNAMED
        </argLine>
    </configuration>
</plugin>
如果对JDK内部类使用反射,需添加JVM参数:
bash
--add-opens java.base/java.lang=ALL-UNNAMED
--add-opens java.base/java.util=ALL-UNNAMED
Maven Surefire插件:
xml
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <configuration>
        <argLine>
            --add-opens java.base/java.lang=ALL-UNNAMED
        </argLine>
    </configuration>
</plugin>

New Features to Adopt

值得采用的新特性

java
// var (local variable type inference)
var list = new ArrayList<String>();  // instead of ArrayList<String> list = ...

// String methods
"  hello  ".isBlank();      // true for whitespace-only
"  hello  ".strip();        // better trim() (Unicode-aware)
"line1\nline2".lines();     // Stream<String>
"ha".repeat(3);             // "hahaha"

// Collection factory methods (Java 9+)
List.of("a", "b", "c");     // immutable list
Set.of(1, 2, 3);            // immutable set
Map.of("k1", "v1");         // immutable map

// Optional improvements
optional.ifPresentOrElse(
    value -> process(value),
    () -> handleEmpty()
);

// HTTP Client (replaces HttpURLConnection)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.example.com"))
    .build();
HttpResponse<String> response = client.send(request,
    HttpResponse.BodyHandlers.ofString());

java
// var(局部变量类型推断)
var list = new ArrayList<String>();  // 替代ArrayList<String> list = ...

// String新方法
"  hello  ".isBlank();      // 仅含空白字符时返回true
"  hello  ".strip();        // 更优的trim()(支持Unicode)
"line1\nline2".lines();     // 返回Stream<String>
"ha".repeat(3);             // 输出"hahaha"

// 集合工厂方法(Java 9+)
List.of("a", "b", "c");     // 不可变列表
Set.of(1, 2, 3);            // 不可变集合
Map.of("k1", "v1");         // 不可变映射

// Optional增强
optional.ifPresentOrElse(
    value -> process(value),
    () -> handleEmpty()
);

// HTTP客户端(替代HttpURLConnection)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.example.com"))
    .build();
HttpResponse<String> response = client.send(request,
    HttpResponse.BodyHandlers.ofString());

Java 11 → 17 Migration

Java 11 → 17 迁移

Breaking Changes

破坏性变更

ChangeImpact
Strong encapsulation
--illegal-access
no longer works, must use explicit
--add-opens
Sealed classes (final)If you used preview features
Pattern matching instanceofPreview → final syntax change
变更内容影响
强封装机制
--illegal-access
参数失效,必须显式使用
--add-opens
密封类(正式版)若使用过预览版特性需调整
instanceof模式匹配预览版→正式版的语法变更

New Features to Adopt

值得采用的新特性

java
// Records (immutable data classes)
public record User(String name, String email) {}
// Auto-generates: constructor, getters, equals, hashCode, toString

// Sealed classes
public sealed class Shape permits Circle, Rectangle {}
public final class Circle extends Shape {}
public final class Rectangle extends Shape {}

// Pattern matching for instanceof
if (obj instanceof String s) {
    System.out.println(s.length());  // s already cast
}

// Switch expressions
String result = switch (day) {
    case MONDAY, FRIDAY -> "Work";
    case SATURDAY, SUNDAY -> "Rest";
    default -> "Midweek";
};

// Text blocks
String json = """
    {
        "name": "John",
        "age": 30
    }
    """;

// Helpful NullPointerException messages
// a.b.c.d() → tells exactly which part was null

java
// Records(不可变数据类)
public record User(String name, String email) {}
// 自动生成:构造方法、getter、equals、hashCode、toString

// 密封类
public sealed class Shape permits Circle, Rectangle {}
public final class Circle extends Shape {}
public final class Rectangle extends Shape {}

// instanceof模式匹配
if (obj instanceof String s) {
    System.out.println(s.length());  // s已自动强转
}

// Switch表达式
String result = switch (day) {
    case MONDAY, FRIDAY -> "工作日";
    case SATURDAY, SUNDAY -> "休息日";
    default -> "周中";
};

// 文本块
String json = """
    {
        "name": "John",
        "age": 30
    }
    """;

// 更友好的NullPointerException提示
// a.b.c.d() → 会明确指出哪个部分为null

Java 17 → 21 Migration

Java 17 → 21 迁移

Breaking Changes

破坏性变更

ChangeImpact
Pattern matching switch (final)Minor syntax differences from preview
finalize()
deprecated for removal
Replace with
Cleaner
or try-with-resources
UTF-8 by defaultMay affect file reading if assumed platform encoding
变更内容影响
Switch模式匹配(正式版)与预览版存在细微语法差异
finalize()
标记为待移除
替换为
Cleaner
或try-with-resources
默认使用UTF-8编码若之前依赖平台编码,可能影响文件读取

New Features to Adopt

值得采用的新特性

java
// Virtual Threads (Project Loom) - MAJOR
try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    executor.submit(() -> handleRequest());
}
// Or simply:
Thread.startVirtualThread(() -> doWork());

// Pattern matching in switch
String formatted = switch (obj) {
    case Integer i -> "int: " + i;
    case String s -> "string: " + s;
    case null -> "null value";
    default -> "unknown";
};

// Record patterns
record Point(int x, int y) {}
if (obj instanceof Point(int x, int y)) {
    System.out.println(x + ", " + y);
}

// Sequenced Collections
List<String> list = new ArrayList<>();
list.addFirst("first");    // new method
list.addLast("last");      // new method
list.reversed();           // reversed view

// String templates (preview in 21)
// May need --enable-preview

// Scoped Values (preview) - replace ThreadLocal
ScopedValue<User> CURRENT_USER = ScopedValue.newInstance();
ScopedValue.where(CURRENT_USER, user).run(() -> {
    // CURRENT_USER.get() available here
});

java
// 虚拟线程(Project Loom)- 重大特性
try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    executor.submit(() -> handleRequest());
}
// 或直接使用:
Thread.startVirtualThread(() -> doWork());

// Switch中的模式匹配
String formatted = switch (obj) {
    case Integer i -> "int: " + i;
    case String s -> "string: " + s;
    case null -> "空值";
    default -> "未知类型";
};

// Record模式
record Point(int x, int y) {}
if (obj instanceof Point(int x, int y)) {
    System.out.println(x + ", " + y);
}

// 有序集合
List<String> list = new ArrayList<>();
list.addFirst("first");    // 新方法
list.addLast("last");      // 新方法
list.reversed();           // 返回逆序视图

// 字符串模板(Java 21预览版)
// 需添加--enable-preview参数

// 作用域值(预览版)- 替代ThreadLocal
ScopedValue<User> CURRENT_USER = ScopedValue.newInstance();
ScopedValue.where(CURRENT_USER, user).run(() -> {
    // 此处可通过CURRENT_USER.get()获取值
});

Java 21 → 25 Migration

Java 21 → 25 迁移

Breaking Changes

破坏性变更

ChangeImpact
Security Manager removedApplications relying on it need alternative security approaches
sun.misc.Unsafe
methods removed
Use
VarHandle
or FFM API instead
32-bit platforms droppedNo more x86-32 support
Record pattern variables finalCannot reassign pattern variables in switch
ScopedValue.orElse(null)
disallowed
Must provide non-null default
Dynamic agents restrictedRequires
-XX:+EnableDynamicAgentLoading
flag
变更内容影响
移除Security Manager依赖该组件的应用需采用其他安全方案
移除
sun.misc.Unsafe
方法
替换为
VarHandle
或FFM API
不再支持32位平台取消x86-32架构支持
Record模式变量为final无法在switch中重新赋值模式变量
禁用
ScopedValue.orElse(null)
必须提供非空默认值
限制动态代理需要添加
-XX:+EnableDynamicAgentLoading
参数

Check for Unsafe Usage

检查Unsafe的使用情况

bash
undefined
bash
undefined

Find sun.misc.Unsafe usage

查找sun.misc.Unsafe的使用

grep -rn "sun.misc.Unsafe" --include="*.java" src/
grep -rn "sun.misc.Unsafe" --include="*.java" src/

Find Security Manager usage

查找Security Manager的使用

grep -rn "SecurityManager|System.getSecurityManager" --include="*.java" src/
undefined
grep -rn "SecurityManager|System.getSecurityManager" --include="*.java" src/
undefined

New Features to Adopt

值得采用的新特性

java
// Scoped Values (FINAL in Java 25) - replaces ThreadLocal
private static final ScopedValue<User> CURRENT_USER = ScopedValue.newInstance();

public void handleRequest(User user) {
    ScopedValue.where(CURRENT_USER, user).run(() -> {
        processRequest();  // CURRENT_USER.get() available here and in child threads
    });
}

// Structured Concurrency (Preview, redesigned API in 25)
try (StructuredTaskScope.ShutdownOnFailure scope = StructuredTaskScope.open()) {
    Subtask<User> userTask = scope.fork(() -> fetchUser(id));
    Subtask<Orders> ordersTask = scope.fork(() -> fetchOrders(id));

    scope.join();
    scope.throwIfFailed();

    return new Profile(userTask.get(), ordersTask.get());
}

// Stable Values (Preview) - lazy initialization made easy
private static final StableValue<ExpensiveService> SERVICE =
    StableValue.of(() -> new ExpensiveService());

public void useService() {
    SERVICE.get().doWork();  // Initialized on first access, cached thereafter
}

// Compact Object Headers - automatic, no code changes
// Objects now use 64-bit headers instead of 128-bit (less memory)

// Primitive Patterns in instanceof (Preview)
if (obj instanceof int i) {
    System.out.println("int value: " + i);
}

// Module Import Declarations (Preview)
import module java.sql;  // Import all public types from module
java
// 作用域值(Java 25正式版)- 替代ThreadLocal
private static final ScopedValue<User> CURRENT_USER = ScopedValue.newInstance();

public void handleRequest(User user) {
    ScopedValue.where(CURRENT_USER, user).run(() -> {
        processRequest();  // 此处及子线程中可通过CURRENT_USER.get()获取值
    });
}

// 结构化并发(预览版,Java 25中API重新设计)
try (StructuredTaskScope.ShutdownOnFailure scope = StructuredTaskScope.open()) {
    Subtask<User> userTask = scope.fork(() -> fetchUser(id));
    Subtask<Orders> ordersTask = scope.fork(() -> fetchOrders(id));

    scope.join();
    scope.throwIfFailed();

    return new Profile(userTask.get(), ordersTask.get());
}

// 稳定值(预览版)- 简化延迟初始化
private static final StableValue<ExpensiveService> SERVICE =
    StableValue.of(() -> new ExpensiveService());

public void useService() {
    SERVICE.get().doWork();  // 首次访问时初始化,后续缓存
}

// 紧凑对象头 - 自动生效,无需代码变更
// 对象头从16字节缩减为8字节(减少内存占用)

// instanceof中的基本类型模式(预览版)
if (obj instanceof int i) {
    System.out.println("int值: " + i);
}

// 模块导入声明(预览版)
import module java.sql;  // 导入模块中的所有公共类型

Performance Improvements (Automatic)

自动性能优化

Java 25 includes several automatic performance improvements:
  • Compact Object Headers: 8 bytes instead of 16 bytes per object
  • String.hashCode() constant folding: Faster Map lookups with String keys
  • AOT class loading: Faster startup with ahead-of-time cache
  • Generational Shenandoah GC: Better throughput, lower pauses
Java 25包含多项自动性能提升:
  • 紧凑对象头:每个对象占用8字节而非16字节
  • String.hashCode()常量折叠:使用String键的Map查找更快
  • AOT类加载:借助提前编译缓存加快启动速度
  • 分代Shenandoah GC:更高吞吐量、更低停顿

Migration with OpenRewrite

使用OpenRewrite进行自动化迁移

bash
undefined
bash
undefined

Automated Java 25 migration

自动迁移到Java 25

mvn -U org.openrewrite.maven:rewrite-maven-plugin:run
-Drewrite.recipeArtifactCoordinates=org.openrewrite.recipe:rewrite-migrate-java:LATEST
-Drewrite.activeRecipes=org.openrewrite.java.migrate.UpgradeToJava25

---
mvn -U org.openrewrite.maven:rewrite-maven-plugin:run
-Drewrite.recipeArtifactCoordinates=org.openrewrite.recipe:rewrite-migrate-java:LATEST
-Drewrite.activeRecipes=org.openrewrite.java.migrate.UpgradeToJava25

---

Spring Boot Migration

Spring Boot迁移

Spring Boot 2.x → 3.x

Spring Boot 2.x → 3.x

Requirements:
  • Java 17+ (mandatory)
  • Jakarta EE 9+ (javax.* → jakarta.*)
Package Renames:
java
// Before (Spring Boot 2.x)
import javax.persistence.*;
import javax.validation.*;
import javax.servlet.*;

// After (Spring Boot 3.x)
import jakarta.persistence.*;
import jakarta.validation.*;
import jakarta.servlet.*;
Find & Replace:
bash
undefined
要求:
  • Java 17+(强制要求)
  • Jakarta EE 9+(javax.* → jakarta.*)
包名重命名:
java
// 之前(Spring Boot 2.x)
import javax.persistence.*;
import javax.validation.*;
import javax.servlet.*;

// 之后(Spring Boot 3.x)
import jakarta.persistence.*;
import jakarta.validation.*;
import jakarta.servlet.*;
查找与替换:
bash
undefined

Find all javax imports that need migration

查找所有需要迁移的javax导入

grep -r "import javax." --include="*.java" src/ | grep -v "javax.crypto" | grep -v "javax.net"

**Automated migration:**
```bash
grep -r "import javax." --include="*.java" src/ | grep -v "javax.crypto" | grep -v "javax.net"

**自动化迁移:**
```bash

Use OpenRewrite

使用OpenRewrite

mvn -U org.openrewrite.maven:rewrite-maven-plugin:run
-Drewrite.recipeArtifactCoordinates=org.openrewrite.recipe:rewrite-spring:LATEST
-Drewrite.activeRecipes=org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_0
undefined
mvn -U org.openrewrite.maven:rewrite-maven-plugin:run
-Drewrite.recipeArtifactCoordinates=org.openrewrite.recipe:rewrite-spring:LATEST
-Drewrite.activeRecipes=org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_0
undefined

Dependency Updates (Spring Boot 3.x)

依赖更新(Spring Boot 3.x)

xml
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.2.2</version>
</parent>

<!-- Hibernate 6 (auto-included) -->
<!-- Spring Security 6 (auto-included) -->
xml
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.2.2</version>
</parent>

<!-- Hibernate 6(自动引入) -->
<!-- Spring Security 6(自动引入) -->

Hibernate 5 → 6 Changes

Hibernate 5 → 6 变更

java
// ID generation strategy changed
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)  // preferred
private Long id;

// Query changes
// Before: createQuery returns raw type
// After: createQuery requires type parameter

// Before
Query query = session.createQuery("from User");

// After
TypedQuery<User> query = session.createQuery("from User", User.class);

java
// ID生成策略变更
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)  // 推荐使用
private Long id;

// 查询变更
// 之前:createQuery返回原始类型
// 之后:createQuery需要指定类型参数

// 之前
Query query = session.createQuery("from User");

// 之后
TypedQuery<User> query = session.createQuery("from User", User.class);

Common Migration Issues

常见迁移问题

Issue: Reflection Access Denied

问题:反射访问被拒绝

Symptom:
java.lang.reflect.InaccessibleObjectException: Unable to make field accessible
Fix:
bash
--add-opens java.base/java.lang=ALL-UNNAMED
--add-opens java.base/java.lang.reflect=ALL-UNNAMED
症状:
java.lang.reflect.InaccessibleObjectException: Unable to make field accessible
解决方法:
bash
--add-opens java.base/java.lang=ALL-UNNAMED
--add-opens java.base/java.lang.reflect=ALL-UNNAMED

Issue: JAXB ClassNotFoundException

问题:JAXB类未找到

Symptom:
java.lang.ClassNotFoundException: javax.xml.bind.JAXBContext
Fix: Add JAXB dependencies (see Java 8→11 section)
症状:
java.lang.ClassNotFoundException: javax.xml.bind.JAXBContext
解决方法: 添加JAXB依赖(参考Java 8→11章节)

Issue: Lombok Not Working

问题:Lombok无法正常工作

Fix: Update Lombok to latest version:
xml
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.30</version>
</dependency>
解决方法: 更新Lombok至最新版本:
xml
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.30</version>
</dependency>

Issue: Test Failures with Mockito

问题:Mockito测试失败

Fix: Update Mockito:
xml
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>5.8.0</version>
    <scope>test</scope>
</dependency>

解决方法: 更新Mockito:
xml
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>5.8.0</version>
    <scope>test</scope>
</dependency>

Migration Checklist

迁移检查清单

Pre-Migration

迁移前

  • Document current Java version
  • List all dependencies and their versions
  • Identify usage of internal APIs (
    sun.*
    ,
    com.sun.*
    )
  • Check framework compatibility (Spring, Hibernate, etc.)
  • Backup / create branch
  • 记录当前Java版本
  • 列出所有依赖及其版本
  • 识别内部API的使用情况(
    sun.*
    com.sun.*
  • 检查框架兼容性(Spring、Hibernate等)
  • 备份代码/创建分支

During Migration

迁移中

  • Update build tool configuration
  • Add missing Jakarta dependencies
  • Fix
    javax.*
    jakarta.*
    imports (if Spring Boot 3)
  • Add
    --add-opens
    flags if needed
  • Update Lombok, Mockito, other tools
  • Fix compilation errors
  • Run tests
  • 更新构建工具配置
  • 添加缺失的Jakarta依赖
  • 替换
    javax.*
    jakarta.*
    导入(若升级Spring Boot 3)
  • 按需添加
    --add-opens
    参数
  • 更新Lombok、Mockito等工具版本
  • 修复编译错误
  • 运行测试

Post-Migration

迁移后

  • Remove unnecessary
    --add-opens
    flags
  • Adopt new language features (records, var, etc.)
  • Update CI/CD pipeline
  • Document changes made

  • 移除不必要的
    --add-opens
    参数
  • 采用新语言特性(records、var等)
  • 更新CI/CD流水线
  • 记录所做变更

Quick Commands

常用命令

bash
undefined
bash
undefined

Check Java version

检查Java版本

java -version
java -version

Find internal API usage

查找内部API的使用

grep -rn "sun.|com.sun." --include="*.java" src/
grep -rn "sun.|com.sun." --include="*.java" src/

Find javax imports (for Jakarta migration)

查找javax导入(用于Jakarta迁移)

grep -rn "import javax." --include="*.java" src/
grep -rn "import javax." --include="*.java" src/

Compile and show first errors

编译并显示前100个错误

mvn clean compile 2>&1 | head -100
mvn clean compile 2>&1 | head -100

Run with verbose module warnings

开启详细模块警告运行

java --illegal-access=debug -jar app.jar
java --illegal-access=debug -jar app.jar

OpenRewrite Spring Boot 3 migration

使用OpenRewrite迁移Spring Boot 3

mvn org.openrewrite.maven:rewrite-maven-plugin:run
-Drewrite.recipeArtifactCoordinates=org.openrewrite.recipe:rewrite-spring:LATEST
-Drewrite.activeRecipes=org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_0

---
mvn org.openrewrite.maven:rewrite-maven-plugin:run
-Drewrite.recipeArtifactCoordinates=org.openrewrite.recipe:rewrite-spring:LATEST
-Drewrite.activeRecipes=org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_0

---

Version Compatibility Matrix

版本兼容性矩阵

FrameworkJava 8Java 11Java 17Java 21Java 25
Spring Boot 2.7.x⚠️
Spring Boot 3.2.x
Spring Boot 3.4+
Hibernate 5.6⚠️
Hibernate 6.4+
JUnit 5.10+
Mockito 5+
Lombok 1.18.34+
LTS Support Timeline:
  • Java 21: Oracle free support until September 2028
  • Java 25: Oracle free support until September 2033
框架Java 8Java 11Java 17Java 21Java 25
Spring Boot 2.7.x⚠️
Spring Boot 3.2.x
Spring Boot 3.4+
Hibernate 5.6⚠️
Hibernate 6.4+
JUnit 5.10+
Mockito 5+
Lombok 1.18.34+
LTS支持时间线:
  • Java 21:Oracle免费支持至2028年9月
  • Java 25:Oracle免费支持至2033年9月