Add openrewrite module: Boot 2.7 to 3.5 to 4.0 upgrade with OpenRewrite recipes, leftovers and CI gate

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Gth99spB1CzQmBFofXmU4Z
This commit is contained in:
Claude
2026-09-28 08:40:08 +00:00
parent e4f927d7af
commit b4b43b94bf
24 changed files with 559 additions and 0 deletions
@@ -0,0 +1,3 @@
# 00-gotcha-gitignore: same recipe, same project, sources under a .gitignore'd directory
[INFO] Project [legacy-app] Parsing source files
[INFO] Applying recipes would make no changes. No patch file generated.
+3
View File
@@ -0,0 +1,3 @@
# 01-baseline: legacy app, Spring Boot 2.7.18, JDK 17
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO] BUILD SUCCESS
+173
View File
@@ -0,0 +1,173 @@
# 02-step1-diff: recipe org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_5 on the legacy app (52 s)
diff -ru -x target legacy-app/pom.xml step1/pom.xml
--- legacy-app/pom.xml
+++ step1/pom.xml
@@ -4,7 +4,7 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
- <version>2.7.18</version>
+ <version>3.5.16</version>
<relativePath/>
</parent>
<groupId>com.ankurm</groupId>
@@ -14,6 +14,10 @@
<java.version>17</java.version>
</properties>
<dependencies>
+ <dependency>
+ <groupId>jakarta.servlet</groupId>
+ <artifactId>jakarta.servlet-api</artifactId>
+ </dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency>
@@ -21,7 +25,6 @@
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency>
<dependency><groupId>com.h2database</groupId><artifactId>h2</artifactId><scope>runtime</scope></dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency>
- <dependency><groupId>org.junit.vintage</groupId><artifactId>junit-vintage-engine</artifactId><scope>test</scope></dependency>
<dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-test</artifactId><scope>test</scope></dependency>
</dependencies>
<build>
diff -ru -x target legacy-app/src/main/java/com/ankurm/legacy/AuditAutoConfiguration.java step1/src/main/java/com/ankurm/legacy/AuditAutoConfiguration.java
--- legacy-app/src/main/java/com/ankurm/legacy/AuditAutoConfiguration.java
+++ step1/src/main/java/com/ankurm/legacy/AuditAutoConfiguration.java
@@ -1,7 +1,7 @@
package com.ankurm.legacy;
-import org.springframework.context.annotation.Configuration;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
-@Configuration
+@AutoConfiguration
public class AuditAutoConfiguration {
}
diff -ru -x target legacy-app/src/main/java/com/ankurm/legacy/Customer.java step1/src/main/java/com/ankurm/legacy/Customer.java
--- legacy-app/src/main/java/com/ankurm/legacy/Customer.java
+++ step1/src/main/java/com/ankurm/legacy/Customer.java
@@ -1,10 +1,10 @@
package com.ankurm.legacy;
-import javax.persistence.Entity;
-import javax.persistence.GeneratedValue;
-import javax.persistence.Id;
-import javax.validation.constraints.Email;
-import javax.validation.constraints.NotBlank;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.Id;
+import jakarta.validation.constraints.Email;
+import jakarta.validation.constraints.NotBlank;
@Entity
public class Customer {
diff -ru -x target legacy-app/src/main/java/com/ankurm/legacy/CustomerController.java step1/src/main/java/com/ankurm/legacy/CustomerController.java
--- legacy-app/src/main/java/com/ankurm/legacy/CustomerController.java
+++ step1/src/main/java/com/ankurm/legacy/CustomerController.java
@@ -1,8 +1,8 @@
package com.ankurm.legacy;
import java.util.List;
-import javax.annotation.PostConstruct;
-import javax.validation.Valid;
+import jakarta.annotation.PostConstruct;
+import jakarta.validation.Valid;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
diff -ru -x target legacy-app/src/main/java/com/ankurm/legacy/CustomerRepository.java step1/src/main/java/com/ankurm/legacy/CustomerRepository.java
--- legacy-app/src/main/java/com/ankurm/legacy/CustomerRepository.java
+++ step1/src/main/java/com/ankurm/legacy/CustomerRepository.java
@@ -1,10 +1,10 @@
package com.ankurm.legacy;
-import javax.persistence.LockModeType;
+import jakarta.persistence.LockModeType;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Lock;
import org.springframework.data.jpa.repository.QueryHints;
-import javax.persistence.QueryHint;
+import jakarta.persistence.QueryHint;
public interface CustomerRepository extends JpaRepository<Customer, Long> {
diff -ru -x target legacy-app/src/main/java/com/ankurm/legacy/RequestLogFilter.java step1/src/main/java/com/ankurm/legacy/RequestLogFilter.java
--- legacy-app/src/main/java/com/ankurm/legacy/RequestLogFilter.java
+++ step1/src/main/java/com/ankurm/legacy/RequestLogFilter.java
@@ -1,10 +1,10 @@
package com.ankurm.legacy;
import java.io.IOException;
-import javax.servlet.FilterChain;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
diff -ru -x target legacy-app/src/main/java/com/ankurm/legacy/SecurityConfig.java step1/src/main/java/com/ankurm/legacy/SecurityConfig.java
--- legacy-app/src/main/java/com/ankurm/legacy/SecurityConfig.java
+++ step1/src/main/java/com/ankurm/legacy/SecurityConfig.java
@@ -1,17 +1,19 @@
package com.ankurm.legacy;
+import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
-import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
-public class SecurityConfig extends WebSecurityConfigurerAdapter {
- @Override
- protected void configure(HttpSecurity http) throws Exception {
- http.csrf().disable()
- .authorizeRequests().antMatchers("/actuator/health").permitAll()
- .anyRequest().permitAll();
+public class SecurityConfig {
+ @Bean
+ SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
+ http.csrf(csrf -> csrf.disable())
+ .authorizeHttpRequests(requests -> requests.requestMatchers("/actuator/health").permitAll()
+ .anyRequest().permitAll());
+ return http.build();
}
}
Only in step1/src/main/resources/META-INF: spring
diff -ru -x target legacy-app/src/main/resources/application.properties step1/src/main/resources/application.properties
--- legacy-app/src/main/resources/application.properties
+++ step1/src/main/resources/application.properties
@@ -3,4 +3,4 @@
management.metrics.export.prometheus.enabled=true
spring.jpa.hibernate.ddl-auto=create-drop
server.max-http-header-size=16KB
-spring.jpa.properties.javax.persistence.validation.mode=none
+spring.jpa.properties.jakarta.persistence.validation.mode=none
diff -ru -x target legacy-app/src/test/java/com/ankurm/legacy/CustomerControllerTest.java step1/src/test/java/com/ankurm/legacy/CustomerControllerTest.java
--- legacy-app/src/test/java/com/ankurm/legacy/CustomerControllerTest.java
+++ step1/src/test/java/com/ankurm/legacy/CustomerControllerTest.java
@@ -4,15 +4,12 @@
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
-@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class CustomerControllerTest {
Only in step1/src/main/resources/META-INF: spring
+3
View File
@@ -0,0 +1,3 @@
# 03-step1-build: after step 1, JDK 17
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO] BUILD SUCCESS
+65
View File
@@ -0,0 +1,65 @@
# 04-step2-diff: recipe org.openrewrite.java.spring.boot4.UpgradeSpringBoot_4_0 applied on top of step 1 (32 s)
diff -ru -x target step1/pom.xml step2/pom.xml
--- step1/pom.xml
+++ step2/pom.xml
@@ -4,7 +4,7 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
- <version>3.5.16</version>
+ <version>4.0.8</version>
<relativePath/>
</parent>
<groupId>com.ankurm</groupId>
@@ -18,14 +18,23 @@
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
</dependency>
- <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>
+ <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webmvc</artifactId></dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-restclient</artifactId>
+ </dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency>
<dependency><groupId>com.h2database</groupId><artifactId>h2</artifactId><scope>runtime</scope></dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency>
- <dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-test</artifactId><scope>test</scope></dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-webmvc-test</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security-test</artifactId><scope>test</scope></dependency>
</dependencies>
<build>
<plugins>
diff -ru -x target step1/src/main/resources/application.properties step2/src/main/resources/application.properties
--- step1/src/main/resources/application.properties
+++ step2/src/main/resources/application.properties
@@ -1,6 +1,6 @@
-spring.redis.host=localhost
-spring.redis.port=6379
-management.metrics.export.prometheus.enabled=true
+spring.data.redis.host=localhost
+spring.data.redis.port=6379
+management.prometheus.metrics.export.enabled=true
spring.jpa.hibernate.ddl-auto=create-drop
-server.max-http-header-size=16KB
+server.max-http-request-header-size=16KB
spring.jpa.properties.jakarta.persistence.validation.mode=none
diff -ru -x target step1/src/test/java/com/ankurm/legacy/CustomerControllerTest.java step2/src/test/java/com/ankurm/legacy/CustomerControllerTest.java
--- step1/src/test/java/com/ankurm/legacy/CustomerControllerTest.java
+++ step2/src/test/java/com/ankurm/legacy/CustomerControllerTest.java
@@ -6,7 +6,7 @@
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;
+3
View File
@@ -0,0 +1,3 @@
# 05-step2-build: after step 2, JDK 17
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO] BUILD SUCCESS
@@ -0,0 +1,13 @@
# 06-what-it-left-behind (in /tmp/or-work/step2, after both recipes)
--- leftover 'javax.' string literals or keys in source and resources:
src/main/java/com/ankurm/legacy/CustomerRepository.java:12: @QueryHints(@QueryHint(name = "javax.persistence.lock.timeout", value = "3000"))
--- META-INF files:
./spring.factories
./spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
--- explicit jakarta.servlet-api dependency added to the pom:
1
--- RestTemplate usages (recipe does not touch them):
src/main/java/com/ankurm/legacy/RemoteClient.java:4:import org.springframework.web.client.RestTemplate;
src/main/java/com/ankurm/legacy/RemoteClient.java:8: private final RestTemplate rest = new RestTemplate();
--- Spring Boot version the recipe stopped at:
<version>4.0.8</version>
@@ -0,0 +1,4 @@
# 07-step3-boot-4.1.1: parent bumped by hand from the recipe's 4.0.x to 4.1.1, JDK 17
<version>4.1.1</version>
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO] BUILD SUCCESS
+4
View File
@@ -0,0 +1,4 @@
# 08-ci-gate (mvn rewrite:dryRun, exit code decides the CI job)
legacy app, -Drewrite.failOnDryRunResults=true (the name you would guess): exit code 0
legacy app, -DfailOnDryRunResults=true (the real user property): exit code 1
migrated app, -DfailOnDryRunResults=true: exit code 0