OpenRewrite is an automated refactoring ecosystem for source code, enabling developers to effectively eliminate technical debt within their repositories.
It consists of an auto-refactoring engine that runs prepackaged, open-source refactoring recipes for common framework migrations, security fixes, and stylistic consistency tasks – reducing your coding effort from hours or days to minutes. Build tool plugins like the OpenRewrite Gradle plugin and the OpenRewrite Maven plugin help you run these recipes on one repository at a time.
(Note: Any installation of external software or IDE plugin/extension is not required)
Reference Link: Introduction to OpenRewrite | OpenRewrite by Moderne
Types of Recipes
A recipe can represent a single, stand-alone operation or it can be linked together with other recipes to accomplish a larger goal such as a framework migration.
We can also write custom recipes: There are 2 ways to write custom recipes in OpenRewrite:
- Imperative Recipes: An imperative recipe is built by extending the org.openrewrite.Recipe class and injecting configuration properties via its constructor.
- Declarative Recipes: Declarative recipes are defined in YAML and loaded as part of OpenRewrite's managed Environment. A declarative recipe composes and configures other recipes via the OpenRewrite configuration file.
For Java:
For examples for the third-party Java components which are not covered by OpenRewrite
Infinispan
In OpenRewrite Plugin, it generates a migration report ‘rewrite.patch’ file (in the build/reports/rewrite folder)prior to the migration. So, we can check what will be changed from that file.
Steps to migrate Java using OpenRewrite Plugin:
1. Clone legacy Java 8 code base into your IntelliJ
2. Click on the Maven icon in the right side of IntelliJ and then click on the below shown icon to execute Maven goal.

OR
Click on the Gradle icon in the right side of IntelliJ and then click on the below shown icon to execute Gradle task.

