java-migration
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseJava 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 → LTSJava 8 (LTS) → Java 11 (LTS) → Java 17 (LTS) → Java 21 (LTS) → Java 25 (LTS)
│ │ │ │ │
└──────────────┴───────────────┴──────────────┴───────────────┘
始终采用LTS版本间的迁移Quick Reference: What Breaks
快速参考:哪些内容会受影响
| From → To | Major Breaking Changes |
|---|---|
| 8 → 11 | Removed |
| 11 → 17 | Sealed classes (preview→final), strong encapsulation |
| 17 → 21 | Pattern matching changes, |
| 21 → 25 | Security Manager removed, Unsafe methods removed, 32-bit dropped |
| 版本跨度 | 主要破坏性变更 |
|---|---|
| 8 → 11 | 移除 |
| 11 → 17 | 密封类(预览版→正式版)、强封装机制 |
| 17 → 21 | 模式匹配变更、 |
| 21 → 25 | 移除Security Manager、移除Unsafe方法、不再支持32位平台 |
Migration Workflow
迁移流程
Step 1: Assess Current State
步骤1:评估当前状态
bash
undefinedbash
undefinedCheck 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/
undefinedgrep -r "sun." --include=".java" src/
grep -r "javax.xml.bind" --include=".java" src/
undefinedStep 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 -50Step 4: Run Tests
步骤4:运行测试
bash
mvn testbash
mvn testStep 5: Check Runtime Warnings
步骤5:检查运行时警告
bash
undefinedbash
undefinedRun 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
| Removed | Replacement |
|---|---|
| Add dependency: |
| Add dependency: |
| Add dependency: |
| No replacement (rarely used) |
| Add dependency: |
| Use |
| Use |
| 已移除API | 替代方案 |
|---|---|
| 添加依赖: |
| 添加依赖: |
| 添加依赖: |
| 无替代方案(极少使用) |
| 添加依赖: |
| 使用 |
| 尽可能使用 |
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-UNNAMEDMaven 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-UNNAMEDMaven 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
破坏性变更
| Change | Impact |
|---|---|
| Strong encapsulation | |
| Sealed classes (final) | If you used preview features |
| Pattern matching instanceof | Preview → final syntax change |
| 变更内容 | 影响 |
|---|---|
| 强封装机制 | |
| 密封类(正式版) | 若使用过预览版特性需调整 |
| 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 nulljava
// 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() → 会明确指出哪个部分为nullJava 17 → 21 Migration
Java 17 → 21 迁移
Breaking Changes
破坏性变更
| Change | Impact |
|---|---|
| Pattern matching switch (final) | Minor syntax differences from preview |
| Replace with |
| UTF-8 by default | May affect file reading if assumed platform encoding |
| 变更内容 | 影响 |
|---|---|
| Switch模式匹配(正式版) | 与预览版存在细微语法差异 |
| 替换为 |
| 默认使用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
破坏性变更
| Change | Impact |
|---|---|
| Security Manager removed | Applications relying on it need alternative security approaches |
| Use |
| 32-bit platforms dropped | No more x86-32 support |
| Record pattern variables final | Cannot reassign pattern variables in switch |
| Must provide non-null default |
| Dynamic agents restricted | Requires |
| 变更内容 | 影响 |
|---|---|
| 移除Security Manager | 依赖该组件的应用需采用其他安全方案 |
移除 | 替换为 |
| 不再支持32位平台 | 取消x86-32架构支持 |
| Record模式变量为final | 无法在switch中重新赋值模式变量 |
禁用 | 必须提供非空默认值 |
| 限制动态代理 | 需要添加 |
Check for Unsafe Usage
检查Unsafe的使用情况
bash
undefinedbash
undefinedFind 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/
undefinedgrep -rn "SecurityManager|System.getSecurityManager" --include="*.java" src/
undefinedNew 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 modulejava
// 作用域值(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
undefinedbash
undefinedAutomated 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
-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
-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
undefinedFind all javax imports that need migration
查找所有需要迁移的javax导入
grep -r "import javax." --include="*.java" src/ | grep -v "javax.crypto" | grep -v "javax.net"
**Automated migration:**
```bashgrep -r "import javax." --include="*.java" src/ | grep -v "javax.crypto" | grep -v "javax.net"
**自动化迁移:**
```bashUse 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
-Drewrite.recipeArtifactCoordinates=org.openrewrite.recipe:rewrite-spring:LATEST
-Drewrite.activeRecipes=org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_0
undefinedmvn -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
-Drewrite.recipeArtifactCoordinates=org.openrewrite.recipe:rewrite-spring:LATEST
-Drewrite.activeRecipes=org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_0
undefinedDependency 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 accessibleFix:
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-UNNAMEDIssue: JAXB ClassNotFoundException
问题:JAXB类未找到
Symptom:
java.lang.ClassNotFoundException: javax.xml.bind.JAXBContextFix: 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.*imports (if Spring Boot 3)jakarta.* - Add flags if needed
--add-opens - Update Lombok, Mockito, other tools
- Fix compilation errors
- Run tests
- 更新构建工具配置
- 添加缺失的Jakarta依赖
- 替换→
javax.*导入(若升级Spring Boot 3)jakarta.* - 按需添加参数
--add-opens - 更新Lombok、Mockito等工具版本
- 修复编译错误
- 运行测试
Post-Migration
迁移后
- Remove unnecessary flags
--add-opens - Adopt new language features (records, var, etc.)
- Update CI/CD pipeline
- Document changes made
- 移除不必要的参数
--add-opens - 采用新语言特性(records、var等)
- 更新CI/CD流水线
- 记录所做变更
Quick Commands
常用命令
bash
undefinedbash
undefinedCheck 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
-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
-Drewrite.recipeArtifactCoordinates=org.openrewrite.recipe:rewrite-spring:LATEST
-Drewrite.activeRecipes=org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_0
---Version Compatibility Matrix
版本兼容性矩阵
| Framework | Java 8 | Java 11 | Java 17 | Java 21 | Java 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 8 | Java 11 | Java 17 | Java 21 | Java 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月