Java 21 to Java 25 Upgrade Guide (with AI Prompts)

Java 25 shipped as an LTS release in September 2025. If you are already on Java 21 LTS, the jump is mostly smooth — most new features were previews in 21 that are now final — but there are a handful of deprecations, build-tool bumps, and behavioural tweaks that will trip you up if you do not prepare. This guide walks through the upgrade end-to-end with a migration checklist and AI prompts to automate the tedious parts.

Step 1 — Bump Your Build Files

The first thing to change is your compiler release target. For Maven, update all three properties to avoid split-brain between source, target, and bytecode version:

<!-- Maven (pom.xml) -->
<properties>
    <maven.compiler.source>25</maven.compiler.source>
    <maven.compiler.target>25</maven.compiler.target>
    <maven.compiler.release>25</maven.compiler.release>
</properties>

// Gradle (build.gradle.kts)
java {
    toolchain {
        languageVersion.set(JavaLanguageVersion.of(25))
    }
}

Use maven.compiler.release (not just source/target) — it sets the cross-compilation flag correctly and rejects internal APIs from older JDKs at compile time.

Step 2 — Upgrade Core Dependencies

Java 25 is stricter about annotation processor and bytecode enhancer compatibility. These are the minimum versions you need:

  • Spring Boot 3.4+ — first version to officially support Java 25 across the whole starter ecosystem.
  • Hibernate 7.x — drops the old CGLib-based bytecode enhancer; requires Jakarta EE 10 (jakarta.* packages, not javax.*). See Hibernate Tutorials for migration patterns.
  • Lombok 1.18.34+ — earlier versions fail on Java 25’s updated annotation processor APIs. Check the Lombok changelog for any annotation changes.
  • JUnit 5.11+ / JUnit 6 — JUnit 6 is the recommended runner; compatible with the virtual-thread executor.
  • Mockito 5.12+ — required for virtual-thread-safe mocking and Java 25’s updated reflection model.

Step 3 — Remove Preview Flags

Structured concurrency (JEP 505) and scoped values (JEP 506) were preview in Java 21; they are final in Java 25. Delete --enable-preview from your Maven/Gradle compiler args and from any java launch scripts or Dockerfiles. Unnamed patterns and unnamed classes are also final in 25.

Step 4 — Watch for Breaking Changes

The following changes are the most likely to break existing code silently or loudly:

  • Security Manager is gone. If your code calls System.setSecurityManager(), it now throws UnsupportedOperationException at runtime. Replace with OS-level sandboxing or Java agents.
  • sun.misc.Unsafe memory methods deprecated for removal. Use java.lang.foreign.MemorySegment (final since Java 22, JEP 454) instead.
  • Thread.stop / suspend / resume removed. These methods were deprecated for 20+ years and are now gone entirely.
  • Finalization removed by default. Replace Object.finalize() overrides with try-with-resources or java.lang.ref.Cleaner.
  • JNI warnings on stderr by default. Audit any native libraries your project loads. The warning is not fatal but indicates upcoming stricter enforcement.
  • Stricter strong encapsulation. Some internal JDK APIs accessible via --add-opens in Java 21 may now require explicit module declarations.

Step 5 — Adopt the New Features

Upgrading without adopting new idioms is half the job. These are the highest-value migrations:

  • ThreadLocal → ScopedValue — structured, immutable, and much cheaper on virtual threads.
  • Pooled executors → virtual threads — swap I/O-bound FixedThreadPool for newVirtualThreadPerTaskExecutor().
  • instanceof chains → pattern-matching switch — exhaustive, null-safe, and works with records and sealed hierarchies.
  • CompletableFuture.allOf → StructuredTaskScope — automatic cancellation, proper error propagation, and readable fan-out/fan-in.

Migration Checklist

  • Update maven.compiler.release or Gradle toolchain to 25.
  • Run jdeps --jdk-internals on every module jar to find internal API usage.
  • Remove --enable-preview everywhere (compiler args, Dockerfiles, run scripts).
  • Upgrade Spring Boot, Hibernate, Lombok, JUnit, Mockito to minimum compatible versions.
  • Replace all SecurityManager usage.
  • Replace finalizers with Cleaner or AutoCloseable.
  • Run the full test suite; fix reflection-breakage and module-access errors.
  • Switch I/O-bound executors to newVirtualThreadPerTaskExecutor().
  • Migrate ThreadLocal to ScopedValue where thread scope is not needed.
  • Enable GraalVM CE / native-image builds if applicable; Java 25 ships improved native-image support.
  • Measure startup time and GC pause times — Java 25 ships with improved ZGC generational mode.

AI Prompts You Can Use

Each prompt below is designed for a specific upgrade task. Paste it into Claude, ChatGPT, or Gemini and attach the relevant file(s):

Prompt 1 — Upgrade pom.xml