3. Then execute mvn clean install, to ensure project with no errors.
OR
Then execute Gradle clean build, to ensure project with no errors.
4. Then add relevant dependencies to build file (maven/Gradle) to migrate from java lower to higher version as given in the below section.
5. Then execute Maven goal - mvn rewrite:dryRun OR Gradle task - Gradle rewriteDryRun.
It will not make any changes to the code, instead it will generate a rewrite.patch file which will give the details of changes it will make when you execute added recipes.
- Org.openrewrite.java.migrate.UpgradeToJava21: To convert Java version to 21. To convert to any other version, just change the version number in the recipe.
- Org.openrewrite.java.spring.framework.UpgradeSpringFramework_6_1: Converting Spring Framework version to 6.1.
- Org.openrewrite.java.spring.security6.UpgradeSpringSecurity_6_2: Converting Spring security version to 6.2.
- Org.openrewrite.java.spring.cloud2023.UpgradeSpringCloud_2023: Converting to the latest Spring Cloud 2023 release.
- Org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_2: To convert Spring Boot version to 3.2.
- Org.openrewrite.java.logging.slf4j.Log4jToSlf4j: To convert Log4j to Slf4j
- Org.openrewrite.java.testing.junit5.JUnit5BestPractices: To convert Junit Test cases
- Org.openrewrite.java.spring.boot2.SpringBoot2JUnit4to5Migration: To convert Junit testcases from version 4 to 5
- Org.openrewrite.java.testing.mockito.Mockito1to5Migration: To convert Mockito framework from lower version to higher version(5.x)
- Org.openrewrite.java.testing.mockito.ReplacePowerMockito: Upgrade to Mockito 5 and replace PowerMockito with raw Mockito
- io.quarkus.updates.core.quarkus30.JacksonJavaxToJakarta: To replace existing Jackson dependencies with their counterparts that are compatible with Jakarta EE.
- Org.openrewrite.java.migrate.jakarta.JavaxXmlSoapToJakartaXmlSoap: To migrate from javax to Jakarta namespace for this dependency
- Org.openrewrite.apache.httpclient5.UpgradeApacheHttpClient_5: To migrate from apache Http Component to version 4 to 5
For examples for the third-party Java components which are not covered by OpenRewrite
Infinispan
- Liquibase
- Apache CXF
- Apache Flink
- Avro
- KafkaClient
- OWASP ESAPI
- TestNG
In OpenRewrite Plugin, it generates a migration report ‘rewrite.patch’ file (in the build/reports/rewrite folder)prior to the migration. So, we can check what will be changed from that file.
Steps to migrate Java using OpenRewrite Plugin:
1. Clone legacy Java 8 code base into your IntelliJ
2. Click on the Maven icon in the right side of IntelliJ and then click on the below shown icon to execute Maven goal.
OR
Click on the Gradle icon in the right side of IntelliJ and then click on the below shown icon to execute Gradle task.
3. Then execute mvn clean install, to ensure project with no errors.
OR
Then execute Gradle clean build, to ensure project with no errors.
4. Then add relevant dependencies to build file (maven/Gradle) to migrate from java lower to higher version as given in the below section.
5. Then execute Maven goal - mvn rewrite:dryRun OR Gradle task - Gradle rewriteDryRun.
It will not make any changes to the code, instead it will generate a rewrite.patch file which will give the details of changes it will make when you execute added recipes.
Mostly this file will be stored in your project build folder under the rewrite folder. Please take a backup of this file once dryRun is completed, because the build folder will be changed each time you build.
6. After verifying the changes in rewrite patch, we can execute Maven goal mvn rewrite:Run OR Gradle task Gradle rewriteRun, this will migrate the code and build files, etc.
7. As shown below you can also see the files got changed from the console, once execute step 6.
Gradle dependencies:
Step 1: Add Plugin
plugins {
id ‘org.openrewrite.rewrite’ version ‘6.20.0’
}
Step 2: Add rewrite section to declare active recipes
rewrite {
activeRecipe("org.openrewrite.java.migrate.UpgradeToJava21")
activeRecipe("org.openrewrite.java.spring.framework.UpgradeSpringFramework_6_1")
activeRecipe("org.openrewrite.java.spring.security6.UpgradeSpringSecurity_6_2")
activeRecipe("org.openrewrite.java.spring.cloud2023.UpgradeSpringCloud_2023")
activeRecipe("org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_2")
activeRecipe("org.openrewrite.java.logging.slf4j.Log4jToSlf4j")
activeRecipe("org.openrewrite.java.testing.junit5.JUnit5BestPractices")
activeRecipe("org.openrewrite.java.spring.boot2.SpringBoot2JUnit4to5Migration")
activeRecipe("org.openrewrite.java.testing.mockito.Mockito1to5Migration")
activeRecipe("org.openrewrite.java.testing.mockito.ReplacePowerMockito")
activeRecipe("io.quarkus.updates.core.quarkus30.JacksonJavaxToJakarta")
activeRecipe("org.openrewrite.java.migrate.jakarta.JavaxXmlSoapToJakartaXmlSoap")
exportDatatables = true
}
Step 3: Add mavenCentral if not exist
repositories {
mavenCentral()
}
Step 4: Add dependencies for declared Recipes
dependencies {
rewrite group: 'org.openrewrite.recipe’, name: ‘rewrite-migrate-java', version: ‘2.22.0’
rewrite group: 'org.openrewrite.recipe’, name: ‘rewrite-spring’, version: ‘5.17.0’
rewrite group: 'org.openrewrite.recipe’, name: ‘rewrite-logging-frameworks', version: ‘2.12.0’
rewrite group: 'org.openrewrite.recipe’, name: ‘rewrite-testing-frameworks', version: ‘2.15.0’
rewrite group: ‘org.openrewrite.recipe’, name: ‘rewrite-third-party’, version: ‘0.6.0’
}
Maven dependencies:
<project>
<build>
<plugins>
<plugin>
<groupId>org.openrewrite.maven</groupId>
<artifactId>rewrite-maven-plugin</artifactId>
<version>5.39.0</version>
<configuration>
<exportDatatables>true</exportDatatables>
<activeRecipes>
<recipe>org.openrewrite.java.migrate.UpgradeToJava21</recipe>
<recipe>org.openrewrite.java.spring.framework.UpgradeSpringFramework_6_1</recipe>
<recipe>org.openrewrite.java.spring.security6.UpgradeSpringSecurity_6_2</recipe>
<recipe>org.openrewrite.java.spring.cloud2023.UpgradeSpringCloud_2023</recipe>
<recipe>org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_2</recipe>
<recipe>org.openrewrite.java.logging.slf4j.Log4jToSlf4j</recipe>
<recipe>org.openrewrite.java.testing.junit5.JUnit5BestPractices</recipe>
<recipe>org.openrewrite.java.spring.boot2.SpringBoot2JUnit4to5Migration</recipe>
<recipe>org.openrewrite.java.testing.mockito.Mockito1to5Migration</recipe>
<recipe>org.openrewrite.java.testing.mockito.ReplacePowerMockito</recipe>
<recipe>org.openrewrite.java.migrate.jakarta.JacksonJavaxToJakarta</recipe>
<recipe>org.openrewrite.java.migrate.jakarta.JavaxXmlSoapToJakartaXmlSoap</recipe>
</activeRecipes>
</configuration>
<dependencies>
<dependency>
<groupId>org.openrewrite.recipe</groupId>
<artifactId>rewrite-migrate-java</artifactId>
<version>2.22.0</version>
</dependency>
<dependency>
<groupId>org.openrewrite.recipe</groupId>
<artifactId>rewrite-spring</artifactId>
<version>5.17.0</version>
</dependency>
<dependency>
<groupId>org.openrewrite.recipe</groupId>
<artifactId>rewrite-logging-frameworks</artifactId>
<version>2.12.0</version>
</dependency>
<dependency>
<groupId>org.openrewrite.recipe</groupId>
<artifactId>rewrite-testing-frameworks</artifactId>
<version>2.15.0</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>
6. After verifying the changes in rewrite patch, we can execute Maven goal mvn rewrite:Run OR Gradle task Gradle rewriteRun, this will migrate the code and build files, etc.
7. As shown below you can also see the files got changed from the console, once execute step 6.
Gradle dependencies:
Step 1: Add Plugin
plugins {
id ‘org.openrewrite.rewrite’ version ‘6.20.0’
}
Step 2: Add rewrite section to declare active recipes
rewrite {
activeRecipe("org.openrewrite.java.migrate.UpgradeToJava21")
activeRecipe("org.openrewrite.java.spring.framework.UpgradeSpringFramework_6_1")
activeRecipe("org.openrewrite.java.spring.security6.UpgradeSpringSecurity_6_2")
activeRecipe("org.openrewrite.java.spring.cloud2023.UpgradeSpringCloud_2023")
activeRecipe("org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_2")
activeRecipe("org.openrewrite.java.logging.slf4j.Log4jToSlf4j")
activeRecipe("org.openrewrite.java.testing.junit5.JUnit5BestPractices")
activeRecipe("org.openrewrite.java.spring.boot2.SpringBoot2JUnit4to5Migration")
activeRecipe("org.openrewrite.java.testing.mockito.Mockito1to5Migration")
activeRecipe("org.openrewrite.java.testing.mockito.ReplacePowerMockito")
activeRecipe("io.quarkus.updates.core.quarkus30.JacksonJavaxToJakarta")
activeRecipe("org.openrewrite.java.migrate.jakarta.JavaxXmlSoapToJakartaXmlSoap")
exportDatatables = true
}
Step 3: Add mavenCentral if not exist
repositories {
mavenCentral()
}
Step 4: Add dependencies for declared Recipes
dependencies {
rewrite group: 'org.openrewrite.recipe’, name: ‘rewrite-migrate-java', version: ‘2.22.0’
rewrite group: 'org.openrewrite.recipe’, name: ‘rewrite-spring’, version: ‘5.17.0’
rewrite group: 'org.openrewrite.recipe’, name: ‘rewrite-logging-frameworks', version: ‘2.12.0’
rewrite group: 'org.openrewrite.recipe’, name: ‘rewrite-testing-frameworks', version: ‘2.15.0’
rewrite group: ‘org.openrewrite.recipe’, name: ‘rewrite-third-party’, version: ‘0.6.0’
}
Maven dependencies:
<project>
<build>
<plugins>
<plugin>
<groupId>org.openrewrite.maven</groupId>
<artifactId>rewrite-maven-plugin</artifactId>
<version>5.39.0</version>
<configuration>
<exportDatatables>true</exportDatatables>
<activeRecipes>
<recipe>org.openrewrite.java.migrate.UpgradeToJava21</recipe>
<recipe>org.openrewrite.java.spring.framework.UpgradeSpringFramework_6_1</recipe>
<recipe>org.openrewrite.java.spring.security6.UpgradeSpringSecurity_6_2</recipe>
<recipe>org.openrewrite.java.spring.cloud2023.UpgradeSpringCloud_2023</recipe>
<recipe>org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_2</recipe>
<recipe>org.openrewrite.java.logging.slf4j.Log4jToSlf4j</recipe>
<recipe>org.openrewrite.java.testing.junit5.JUnit5BestPractices</recipe>
<recipe>org.openrewrite.java.spring.boot2.SpringBoot2JUnit4to5Migration</recipe>
<recipe>org.openrewrite.java.testing.mockito.Mockito1to5Migration</recipe>
<recipe>org.openrewrite.java.testing.mockito.ReplacePowerMockito</recipe>
<recipe>org.openrewrite.java.migrate.jakarta.JacksonJavaxToJakarta</recipe>
<recipe>org.openrewrite.java.migrate.jakarta.JavaxXmlSoapToJakartaXmlSoap</recipe>
</activeRecipes>
</configuration>
<dependencies>
<dependency>
<groupId>org.openrewrite.recipe</groupId>
<artifactId>rewrite-migrate-java</artifactId>
<version>2.22.0</version>
</dependency>
<dependency>
<groupId>org.openrewrite.recipe</groupId>
<artifactId>rewrite-spring</artifactId>
<version>5.17.0</version>
</dependency>
<dependency>
<groupId>org.openrewrite.recipe</groupId>
<artifactId>rewrite-logging-frameworks</artifactId>
<version>2.12.0</version>
</dependency>
<dependency>
<groupId>org.openrewrite.recipe</groupId>
<artifactId>rewrite-testing-frameworks</artifactId>
<version>2.15.0</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>
Manual Migration : There are few areas where openRewrite is suggesting for manual migration, so we captured one of that scenario from our PoC migration report, as in the below screenshot.

