VVersions.dev

Java 21 → Java 25

Java 21 → 25 is the small LTS-to-LTS step. Both are post-module-system releases, so it is a toolchain bump plus optional adoption of features finalized in JDK 22–25: scoped values, module imports, flexible constructor bodies, stream gatherers, and generational Shenandoah.

Version upgradeDifficulty: moderateEffort: 0.5–3 days for a typical servicemedium risk

Last verified · Updated May 22, 2026

Migrating from Java 21 to 25 is the small LTS step. The module system and encapsulation work is long behind you, so the work here is bumping the toolchain and optionally adopting features that became final in JDK 22–25 — scoped values (JEP 506), module import declarations (JEP 511), compact source files and instance main methods (JEP 512), flexible constructor bodies (JEP 513), and stream gatherers (JEP 485, final in JDK 24). Generational Shenandoah (JEP 521) and compact object headers (JEP 519) are available as opt-in runtime flags.

Why this jump is small

Java 21 and 25 are both LTS releases on the same modular platform, so there are no packaging surprises. Most projects bump the toolchain, run the build, and ship — then adopt scoped values, module imports, and flexible constructors incrementally where they help.

Key differences (final in JDK 22–25)

  • Scoped values (JEP 506) — immutable, inheritable per-task values; a safer thread-local replacement that fits virtual threads.
  • Module import declarations (JEP 511) — 'import module M;' imports all of M's exported packages.
  • Compact source files and instance main methods (JEP 512) — lighter single-file programs.
  • Flexible constructor bodies (JEP 513) — statements before super()/this() for argument validation and preparation.
  • Stream gatherers (JEP 485, final in JDK 24) — custom intermediate operations via Stream.gather.
  • Generational Shenandoah (JEP 521) and compact object headers (JEP 519) — opt-in GC/runtime improvements.

Files and patterns to inspect

  • pom.xml / build.gradle: compiler release / Gradle toolchain language version (21 → 25).
  • Thread-local usage that could become scoped values, especially around virtual threads.
  • Verbose import blocks that a module import declaration could collapse.
  • Constructors with awkward static-helper workarounds for pre-super() validation.
  • Bytecode libraries (Lombok, ASM, ByteBuddy) for JDK 25 compatibility.

ℹ Keep preview features out of production

Structured concurrency (JEP 505) and primitive types in patterns (JEP 507) are still preview in JDK 25. Bump the toolchain and adopt the final features first; only reach for preview APIs behind --enable-preview, and expect their APIs to change in later releases.

Java LTS support matrix

VersionReleasedLTSOracle Premier Support untilSupport status
Java 82014-03-18YesMarch 2022Security-only
Java 112018-09-25YesSeptember 2023Maintenance
Java 172021-09-14YesSeptember 2026Active (Premier ending)
Java 212023-09-19YesSeptember 2028Active
Java 252025-09-16YesSeptember 2030Current LTS

Statements before super() are now legal

// Java 25: flexible constructor bodies (JEP 513) — validate before super()
class PositivePoint extends Point {
    PositivePoint(int x, int y) {
        if (x < 0 || y < 0)                       // prologue runs before super()
            throw new IllegalArgumentException("negative");
        super(x, y);
    }
}

Pre-migration checklist

  • Green test suite on Java 21
  • Build toolchain can resolve a JDK 25 distribution
  • Bytecode libraries confirmed JDK 25-compatible
  • No reliance on preview APIs without --enable-preview
  • A dedicated upgrade branch

Official sources

Copy-ready AI prompts

Structured prompts for an AI coding assistant. Inspect first, then execute incrementally, and keep a human in the review loop.

Repo inspection: Repo inspection prompt

You are helping migrate a Java codebase from java-21 to java-25.

Do not edit files yet. First inspect the repository and report:
1. The current source/target Java version in Maven (maven-compiler-plugin <release>/<source>/<target>) or Gradle (sourceCompatibility / toolchain languageVersion).
2. Usage of removed Java EE modules (javax.xml.bind/JAXB, javax.jws/JAX-WS, javax.activation) that must become explicit dependencies.
3. Reflective or direct access to JDK internals (sun.misc.Unsafe, sun.*, reflection into java.* internals) that strong encapsulation will block.
4. Build/toolchain versions: Maven, Gradle, and key plugins (compiler, surefire, shade) plus bytecode-manipulating libraries (Lombok, ASM, ByteBuddy, cglib) that must be bumped.
5. The build, test, and run commands.

Return: a migration risk summary, the modules/classes most likely to break, a suggested migration order, the commands to run before editing, and any questions that need human confirmation.

Safety: Inspection only. The agent must not modify files in this step.

Works with Claude Code, Cursor, GitHub Copilot.

Migration execution: Migration execution prompt

Migrate this codebase from java-21 to java-25, one concern at a time.

Work in this order and pause for review after each: (1) install the target JDK and point the build toolchain at it, (2) set the compiler 'release' flag to the target major, (3) add explicit dependencies for any removed javax.* modules surfaced during inspection, (4) bump Lombok and other bytecode-manipulating libraries to versions that support the target JDK, (5) add the minimum --add-opens/--add-exports flags only where strong encapsulation blocks required reflection, (6) fix remaining compile and test failures.

After each step run the project's build and test commands and report results before continuing. Do not refactor unrelated code.

Safety: Apply changes incrementally and keep each step reviewable. Prefer fixing encapsulation violations over blanket --add-opens. Never bundle unrelated refactors.

Works with Claude Code, Cursor, GitHub Copilot.

Test plan

Commands

  • java -version
  • ./mvnw -version
  • ./mvnw clean verify
  • ./gradlew build

Manual checks

  • Startup: launch the app and confirm no InaccessibleObjectException or NoClassDefFoundError from removed javax.* modules.
  • Serialization: exercise any JAXB/JAX-WS marshalling paths now backed by external dependencies.
  • Reflection: verify frameworks doing reflective access (Jackson, Hibernate, Spring) start without illegal-access errors.

Regression risks

  • Removed Java EE modules (JAXB/JAX-WS) failing at runtime rather than compile time.
  • Older Lombok or ASM/ByteBuddy versions that cannot parse newer bytecode.
  • Reflective access into JDK internals broken by strong encapsulation.

Acceptance criteria

  • Clean build and full test suite pass on the target JDK.
  • No InaccessibleObjectException or illegal-access warnings at startup.
  • All bytecode-manipulating and serialization libraries resolve to target-JDK-compatible versions.

Frequently asked questions

Do I have to adopt scoped values or module imports?

No. They are additive language and API features. Bump the toolchain to JDK 25, get a green build, and adopt scoped values, module imports, and flexible constructor bodies module by module where they improve the code.