What it does: Rewrites your Maven build file to target Java 25 in a single AI-generated diff, bumping all the common framework versions simultaneously. Saves the tedious cross-referencing of compatibility matrices.

When to use it: At the very start of the upgrade — get the build green first, then deal with code changes.

Here is my pom.xml targeting Java 21. Update it to target Java 25. Bump Spring Boot to the latest 3.x, Hibernate to 7.x, Lombok to the latest, JUnit to 6.x, Mockito to 5.12+. List any dependency that does not have a Java 25 compatible version and suggest alternatives.

Prompt 2 — Find Breaking Changes

What it does: Scans a Java file for the specific API removals and deprecations that are most likely to break in Java 25: SecurityManager, Thread.stop/suspend/resume, Object.finalize, sun.misc.Unsafe memory methods, and old java.net.URL constructors. Produces a prioritized fix list.

When to use it: After bumping the compiler release — most breaks will surface here before you ever run the tests.

Scan this Java file for usages of SecurityManager, Thread.stop/suspend/resume, Object.finalize, sun.misc.Unsafe memory methods, and the old java.net.URL constructors. For each finding, provide a Java 25 replacement with a before/after code snippet.

Prompt 3 — Remove Preview Flags

What it does: Reviews a Maven or Gradle build file, removes all --enable-preview compiler and runtime arguments, and explains which features each flag was enabling — and whether those features are now final or were dropped entirely in Java 25.

When to use it: Once your dependencies are updated and the project compiles on Java 25, run this to clean up preview flags.

Review the attached Maven/Gradle build file and remove all --enable-preview compiler and runtime args. Explain which features they were enabling and whether any now need different handling in Java 25.

Prompt 4 — Modernize Idioms

What it does: Applies four Java 25 idioms to an existing file in one pass: records for data carriers, pattern-matching switch for type checks, sequenced collection APIs (getFirst/getLast), and ScopedValue instead of ThreadLocal. All changes preserve the original behaviour.

When to use it: After the project is green on Java 25 — this is the “nice to have” modernization pass that makes the codebase idiomatically Java 25.

Apply these Java 25 idioms to this file: records for data carriers, pattern-matching switch for type checks, sequenced collection APIs (getFirst/getLast), and ScopedValue instead of ThreadLocal. Preserve behaviour exactly and add a comment for each change explaining why the new form is preferred.

Prompt 5 — Virtual-Thread Safety Audit

What it does: Checks a class for the four patterns that cause problems when you flip to a virtual-thread executor: synchronized blocks around I/O (carrier pinning on Java 21–24), ThreadLocal usage, JNI calls, and code that implicitly assumes a bounded thread count. Returns a risk report with line numbers.

When to use it: Before switching any executor to newVirtualThreadPerTaskExecutor() — always audit first.

Before I flip my executors to virtual threads on Java 25, audit this class for: synchronized blocks around I/O (pinning), ThreadLocal usage, JNI calls, and any code that assumes a bounded thread pool. Report risks with line numbers and a severity (blocking/warning/low).

Prompt 6 — Upgrade Checklist Runner

What it does: Treats your entire project as input and produces a prioritised, risk-grouped upgrade checklist — blocking items (compile/test failures), warnings (deprecations and behavioural changes), and nice-to-haves (modernization opportunities) — with a rough developer-hours estimate for each group.

When to use it: At the beginning of a team upgrade to align on scope and schedule before writing a single line of code.

Act as a Java 25 upgrade reviewer. Given the attached project files, produce a prioritized checklist of upgrade tasks, group them by risk (blocking / warning / nice-to-have), and estimate effort in developer-hours per group.

See Also

FAQs

Can I skip Java 21 and go straight from Java 17 to Java 25?

Yes, but you will hit both the 17→21 and 21→25 changes simultaneously. The combined breakage surface is larger and harder to debug. Use the companion AI Prompts Playbook to work through each stage separately, even if you compile against Java 25 from the start.

Does IntelliJ IDEA support Java 25?

Yes — IntelliJ IDEA 2025.2 and later has full Java 25 language support, including pattern-matching switch, records, scoped values, and structured concurrency. Eclipse and VS Code (via the Language Server for Java) also have Java 25 support as of mid-2025.

Will Spring Boot 3.3.x work on Java 25?

It may compile and run for basic functionality, but Spring Boot 3.4 is the first version with official, tested Java 25 support. Running on an untested combination risks subtle issues with auto-configuration, Hibernate bytecode enhancement, and reflection-based injection. Upgrade Spring Boot first.

Conclusion

The Java 21 → 25 jump is the easiest LTS upgrade in years. Bump your build, remove preview flags, update Spring Boot / Hibernate / JUnit, and let the AI prompts above do the line-by-line modernization. The reward is final-form virtual threads, scoped values, structured concurrency, and a faster ZGC — all changes you would want to make anyway. The six-step checklist gives you a safe rollback point at each stage.

Further Reading

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.