OpenRewrite: The Smartest Way to Tackle Tech Debt

Addressing technical debt in modern software engineering is crucial, particularly when it comes to mitigating security vulnerabilities. With the increasing prevalence of data breaches and security threats in our daily lives, tackling this challenge has become more critical than ever.
On the other hand, managing technical debt is both complex and time-consuming — a seemingly never-ending loop. The effort required to update projects can be substantial. Since we’re often dealing with in-flight projects, it’s not feasible to simply halt everything for migrations or to deprioritize business features in favor of addressing technical debt. Unfortunately, technical debt often remains invisible to non-technical stakeholders — until, of course, a data breach occurs or a company faces bankruptcy as a result.
Sometimes, our systems may be vulnerable due to dependencies that aren’t directly used in our projects. While tools like GitHub Code Scanning can help identify these hidden vulnerabilities, addressing them often requires significant manual effort, making the process both time-intensive and complicated.
In this tutorial, I’ll introduce OpenRewrite, a powerful tool that simplifies refactoring with minimal effort. With just a single command-line operation, you can keep your project up to date, saving time and effort while maintaining security and code quality.
Refactoring Your Project With OpenRewrite
OpenRewrite is a game-changer when it comes to tackling technical debt. Released under the Apache License and fully open-source, OpenRewrite primarily focuses on the Java ecosystem but is gradually expanding to support other areas of software engineering.
OpenRewrite offers IDE plugins with built-in functionalities. However, in this tutorial, I’ll demonstrate how to use OpenRewrite in a Maven project to migrate a Spring Boot application. To perform the upgrade, you’ll need a basic understanding of a few core concepts in OpenRewrite.
In this demo, I’m using a Spring Boot 2.x.x project that I developed five years ago with Java 8.
> git clone https://github.com/Denuwanhh/spring-audit-demo.git
Identify Recipes
In OpenRewrite, recipes act as the “switches” that determine the output of the refactoring process. Simply put, your project is the input, and a recipe is the configuration that defines what changes need to be applied. OpenRewrite’s documentation includes popular recipes such as “Migrate to Java 17” and “Migrate to Spring Boot 3 from Spring Boot 2.” You can select a recipe based on your specific requirements and start your migration process.
Recipes often consist of multiple actions to achieve a complete migration. For example, the “Migrate to Spring Boot 3 from Spring Boot 2” recipe doesn’t just handle Java library upgrades — it may also update your source code to align with the requirements of the newer version.
In this demo, I’ll apply two recipes: one to upgrade the Java version and another to upgrade the Spring Boot version. Since I’m using a Maven project, I’ll add the following plugins to the pom.xml
file and simply run the Maven action to initiate the process.
Recipe #1: Migrate to Java 17
Add the following plugins to the pom.xml
file and simply run the Maven mvn rewrite:run
action to initiate the process.
<build>
<plugins>
<plugin>
<groupId>org.openrewrite.maven</groupId>
<artifactId>rewrite-maven-plugin</artifactId>
<version>6.0.0</version>
<configuration>
<activeRecipes>
<recipe>org.openrewrite.java.migrate.UpgradeToJava17</recipe>
</activeRecipes>
</configuration>
<dependencies>
<dependency>
<groupId>org.openrewrite.recipe</groupId>
<artifactId>rewrite-migrate-java</artifactId>
<version>3.0.0</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
Recipe #2: Migrate to Spring Boot 3 from Spring Boot 2
Add the following plugins to the pom.xml
file and simply run the Maven mvn rewrite:run
action to initiate the process.
<project>
<build>
<plugins>
<plugin>
<groupId>org.openrewrite.maven</groupId>
<artifactId>rewrite-maven-plugin</artifactId>
<version>6.0.0</version>
<configuration>
<exportDatatables>true</exportDatatables>
<activeRecipes>
<recipe>org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_2</recipe>
</activeRecipes>
</configuration>
<dependencies>
<dependency>
<groupId>org.openrewrite.recipe</groupId>
<artifactId>rewrite-spring</artifactId>
<version>6.0.0</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>
I won’t go into detail about the changes that occur during the migration. However, you can check out this pull request where I merged the feature-version-upgrade
branch into my master
branch. It provides a clear view of the files that were updated during the migration and the resulting behavior.
Additionally, you’ll notice that the 111 Dependabot alerts previously present on the main
branch were resolved after merging the feature-version-upgrade
branch into master
.
Happy coding…