OpenRewrite 指南
1. 概述
OpenRewrite是一個針對 Java 和其他原始程式碼的重構生態系統。有時,我們需要將依賴項升級到最新版本、應用程式安全性修補程式、消除使用已棄用的 API、從一種技術遷移到另一種技術(例如, JUnit 斷言到 AssertJ )等。我們可以使用OpenRewrite 程式庫來解決這些問題挑戰。在本教程中,我們將討論 OpenRewrite 專案的基礎知識,並展示一些如何在實踐中使用它的範例。在每種情況下,我們都將使用Spring PetClinic應用程式。
2.OpenRewrite基礎知識
以下是我們可以使用 OpenRewrite 執行的一些常見升級類型:
- 語言升級:從舊版的語言遷移到新版本,例如從 Java 8 遷移到 Java 11 或更高版本。
- 框架升級:適應較新版本的框架,如 Spring Boot、Hibernate 等。
- 依賴項遷移:當發生重大變更時,從一個庫版本升級到另一個版本。
- 安全修補:以安全的替代方案取代易受攻擊的方法或函式庫。
- 自訂轉換:特定於我們的業務邏輯或基礎架構的任何轉換。
2.1. OpenRewrite 食譜
OpenRewrite 的主要特點是它會透過將配方應用到專案來自動重構原始程式碼。 OpenRewrite 附帶了各種用於常見轉換的內建配方,並且社群經常為廣泛的任務貢獻配方。每個配方都可以執行特定的重構任務。這些配方是用 Java 程式碼編寫的,並包含在使用 OpenRewrite Maven 或 Gradle 外掛程式的建置過程中。在本教程中,我們將重點放在 Maven 插件。
2.2. Maven依賴
讓我們先在pom.xml
的<plugins>
部分導入rewrite-maven-plugin
插件:
<plugin>
<groupId>org.openrewrite.maven</groupId>
<artifactId>rewrite-maven-plugin</artifactId>
<version>5.8.1</version>
<configuration>
<activeRecipes>
// Define the recipes
</activeRecipes>
</configuration>
<dependencies>
// Dependencies for recipes
</dependencies>
</plugin>
<activeRecipes>
標籤指定插件運行時哪些 OpenRewrite 配方應處於活動狀態。此外,我們可以定義插件可能需要的任何其他依賴項。如果某些食譜需要外部庫或特定版本的庫,這可能特別有用。
2.3.結帳春天寵物診所
我們在本地查看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 和 Spring Boot 版本分別為 8 和 1.5。在接下來的部分中,我們將介紹最廣泛使用的食譜。
3. 升級Spring Boot
升級 Spring Boot 專案可能是一項複雜的任務,具體取決於我們目前使用的版本和我們想要升級到的版本之間的變更。然而,使用 OpenRewrite 可以幫助我們順利地完成這個過程。讓我們將 PetClinic 專案從 Spring Boot 1.5 升級到 2.7。
3.1. Maven依賴
讓我們將UpgradeSpringBoot_2_7
配方加入rewrite-maven-plugin
插件的<activeRecipes>
部分:
<activeRecipes>
<recipe>org.openrewrite.java.spring.boot2.UpgradeSpringBoot_2_7</recipe>
</activeRecipes>
另外,我們需要聲明rewrite-spring
對插件的<dependencies>
部分的依賴:
<dependency>
<groupId>org.openrewrite.recipe</groupId>
<artifactId>rewrite-spring</artifactId>
<version>5.0.11</version>
</dependency>
請注意,要升級到 Spring Boot 3,我們需要使用UpgradeSpringBoot_3_0
食譜。
3.2.運行 Spring Boot 升級配方
現在,我們準備好透過執行以下命令來執行遷移:
mvn rewrite:run
下面,我們可以看到Maven的結果:
[INFO] --- rewrite-maven-plugin:5.8.1:run (default-cli) @ spring-petclinic ---
[INFO] Using active recipe(s) [org.openrewrite.java.spring.boot2.UpgradeSpringBoot_2_7]
[INFO] Using active styles(s) []
[INFO] Validating active recipes...
[INFO] Project [petclinic] Resolving Poms...
[INFO] Project [petclinic] Parsing source files
在這裡,我們看到 Maven 列出了活動配方並應用了pom
和原始檔案變更。運行配方後,OpenRewrite 會提供更改清單。我們可以使用git diff
來檢查結果:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
- <version>1.5.4.RELEASE</version>
+ <version>2.7.14</version>
</parent>
這裡我們可以看到, spring-boot-starter-parent
版本已經升級到2.7.14。此外,在升級過程中, @Autowired
已從我們的一些 Java 類別中刪除:
-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
註解。當我們升級到較新版本的 Spring Boot 時,許多託管依賴項(包括 JUnit)也可能會升級。 Spring Boot 2.x 預設使用 JUnit 5,而 Spring Boot 1.5 與 JUnit 4 保持一致。這表示測試的結構和運作方式發生了預期的變化。根據我們的需求,我們可以只升級JUnit,而不會升級Spring Boot。在下一節中,我們將了解如何從 JUnit 4 遷移到 JUnit 5。
4.升級到JUnit5
JUnit 是 Java 應用程式中單元測試的事實上的標準。 OpenRewrite 支援從 JUnit 4 遷移到其後繼 JUnit 5 。
4.1. Maven依賴
讓我們在pom.xml
中啟動[JUnit5BestPractices](https://docs.openrewrite.org/recipes/java/testing/junit5/junit5bestpractices)
配方:
<activeRecipes>
<recipe>org.openrewrite.java.testing.junit5.JUnit5BestPractices</recipe>
</activeRecipes>
另外,我們需要聲明rewrite-testing-frameworks
對我們插件的<dependencies>
部分的依賴:
<dependency>
<groupId>org.openrewrite.recipe</groupId>
<artifactId>rewrite-testing-frameworks</artifactId>
<version>2.0.12</version>
</dependency>
4.2.運行 JUnit 升級配方
現在,我們透過執行mvn rewrite:run
指令來執行遷移。此命令大約在一分鐘內完成,並將所有測試遷移到 JUnit 5,並更新pom.xml
:
-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);
+ });
}
OpenRewrite 不僅更新導入和@Test
註釋,還更新方法可見度、應用MockitoExtension,
並採用assertThrows()
。一般來說,OpenRewrite 可以幫助 JUnit 遷移完成以下任務:
- 更新註釋,例如將
@Before
更改為@BeforeEach
或@After
更改為@AfterEach
。 - 修改斷言方法呼叫以與 JUnit 5 的語法保持一致。
- 刪除 JUnit 4 的特定功能或將其替換為 JUnit 5 的對應功能。
- 將導入語句從 JUnit 4 套件更新到 JUnit 5 套件。
5.升級到Java 11
將較舊的原始程式碼升級到 Java 11 可能是一個具有挑戰性且耗時的問題。在本節中,我們將使用 OpenRewrite 執行從 Java 8 到 Java 11 的自動遷移。
5.1. Maven依賴
要升級 Java,我們需要不同的依賴項和配方。讓我們將Java8toJava11
配方加入<activeRecipes>
部分:
<activeRecipes>
<recipe>org.openrewrite.java.migrate.Java8toJava11</recipe>
</activeRecipes>
另外,我們需要聲明對我們的插件的rewrite-migrate-java
相依性:
<dependency>
<groupId>org.openrewrite.recipe</groupId>
<artifactId>rewrite-migrate-java</artifactId>
<version>2.1.1</version>
</dependency>
請注意,要升級到 Java 17,我們需要使用UpgradeToJava17
配方。
5.2.運行 Java 升級配方
要升級Java,我們可以套用mvn rewrite:run
指令。之後,我們將看到以下輸出:
[INFO] Using active recipe(s) [org.openrewrite.java.migrate.Java8toJava11]
[INFO] Running recipe(s)...
[WARNING] Changes have been made to pom.xml by:
[WARNING] org.openrewrite.java.migrate.Java8toJava11
[WARNING] org.openrewrite.java.migrate.javax.AddJaxbDependencies
[WARNING] org.openrewrite.java.dependencies.AddDependency: {groupId=jakarta.xml.bind, artifactId=jakarta.xml.bind-api, version=2.3.x, onlyIfUsing=javax.xml.bind..*, acceptTransitive=true}
[WARNING] org.openrewrite.maven.AddDependency: {groupId=jakarta.xml.bind, artifactId=jakarta.xml.bind-api, version=2.3.x, onlyIfUsing=javax.xml.bind..*, acceptTransitive=true}
[WARNING] org.openrewrite.java.migrate.javax.AddJaxbRuntime: {runtime=glassfish}
[WARNING] org.openrewrite.java.migrate.javax.AddJaxbRuntime$AddJaxbRuntimeMaven
[WARNING] org.openrewrite.java.migrate.cobertura.RemoveCoberturaMavenPlugin
[WARNING] org.openrewrite.maven.RemovePlugin: {groupId=org.codehaus.mojo, artifactId=cobertura-maven-plugin}
[WARNING] org.openrewrite.java.migrate.wro4j.UpgradeWro4jMavenPluginVersion
[WARNING] org.openrewrite.maven.UpgradePluginVersion: {groupId=ro.isdc.wro4j, artifactId=wro4j-maven-plugin, newVersion=1.10.1}
[WARNING] org.openrewrite.java.migrate.JavaVersion11
[WARNING] org.openrewrite.java.migrate.UpgradeJavaVersion: {version=11}
Java8toJava11
配方產生以下主要相關變更:
- <java.version>1.8</java.version>
+ <java.version>11</java.version>
- <wro4j.version>1.8.0</wro4j.version>
+ <wro4j.version>1.10.1</wro4j.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>
在這裡,我們看到java.version
Maven 屬性更改為 11,這設定了maven.compiler.source
和maven.compiler.target
。這將解鎖 Java 11 語言功能,例如var
。在此過程中, wro4j
也更新到最新版本。 Wro4j 是一個流行的開源項目,用於優化和管理 Java 應用程式中的 Web 資源,例如 JavaScript 和 CSS 檔案。此外,從 Java 8 遷移到 Java 11 時,主要變更之一是從 JDK 中刪除了javax.xml.bind
模組。許多依賴此模組來實作 JAXB 功能的應用程式需要新增第三方相依性才能保留此功能。其中一個替代方案是jakarta.xml.bind-api
依賴項。
六,結論
在本教程中,我們提供了有關利用 OpenRewrite 專案在 Spring PetClinic 程式碼庫中無縫升級 Spring Boot、JUnit 和 Java 版本的逐步指南。透過學習本教程,我們可以深入了解升級過程的複雜性,確保這些核心組件的過渡更順暢,程式碼相容性更好。