1. 概述
OpenRewrite 是一个用于 Java 和其他源代码重构的生态系统。在实际开发中,我们经常需要:
- 升级依赖到最新版本
- 应用安全补丁
- 淘汰废弃 API
- 技术栈迁移(例如 JUnit 迁移到 AssertJ)
OpenRewrite 能帮我们自动化处理这些任务。本文将基于 Spring PetClinic 项目,演示 OpenRewrite 的核心用法。
2. OpenRewrite 基础
2.1 常见重构类型
OpenRewrite 支持以下典型升级场景:
- ✅ 语言升级:Java 8 → Java 11+
- ✅ 框架升级:Spring Boot、Hibernate 等框架版本迁移
- ✅ 依赖迁移:处理破坏性更新的库版本升级
- ✅ 安全补丁:替换有漏洞的方法/库
- ✅ 自定义转换:业务逻辑或基础设施特定改造
2.2 核心机制:Recipe
OpenRewrite 的核心是通过 Recipe(配方) 自动重构代码。特点:
- 内置大量常用 Recipe
- 社区贡献广泛
- 用 Java 编写
- 通过 Maven/Gradle 插件集成
本文以 Maven 插件为例,Gradle 用户可参考官方文档。
2.3 Maven 插件配置
在 pom.xml
中添加插件:
<plugin>
<groupId>org.openrewrite.maven</groupId>
<artifactId>rewrite-maven-plugin</artifactId>
<version>5.8.1</version>
<configuration>
<activeRecipes>
<!-- 定义激活的 Recipe -->
</activeRecipes>
</configuration>
<dependencies>
<!-- Recipe 依赖 -->
</dependencies>
</plugin>
关键配置说明:
<activeRecipes>
:指定要执行的 Recipe<dependencies>
:Recipe 所需的额外依赖(如特定库版本)
2.4 准备演示项目
克隆 Spring PetClinic 并切换到旧版本分支:
git clone https://github.com/spring-projects/spring-petclinic.git
cd spring-petclinic
git switch -c 2.5.x 1.5.x
当前项目状态:
- Java 8
- Spring Boot 1.5
3. Spring Boot 升级实战
3.1 升级到 Spring Boot 2.7
配置 Recipe
<activeRecipes>
<recipe>org.openrewrite.java.spring.boot2.UpgradeSpringBoot_2_7</recipe>
</activeRecipes>
<dependencies>
<dependency>
<groupId>org.openrewrite.recipe</groupId>
<artifactId>rewrite-spring</artifactId>
<version>5.0.11</version>
</dependency>
</dependencies>
⚠️ 升级到 Spring Boot 3 需使用
UpgradeSpringBoot_3_0
Recipe
执行升级
mvn rewrite:run
典型变更
父 POM 版本更新
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> - <version>1.5.4.RELEASE</version> + <version>2.7.14</version> </parent>
构造器注入优化
-import org.springframework.beans.factory.annotation.Autowired; class VetController { private final VetRepository vets; - @Autowired public VetController(VetRepository clinicService) { this.vets = clinicService; } }
Spring Boot 2.x+ 单构造器可省略
@Autowired
连带依赖升级
- JUnit 4 → JUnit 5
- 其他托管依赖自动更新
4. JUnit 5 迁移指南
4.1 配置 Recipe
<activeRecipes>
<recipe>org.openrewrite.java.testing.junit5.JUnit5BestPractices</recipe>
</activeRecipes>
<dependencies>
<dependency>
<groupId>org.openrewrite.recipe</groupId>
<artifactId>rewrite-testing-frameworks</artifactId>
<version>2.0.12</version>
</dependency>
</dependencies>
4.2 执行迁移
mvn rewrite:run
4.3 典型变更
- import org.junit.Before;
- import org.junit.Test;
- import org.junit.runner.RunWith;
+ import static org.junit.jupiter.api.Assertions.assertEquals;
+ import static org.junit.jupiter.api.Assertions.assertThrows;
+ import org.junit.jupiter.api.BeforeEach;
+ import org.junit.jupiter.api.Test;
+ import org.junit.jupiter.api.extension.ExtendWith;
- import org.mockito.runners.MockitoJUnitRunner;
+ import org.mockito.junit.jupiter.MockitoExtension;
- @Before
- public void setup() {
+ @BeforeEach
+ void setup() {
this.petTypeFormatter = new PetTypeFormatter(pets);
}
- @Test(expected = ParseException.class)
- public void shouldThrowParseException() throws ParseException {
- Mockito.when(this.pets.findPetTypes()).thenReturn(makePetTypes());
- petTypeFormatter.parse("Fish", Locale.ENGLISH);
+ @Test
+ void shouldThrowParseException() throws ParseException {
+ assertThrows(ParseException.class, () -> {
+ Mockito.when(this.pets.findPetTypes()).thenReturn(makePetTypes());
+ petTypeFormatter.parse("Fish", Locale.ENGLISH);
+ });
}
自动处理范围
- ✅ 注解迁移(
@Before
→@BeforeEach
) - ✅ 断言方法更新
- ✅ JUnit 4 特性替换
- ✅ 包名调整(
junit
→junit-jupiter
)
5. Java 8 → 11 升级
5.1 配置 Recipe
<activeRecipes>
<recipe>org.openrewrite.java.migrate.Java8toJava11</recipe>
</activeRecipes>
<dependencies>
<dependency>
<groupId>org.openrewrite.recipe</groupId>
<artifactId>rewrite-migrate-java</artifactId>
<version>2.1.1</version>
</dependency>
</dependencies>
⚠️ 升级到 Java 17 需使用
UpgradeToJava17
Recipe
5.2 执行升级
mvn rewrite:run
5.3 关键变更
Java 版本设置
- <java.version>1.8</java.version> + <java.version>11</java.version>
依赖调整
+ <dependency> + <groupId>jakarta.xml.bind</groupId> + <artifactId>jakarta.xml.bind-api</artifactId> + <version>2.3.3</version> + </dependency> + + <dependency> + <groupId>org.glassfish.jaxb</groupId> + <artifactId>jaxb-runtime</artifactId> + <version>2.3.8</version> + <scope>provided</scope> + </dependency>
插件更新
- <wro4j.version>1.8.0</wro4j.version> + <wro4j.version>1.10.1</wro4j.version>
注意事项
- Java 11 移除了
javax.xml.bind
模块 - 需手动添加 JAXB 实现(如 Glassfish)
- 自动启用
var
等新语法特性
6. 总结
通过 OpenRewrite,我们实现了:
- Spring Boot 1.5 → 2.7 的平滑升级
- JUnit 4 → 5 的自动化迁移
- Java 8 → 11 的版本跃迁
核心优势:
- ✅ 减少手动重构工作量
- ✅ 避免升级过程中的常见坑
- ✅ 保证代码兼容性
- ✅ 支持自定义 Recipe 扩展
建议在执行前使用
git commit
保存代码,方便通过git diff
检查变更。对于复杂项目,建议先在测试分支验证。