Java 17 → Java 25
Java 17 → 25 spans two LTS releases but stays on the same modular platform, so it is mostly additive. You pick up everything from Java 21 (virtual threads, pattern matching, sequenced collections, generational ZGC) plus the JDK 22–25 features (scoped values, module imports, flexible constructors, stream gatherers). With Java 17 Premier Support ending September 2026, this is the recommended jump to the current LTS.
Last verified · Updated May 22, 2026
Migrating from Java 17 to 25 crosses two LTS releases but no platform packaging changes — both are post-module-system. The work is a toolchain bump plus optional feature adoption. You inherit the Java 21 additions (virtual threads, pattern matching for switch, record patterns, sequenced collections, generational ZGC) and the JDK 22–25 additions (scoped values JEP 506, module import declarations JEP 511, compact source files JEP 512, flexible constructor bodies JEP 513, stream gatherers JEP 485). Oracle Premier Support for Java 17 ends September 2026, so this is the recommended path to the current LTS.
Why this jump is manageable
The expensive, breaking work — the module system, removed javax.* Java EE modules, strong encapsulation of JDK internals — all landed at or before Java 17. From 17 to 25 there are no new packaging restrictions; you bump the toolchain, get a green build, and then adopt new features at your own pace.
What you gain (Java 18–25, final features)
- From Java 21: virtual threads, pattern matching for switch, record patterns, sequenced collections, generational ZGC.
- Scoped values (JEP 506, final in 25) — safer thread-local replacement for virtual-thread workloads.
- Module import declarations (JEP 511) and compact source files / instance main methods (JEP 512).
- Flexible constructor bodies (JEP 513) — validate arguments before super()/this().
- Stream gatherers (JEP 485, final in JDK 24) — custom intermediate stream operations.
- Generational Shenandoah (JEP 521) and compact object headers (JEP 519) — opt-in footprint/GC wins.
Files and patterns to inspect
- pom.xml / build.gradle: compiler release / Gradle toolchain language version (17 → 25).
- Blocking-I/O thread pools (candidates for virtual threads, available since 21).
- Long instanceof-then-cast chains (candidates for pattern matching for switch).
- Thread-local usage (candidates for scoped values).
- Bytecode libraries (Lombok, ASM, ByteBuddy) for JDK 25 compatibility.
⚠ Java 17 Premier Support ends September 2026
Oracle public updates for JDK 17 moved to the Java SE OTN license in October 2024, and Premier Support ends September 2026. Java 25 is the next permissively licensed LTS — plan the jump rather than letting 17 fall out of support.
ℹ Two LTS releases, still additive
Although you skip Java 21, you are not crossing the module system again. Bump straight to JDK 25, get a green build, and adopt virtual threads and the newer features incrementally. Keep structured concurrency and primitive patterns (preview in 25) out of production paths.
Java LTS support matrix
| Version | Released | LTS | Oracle Premier Support until | Support status |
|---|---|---|---|---|
| Java 8 | 2014-03-18 | Yes | March 2022 | Security-only |
| Java 11 | 2018-09-25 | Yes | September 2023 | Maintenance |
| Java 17 | 2021-09-14 | Yes | September 2026 | Active (Premier ending) |
| Java 21 | 2023-09-19 | Yes | September 2028 | Active |
| Java 25 | 2025-09-16 | Yes | September 2030 | Current LTS |
Bump straight to JDK 25
# Point the toolchain straight at JDK 25 (skipping the 21 stop)
export JAVA_HOME=$(/usr/libexec/java_home -v 25)
java -version
./mvnw versions:set-property -Dproperty=maven.compiler.release -DnewVersion=25
./mvnw clean verifyPre-migration checklist
- Green test suite on Java 17
- 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
Related paths
- Migrate Google AutoValue to Java Records — Related path
- Java 17 to Java 21 Migration Guide — Related version path
- Java 21 to Java 25 Migration Guide — Upgrade path to same target
- Java 8 to Java 17 Migration Guide — Earlier step in the upgrade chain
- Upgrade to Java 21 — Related version path
- Upgrade to Java 25 — Upgrade path to same target
Official sources
- JDK 25 Migration Guide — docs.oracle.com (reliability 98%)
- JDK 25 (Project) — GA 2025-09-16, LTS, feature/JEP list — openjdk.org (reliability 98%)
- Oracle Java SE Support Roadmap — oracle.com (reliability 98%)
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-17 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-17 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
Should I stop at Java 21 first?
Usually no. Java 17 → 25 crosses no platform packaging changes, so a direct toolchain bump is fine for most services. Stopping at 21 only helps if you want to adopt virtual threads and pattern matching in their own reviewable change before taking the JDK 22–25 features.
Is Java 17 → 25 harder than 17 → 21?
Only marginally. It is the same kind of additive, post-module-system step, just with two LTS releases' worth of new features to optionally adopt. The risk is dominated by dependency/bytecode-library compatibility, not by the platform.