VVersions.dev

Java 17 → Java 21

Java 17 → 21 is the small jump. The module system and encapsulation work is already behind you, so this step is mostly additive: virtual threads, pattern matching for switch, record patterns, sequenced collections, and generational ZGC.

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

Last verified · Updated May 22, 2026

Migrating from Java 17 to 21 is the small LTS step. Strong encapsulation and the removed Java EE modules were already dealt with at 17, so the work here is bumping the toolchain and optionally adopting new features — virtual threads, pattern matching for switch, record patterns, sequenced collections, and generational ZGC.

Why this jump is small

Both 17 and 21 are post-module-system LTS releases, so the disruptive packaging changes are already absorbed. Most projects bump the toolchain, run the build, and ship — then adopt virtual threads and pattern matching incrementally where they help.

Key differences

  • Virtual threads finalized (Project Loom) — cheap blocking I/O, opt-in.
  • Pattern matching for switch and record patterns finalized.
  • Sequenced collections add a uniform first/last API.
  • Generational ZGC improves GC throughput for large heaps.

Files and patterns to inspect

  • pom.xml / build.gradle: compiler release / Gradle toolchain language version.
  • Thread pools and executors that are blocking-I/O bound (candidates for virtual threads).
  • Long instanceof-then-cast chains (candidates for pattern matching).
  • Bytecode libraries (Lombok, ASM, ByteBuddy) for JDK 21 compatibility.
Adopt new features incrementally

Nothing forces you to switch to virtual threads or rewrite switches. Bump the toolchain first, get a green build, then adopt features one module at a time so each change is independently reviewable.

Java LTS support matrix

VersionReleasedLTSSupport status
Java 82014-03-18YesSecurity-only
Java 112018-09-25YesMaintenance
Java 172021-09-14YesActive
Java 212023-09-19YesCurrent
Pattern matching and record deconstruction
// Java 21: pattern matching for switch + record patterns
String describe(Shape s) {
    return switch (s) {
        case Circle(double r)        -> "circle r=" + r;
        case Rectangle(double w, double h) -> "rect " + w + "x" + h;
        case null, default           -> "unknown";
    };
}

Pre-migration checklist

  • Green test suite on Java 17
  • Build toolchain can resolve a JDK 21 distribution
  • Bytecode libraries confirmed JDK 21-compatible
  • A dedicated upgrade branch

Official sources

  • Migration guideJDK 21 Migration Guidedocs.oracle.comreliability 98%

    Backs the breaking-change and migration-step claims.

  • Official docsJDK 21 (Project)openjdk.orgreliability 98%

    Backs the breaking-change and migration-step claims.

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 inspectionRepo inspection prompt
You are helping migrate a Java codebase from java-17 to java-21.

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 executionMigration execution prompt
Migrate this codebase from java-17 to java-21, 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.