[MM’s] Boot Notes — OpenRewrite

Automated, auditable migrations to Java 25 and Spring Boot 4

Automated, auditable migrations to Java 25 and Spring Boot 4

Upgrading a large Java codebase is rarely blocked by one catastrophic breaking change. It’s blocked by hundreds of small, mechanical, easy-to-miss updates scattered across build files, deprecated APIs, configuration properties, and test infrastructure.

That’s exactly the kind of work humans are bad at — and exactly the problem OpenRewrite is designed to solve.

TL;DR (Quick Recap)

  • OpenRewrite automates large-scale Java and Spring Boot migrations safely and consistently.
  • Java 25 and Spring Boot 4 upgrades are mostly mechanical, not conceptual — perfect for automation.
  • OpenRewrite applies semantic, AST-aware transformations, not brittle text rewrites — LST (Lossless Semantic Tree)
  • Use it to eliminate migration toil, not to skip testing or validation.

What Is OpenRewrite?

OpenRewrite is an open-source automated refactoring ecosystem built around semantic code transformations. Unlike traditional search-and-replace tools, OpenRewrite operates on the Abstract Syntax Tree (AST) of your code. That means it understands:

  • Language constructs
  • Type hierarchies
  • Build metadata
  • Configuration semantics

At its core, OpenRewrite runs recipes — curated sets of refactorings maintained by framework and platform experts — that encode how migrations should actually be done.

Why OpenRewrite Exists (and Why It Matters Now)

Most teams don’t avoid platform upgrades because they’re hard to understand. They avoid them because they’re time-consuming, error-prone and boring.

Every major Java or Spring Boot upgrade introduces:

  • Deprecated APIs with non-obvious replacements
  • Build and plugin alignment issues
  • Configuration properties that silently stop working
  • Framework defaults that become explicit

Do this manually across dozens of modules or microservices and you’ll:

  • Miss edge cases
  • Introduce inconsistencies
  • Burn engineering time on low-value work

OpenRewrite changes the equation by turning migrations into repeatable, reviewable and automated refactors.

The OpenRewrite Philosophy

OpenRewrite recipes are not blind rewrites. They encode maintainer-level intent:

  • What changed
  • What was removed
  • What must now be explicit
  • What is safe to automate

Three practical benefits:

  1. Consistency Every deprecated pattern is migrated the same way, everywhere.
  2. Auditability Dry runs produce full diffs and reports before anything changes.
  3. Safety Transformations apply only when the intent is unambiguous.

OpenRewrite won’t guarantee identical runtime behavior — that’s your tests’ job — but it will guarantee that the mechanical work is done correctly and consistently.

Migrating to Java 25 with OpenRewrite

Java upgrades rarely fail because teams misunderstand new language features. They fail because small changes accumulate across large codebases.

The Java 25 Migration Entry Point

org.openrewrite.java.migrate.UpgradeToJava25

This composite recipe handles migrations from Java 8, 11, 17 and 21, applying only the transformations relevant to your current baseline.

What the Java 25 Recipe Actually Does

1. Build Configuration Alignment

  • Updates Maven and Gradle source/target levels
  • Aligns compiler plugins
  • Makes Java 25 usage explicit and enforceable

2. Deprecated and Removed API Cleanup

Between Java 21 and 25, several deprecated APIs escalate from warnings to removals. OpenRewrite:

  • Detects deprecated usage with known replacements
  • Applies safe substitutions
  • Removes constructs that no longer exist

The result: future-breaking changes become controlled diffs, not surprise outages.

3. Removal of Legacy Security Constructs

Java’s security model continues to harden. The recipe removes:

  • SecurityManager usage
  • Obsolete security hooks that no longer function meaningfully

This isn’t optional cleanup — these constructs are dead weight in modern Java runtime.

4. Targeted Language and I/O Modernization

Where Java provides clear, safer alternatives, the recipe modernizes code:

  • Legacy output patterns
  • Outdated I/O idioms

Crucially, OpenRewrite only applies these changes, when the transformation is semantically unambiguous.

Running the Java 25 Migration

1. Add the OpenRewrite Plugin

<plugin>
<groupId>org.openrewrite.maven</groupId>
<artifactId>rewrite-maven-plugin</artifactId>
<version>7.24.0</version>
<configuration>
<activeRecipes>
<recipe>org.openrewrite.java.migrate.UpgradeToJava25</recipe>
</activeRecipes>
</configuration>
<dependencies>
<dependency>
<groupId>org.openrewrite.recipe</groupId>
<artifactId>rewrite-migrate-java</artifactId>
<version>latest.release</version>
</dependency>
</dependencies>
</plugin>

2. Always Run a Dry Run First, then Apply the Migration

mvn rewrite:dryRun

mvn rewrite:run
mvn clean compile
mvn test

This should be a purely mechanical refactor commit.

Migrating to Spring Boot 4 with OpenRewrite

Once Java 25 migration is done, Spring Boot 4 is where OpenRewrite delivers its highest ROI. Spring Boot migrations fail less because of “one big breaking change” and more because of:

  • Starter realignments
  • Property renames
  • Deprecated APIs

The Spring Boot 4 Migration Recipe

org.openrewrite.java.spring.boot4.UpgradeSpringBoot_4_0

This recipe encodes Spring-maintained knowledge about what changed — and what must now be explicit.

What the Boot 4 Recipe Handles

1. Build and Dependency Graph Alignment

  • Upgrades Boot dependencies to 4.0.x
  • Aligns Maven/Gradle plugins
  • Fixes BOM and dependencyManagement drift

No half-upgraded builds. No silent mismatches.

2. Configuration Property Migration

  • Renames deprecated properties
  • Removes properties that no longer exist
  • Updates paths where semantics changed

3. Modular Starter Migration

Spring Boot 4 continues the push toward explicit starters:

  • Monolithic starters → modular ones
  • Removal of unused transitive dependencies
  • OAuth2 consolidation under security namespaces

The result is a smaller, clearer classpath and fewer accidental dependencies.

4. Deprecated API and Test Pattern Cleanup

The recipe removes outdated Boot 3.x patterns, including:

  • Deprecated test annotations
  • APIs that no longer behave correctly

You don’t carry dead patterns into Spring Boot 4.

Running the Spring Boot 4 Migration

mvn rewrite:dryRun

mvn rewrite:run
mvn clean compile
mvn test

As before: one mechanical commit, nothing else.

Recommended Migration Order

Sequencing matters:

  1. Java 21 → 25
  2. Tests
  3. Application starts
  4. Run Spring Boot 4 OpenRewrite recipe
  5. Re-test
  6. Validate runtime behavior
  7. Canary → rollout

When something breaks, you’ll know why.

Final Takeaways

OpenRewrite doesn’t replace testing, observability or engineering judgment. It replaces weeks of mechanical migration toil with deterministic automation.

For teams running multiple services or long-lived monoliths, that’s the difference between:

  • “We’ll upgrade someday”
  • “We upgraded last sprint”

The recipes exist.
The tooling is mature.
The technical debt is compounding.

You can find example of changed code on GitHub.

Originally posted on marconak-matej.medium.com.