Moving to Java 25: What Actually Breaks, and Why Oracle JDK 21 Forces the Question Now
Oracle JDK 21 updates move to the OTN licence from the October 2026 patch cycle. Here's what really changes between Java 21 and 25, from the Security Manager to native-access warnings, and a checklist
Java 25 has been out since 16 September 2025, and most vendors treat it as a long-term support (LTS) release. Plenty of teams have left it on the "next quarter" list for a year. Two things on Oracle's own Java SE support roadmap make this month a sensible time to stop putting it off.
The first is licensing. Oracle says update releases of Oracle JDK 21, "beginning with the October 2026 Critical Patch Update (CPU)", are planned to be offered under the Java SE OTN license, the same license that already covers Java 8, 11 and 17. Put simply, the free-to-use window for Oracle JDK 21 updates is closing with this month's patch cycle. Oracle JDK 25, by contrast, is offered under the free licence until updates released after September 2028.
The second is support. On the same roadmap, Oracle Premier Support for Java 17 ran until September 2026. Java 26 was superseded the same month, when Java 27 shipped.
None of this means Java 25 "broke" older Java. Java's compatibility record is still among the best of any mainstream platform, and most application code compiles and runs on 25 unchanged. What has changed since 21 is a short list of runtime behaviours. They won't show up in a compile step, but they will show up on the first production start. That list is what this post covers.
What changed between 21 and 25 that can stop an application
Here are the changes I'd check first, all from the JDK Enhancement Proposals (JEPs) that delivered them.
The Security Manager is gone for good (JEP 486, JDK 24)
The Security Manager can no longer be enabled at startup or installed at runtime. This one is a hard failure, not a warning. If a command line still includes -Djava.security.manager=allow, or any other value that tries to enable it, the JVM "reports an error and exits" with "Enabling a Security Manager is not supported". The JEP says plainly that this error can't be suppressed or downgraded to a warning.
Code that calls System.setSecurityManager now gets an UnsupportedOperationException.
Most server code never used the Security Manager. The JEP itself notes it has "rarely been used to secure server-side code". The places it does turn up are older plugin hosts, some application servers, scripting sandboxes and build tooling. A start script copied forward from 2015 is exactly where a stray flag survives. -Djava.security.manager=disallow (the default since JDK 18) is still accepted.
Warnings about native code (JEP 472, JDK 24)
When code on the class path loads a native library or binds a native method, the JVM now prints a warning on standard error, at most once per module. It looks like "WARNING: A restricted method in java.lang.System has been called". The program keeps running. The JEP says plainly that this is a first step: "Rather than issue warnings, a future JDK release will throw exceptions by default."
This matters for integration and industrial software, because native code is how a lot of Java talks to hardware. Serial-port libraries, USB and fieldbus drivers, vendor SDKs shipped as a JAR plus a .so or .dll, and compression and crypto accelerators all go through it. You can grant access explicitly with --enable-native-access=ALL-UNNAMED (or by module), or with an Enable-Native-Access: ALL-UNNAMED entry in an executable JAR's manifest. The JEP recommends running with --illegal-native-access=deny now to find every place that will need it.
Warnings about sun.misc.Unsafe memory access (JEP 498, JDK 24)
The first time anything calls one of the memory-access methods in sun.misc.Unsafe, the JVM now prints a warning. Those methods were deprecated for removal in JDK 23. The plan in the JEP is explicit: "JDK 26 or later will throw an exception whenever a memory-access method is used." Java 25 still only warns. But the libraries that trigger this warning are usually serialisation, networking and caching libraries deep in your dependency tree, so this is the time to find out which ones they are and whether newer versions have moved to the supported replacements (VarHandles and the Foreign Function & Memory API).
No more 32-bit x86 (JEP 503, JDK 25)
JDK 25 removes the source code and build support for the 32-bit x86 port. The JEP's reasoning is blunt: "No new 32-bit-only x86 hardware is being manufactured." Other 32-bit architectures, including ARM32, are explicitly out of scope and unaffected. The Windows 32-bit x86 port had already been removed earlier (JEP 479).
For most companies this is a non-event. For anyone running Java on an old industrial PC, a thin client or a 32-bit gateway image, it's a hardware conversation, not a flag to flip. Better to find those boxes now than during an upgrade window.
Why these slip past testing
Three of the four items above produce a warning on Java 25, not a failure. Warnings go to standard error. In a lot of deployments, standard error ends up in a log file nobody reads, or in a container log that gets rotated away. The application works, the upgrade gets marked done, and the real break turns up a release or two later, when the warning becomes an exception.
The Security Manager change goes the other way. It's an immediate hard stop, but it lives in start scripts, service definitions and container entrypoints, not in source code. Static analysis of the repository won't find it if the flag is in a systemd unit on the server.
The licensing decision is a separate one
If you run Oracle JDK 21 in production, the October 2026 CPU is the point where staying current with Oracle's builds means accepting the OTN licence terms. The roadmap says those terms are free only for "Personal, Development and other Users". In practice you have three options:
- Move to Oracle JDK 25, which Oracle offers under its free licence until updates released after September 2028.
- Stay on Java 21 but switch distribution. OpenJDK builds of 21 are available from several providers (for example Eclipse Temurin, Amazon Corretto and Azul Zulu), each with its own support timeline.
- Stay on Oracle JDK 21 under a commercial agreement with Oracle.
What you shouldn't do is let it happen by default: someone pulls the latest Oracle JDK 21 installer into an image, and you end up running on terms you never reviewed. I'm not a licensing adviser, and the licence text is what counts. Have whoever owns your vendor agreements read the actual terms for your situation.
Option 2 and an upgrade to 25 aren't mutually exclusive. Many teams will sensibly switch distribution now to remove the licence pressure, then move to 25 on their own schedule.
A checklist for this month
1. Inventory every JVM you run. Record the version and the vendor for each service, scheduled job, edge gateway and desktop tool. java -XshowSettings:properties -version prints both java.version and java.vendor. Don't forget JREs bundled inside third-party products.
2. Mark every Oracle JDK 21 instance and decide its path. Move to 25, change distribution, or license it. Write the decision down per system, with an owner and a date.
3. Search start scripts, not just source, for java.security.manager. Check shell scripts, systemd units, Windows service wrappers, Dockerfiles, Kubernetes manifests, JAVA_TOOL_OPTIONS and JDK_JAVA_OPTIONS. Any value other than disallow stops Java 25 from starting.
4. Do a warnings run on Java 25 in staging. Start each service on 25 with --illegal-native-access=deny and --sun-misc-unsafe-memory-access=deny, exercise the main paths, and collect every failure. Each one is a dependency to upgrade or a native-access grant to add on purpose.
5. Make standard error visible. Route JVM standard error into the same log pipeline and alerting as application logs, at least during the upgrade. Count the WARNING: lines per service. That number should go down over time, not be ignored.
6. Look for 32-bit x86 hosts. If you run any i386/i686 Linux images or 32-bit JREs on old industrial PCs, list them. They can't move to 25, and the plan for them is new hardware or a different runtime.
7. Pin the runtime in every image. Name an exact JDK vendor and version in Dockerfiles and installers, and update it on purpose. The goal is that next September's version news is a calendar item, not a surprise.
Looking further ahead
Oracle's roadmap names Java 29, in September 2027, as the next planned LTS. That's one more reason not to let the 21-to-25 move drag on for another year. The warnings that 25 prints are a list of the breakages you'll otherwise meet on 29, handed to you two years early.
Sources
- Oracle Java SE Support Roadmap (licensing notes and support dates)
- OpenJDK: JDK 25 project page (GA date and JEP list)
- JEP 486: Permanently Disable the Security Manager
- JEP 472: Prepare to Restrict the Use of JNI
- JEP 498: Warn upon Use of Memory-Access Methods in sun.misc.Unsafe
- JEP 503: Remove the 32-bit x86 Port
- Azul: Java 21 end of free commercial use FAQ
If you'd like a clear map of every JVM, its vendor and its upgrade path before you commit to one, that's a two-week discovery and audit sprint. Book a discovery call.