[MM’s] Boot Notes — OpenRewrite
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:
- Consistency Every deprecated pattern is migrated the same way, everywhere.
- Auditability Dry runs produce full diffs and reports before anything changes.
- 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:
- Java 21 → 25
- Tests
- Application starts
- Run Spring Boot 4 OpenRewrite recipe
- Re-test
- Validate runtime behavior
- 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.