Migreren met OpenRewrite

OpenRewrite is een open-source project wat geschreven is in Java en het mogelijk maakt je project te migreren naar nieuwe versies van een bepaald framework en technical debt te verminderen door het uitvoeren van een commando.

We hebben er als developers allemaal misschien in het verleden mee te maken gehad; een migratie van een enorm project naar een nieuwe versie van een bepaald framework zoals bij Spring Boot. Deze neemt veel tijd in beslag en het is veel handwerk. Een voorbeeld hiervan is de migratie van Spring Boot 2.7 naar Spring Boot 3.0 waarin o.a. de Java EE naar Jakarta EE migratie zit.

Tegenwoordig zijn er tools hiervoor beschikbaar die je veel handwerk besparen. OpenRewrite is een van die tools.

Oorspronkelijk lag de focus van OpenRewrite op Java en frameworks daarop gebaseerd, maar tegenwoordig is er ook ondersteuning voor o.a. Kotlin, Groovy, XML en JSON.

Recepten in OpenRewrite

Voor het uitvoeren van de wijzigingen in je project maakt OpenRewrite gebruik van recepten. Een recept is een bestand waarin staat waarnaar er gezocht wordt en wat er gewijzigd moet worden. Een recept kan ook bestaan uit andere recepten. Een voorbeeld hiervan is het ‘Migrate to JUnit 5 recept’. Deze bevat een lijst van 3 recepten die uitgevoerd worden.

public class JUnit5Migration extends Recipe { 
    // Standard recipes descriptions and names ... 
 
    @Override 
    public List getRecipeList() { 
        return Arrays.asList( 
            new ChangeType("org.junit.Test", "org.junit.jupiter.api.Test", false), 
            new AssertToAssertions(), 
            new RemovePublicTestModifiers() 
        ); 
    } 
} 

Het ‘Migrate to JUnit 5 recept’ voert eerst het ‘ChangeType’ recept uit waarin de import van de Test class wordt aangepast naar ‘org.junit.jupiter.api.Test’ (JUnit 5) ipv ‘org.junit.Test’ (JUnit 4). Daarna wordt het ‘AssertToAssertions’ recept uitgevoerd wat ‘org.junit.Assert’ (JUnit 4) veranderd naar ‘org.junit.jupiter.api.Assertions’ (JUnit 5) en als laatste het ‘RemovePublicTestModifiers’ recept wat test classes en methodes niet langer public maakt gezien dat niet meer nodig is in JUnit 5.

Dit zorgt ervoor dat elk recept verantwoordelijk is voor een aanpassing en niet voor meerdere aanpassingen wat het recept mogelijk slecht onderhoudbaar maakt.

Binnen OpenRewrite zijn er veel recepten beschikbaar die je kan uitvoeren op je project. Zo zijn er recepten beschikbaar die kwetsbaarheden in je code kan oplossen en recepten die je code moderniseren mocht er een upgrade naar een nieuwe Java versie of framework zijn waar een betere manier beschikbaar is.

Het is ook mogelijk zelf een recept te schrijven voor o.a. interne libraries die gedeeld worden in projecten.

Uitvoeren van een recept

Voor het uitvoeren van een OpenRewrite recept heb je een Maven of Gradle project nodig en moet je Maven of Gradle geïnstalleerd hebben. Als voorbeeld recept neem ik het ‘Migrate to Spring Boot 3.3’ recept die het project migreert naar Spring Boot 3.3.

Rewrite Maven Plugin

Voor Maven projecten is er de Rewrite Maven plugin. Deze kan je op 2 manieren gebruiken: via de command line of toevoegen aan de pom.xml van het project. Het is aanbevolen de command line manier te gebruiken gezien je dan geen aanpassingen hoeft te maken aan de project configuratie, de pom.xml.

Via de command line kan je het volgende commando uitvoeren om het recept uit te voeren:

mvn -U org.openrewrite.maven:rewrite-maven-plugin:run -
Drewrite.recipeArtifactCoordinates=org.openrewrite.recipe:rewrite-spring:RELEASE -
Drewrite.activeRecipes=org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_3

Dit commando zal het recept uitvoeren en als het recept is uitgevoerd zal OpenRewrite in de log laten zien welke bestanden er zijn aangepast door welk recept.

[WARNING] Changes have been made to src/test/java/org/springframework/samples/petclinic/model/ValidatorTests.java by: 
[WARNING]     org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_2 
[WARNING]         org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_1 
[WARNING]             org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_0 
[WARNING]                 org.openrewrite.java.migrate.UpgradeToJava17 
[WARNING]                     org.openrewrite.java.migrate.Java8toJava11 
[WARNING]                         org.openrewrite.java.migrate.UpgradeBuildToJava11 
[WARNING]                             org.openrewrite.java.migrate.UpgradeJavaVersion: {version=11} 
[WARNING]                     org.openrewrite.java.migrate.UpgradeBuildToJava17 
[WARNING]                         org.openrewrite.java.migrate.UpgradeJavaVersion: {version=17} 
[WARNING]                 org.openrewrite.java.migrate.jakarta.JavaxMigrationToJakarta 
[WARNING]                     org.openrewrite.java.migrate.jakarta.JavaxValidationMigrationToJakartaValidation 
[WARNING]                         org.openrewrite.java.ChangePackage: {oldPackageName=javax.validation, newPackageName=jakarta.validation, recursive=true} 
[WARNING] Please review and commit the results. 
[WARNING] Estimate time saved: 25m 
Stukje uit de log als het Migrate to Spring Boot 3.3 recept wordt uitgevoerd op het Spring PetClinic project die nog draait op Spring Boot 2.7.

Het is aanbevolen de wijzigingen daarna te reviewen voordat je deze toevoegt aan je versiebeheersysteem.

Gradle OpenRewrite

Voor Gradle projecten is er ook een plugin beschikbaar en deze kan je op 2 manieren gebruiken: door het toevoegen van configuratie aan de build.gradle van het project of gebruik maken van een init script. Dit laatste is de aanbevolen manier gezien je dit script daarna weer kan weggooien.

Het init script voor de migratie naar Spring Boot 3.3 ziet er als volgt uit:

initscript { 
    repositories { 
        maven { url "https://plugins.gradle.org/m2" } 
    } 
    dependencies { classpath("org.openrewrite:plugin:6.17.1") } 
} 
rootProject { 
    plugins.apply(org.openrewrite.gradle.RewritePlugin) 
    dependencies { 
        rewrite("org.openrewrite.recipe:rewrite-spring:5.16.0") 
    } 
    rewrite { 
        activeRecipe("org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_3") 
        exportDatatables = true 
    } 
    afterEvaluate { 
        if (repositories.isEmpty()) { 
            repositories { 
                mavenCentral() 
            } 
        } 
    } 
} 

Om het script uit te voeren, moet je op de command line het volgende commando uitvoeren:

gradle --init-script init.gradle rewriteRun

Als het script is voltooid, kan je daarna de wijzigingen reviewen en het init script weer verwijderen.

Conclusie

OpenRewrite is een tool die, door middel van de vele recepten die beschikbaar zijn, ons veel tijd bespaart door handmatige stappen te automatiseren en technical debt eenvoudiger op te ruimen. Ook past het verbeteringen toe aan de code mochten die er zijn om deze weer naar de huidige tijd te brengen.

Bronnen

Want to know more about what we do?

We are your dedicated partner. Reach out to us.