Please Note:
Please Note:
- The basic free version of OpenRwerite appears adequate for Java 21 upgrade.
- Most migrations can be handled with default recipes.
- Custom recipes are required for some Java components-related implementation
- During the POC, we observed 70% of the code was properly converted, while the remaining 30% requires manual fixes.
- The 'rewrite.patch' provides detailed code conversion details. OpenRwerite suggests manual migration for inherited classes and Spring.Security packages.
- Increase in Sonar and Snyk violations observed post-migration.
Optional: Steps to Add Custom Imperative Recipes Using OpenRewrite
Create a New Java Class for the Recipe: Define your custom recipe by creating a new Java class that extends Recipe. Create a file named src/main/java/com/example/recipes/CustomRecipe.java with the following content:
package com.example.recipes;
import org.openrewrite.Recipe;
import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.tree.J;
public class CustomRecipe extends Recipe {
@Override
public String getDisplayName() {
return "Custom Recipe";
}
@Override
public String getDescription() {
return "A custom recipe for demonstration purposes.";
}
@Override
protected JavaIsoVisitor<ExecutionContext> getVisitor() {
return new JavaIsoVisitor<ExecutionContext>() {
@Override
public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration method, ExecutionContext ctx) {
// Add your custom transformation logic here
return super.visitMethodDeclaration(method, ctx);
}
};
}
}
2. Implement the Recipe Logic: Override the getVisitor() method to provide the logic for your recipe. In the visitMethodDeclaration method, add the logic for the transformations you want to apply. For example, you can change method names, modify annotations, etc.
3. Register the Recipe: Ensure your custom recipe is registered and can be discovered by OpenRewrite. You can do this by adding a META-INF/rewrite/rewrite.yml file:
type: specs.openrewrite.org/v1beta/recipe
name: com.example.recipes.CustomRecipe
displayName: Custom Recipe
description: A custom recipe for demonstration purposes.
recipeList:
- com.example.recipes.CustomRecipe
Create a New Java Class for the Recipe: Define your custom recipe by creating a new Java class that extends Recipe. Create a file named src/main/java/com/example/recipes/CustomRecipe.java with the following content:
package com.example.recipes;
import org.openrewrite.Recipe;
import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.tree.J;
public class CustomRecipe extends Recipe {
@Override
public String getDisplayName() {
return "Custom Recipe";
}
@Override
public String getDescription() {
return "A custom recipe for demonstration purposes.";
}
@Override
protected JavaIsoVisitor<ExecutionContext> getVisitor() {
return new JavaIsoVisitor<ExecutionContext>() {
@Override
public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration method, ExecutionContext ctx) {
// Add your custom transformation logic here
return super.visitMethodDeclaration(method, ctx);
}
};
}
}
2. Implement the Recipe Logic: Override the getVisitor() method to provide the logic for your recipe. In the visitMethodDeclaration method, add the logic for the transformations you want to apply. For example, you can change method names, modify annotations, etc.
3. Register the Recipe: Ensure your custom recipe is registered and can be discovered by OpenRewrite. You can do this by adding a META-INF/rewrite/rewrite.yml file:
type: specs.openrewrite.org/v1beta/recipe
name: com.example.recipes.CustomRecipe
displayName: Custom Recipe
description: A custom recipe for demonstration purposes.
recipeList:
- com.example.recipes.CustomRecipe
Steps to Add Custom Declarative Recipes Using OpenRewrite
1. Create a YAML Recipe File: Define your custom recipe in a YAML file. This file will contain the specifications for the transformations you want to apply.
Create a file named src/main/resources/custom-recipe.yml with the following content:
type: specs.openrewrite.org/v1beta/recipe
name: com.example.CustomRecipe
displayName: Custom Recipe
description: A custom recipe for demonstration purposes.
recipeList:
- org.openrewrite.java.ChangeType:
oldFullyQualifiedTypeName: com.oldpackage.OldClass
newFullyQualifiedTypeName: com.newpackage.NewClass
- org.openrewrite.java.ChangeMethodName:
methodPattern: com.oldpackage.OldClass#oldMethod
newMethodName: newMethod
2. Add the Recipe to Your Project: Place the YAML file in your project directory, typically under src/main/resources.
3. Configure the rewrite-maven-plugin: Update your pom.xml to include the rewrite-maven-plugin and reference your custom recipe.
<configuration>
<activeRecipes>
<recipe>com.example.CustomRecipe</recipe>
</activeRecipes>
<configLocation>src/main/resources/custom-recipe.yml</configLocation>
</configuration>
1. Create a YAML Recipe File: Define your custom recipe in a YAML file. This file will contain the specifications for the transformations you want to apply.
Create a file named src/main/resources/custom-recipe.yml with the following content:
type: specs.openrewrite.org/v1beta/recipe
name: com.example.CustomRecipe
displayName: Custom Recipe
description: A custom recipe for demonstration purposes.
recipeList:
- org.openrewrite.java.ChangeType:
oldFullyQualifiedTypeName: com.oldpackage.OldClass
newFullyQualifiedTypeName: com.newpackage.NewClass
- org.openrewrite.java.ChangeMethodName:
methodPattern: com.oldpackage.OldClass#oldMethod
newMethodName: newMethod
2. Add the Recipe to Your Project: Place the YAML file in your project directory, typically under src/main/resources.
3. Configure the rewrite-maven-plugin: Update your pom.xml to include the rewrite-maven-plugin and reference your custom recipe.
<configuration>
<activeRecipes>
<recipe>com.example.CustomRecipe</recipe>
</activeRecipes>
<configLocation>src/main/resources/custom-recipe.yml</configLocation>
</configuration>
Happy Learning!
Comments