Java 17, Java 25, and the Future of Maximo Extensions
Series: MAS JAVA EXTENSIONS | Part 6 of 6 (Series Finale)
Read Time: ~19 minutes
🎯 Who this is for: Maximo developers and upgrade leads who have custom Java in their environment — MBO classes, MIF exits, field validators, bean classes — and want to know exactly what the Java 17 runtime does to that code today, what Java 25 in MAS 9.2 means for tomorrow, and what the whole extension story looks like from here.
You have a folder of .java files that has worked for years. Some of it you wrote. Some of it you inherited from a consultant who left in 2019. It compiles, it runs, it validates a work order the way the business asked for a decade ago, and nobody has touched it because touching it is scary. Now the upgrade team says MAS 9.1 runs on Java 17 — and the MAS 9.2 release notes are already talking about Java 25. A small cold feeling settles in: is all of that about to break?
That fear is reasonable, and it is also mostly — not entirely — misplaced. This finale is about the difference between "mostly" and "entirely," because that gap is exactly where a clean upgrade lives. We will cover what the JVM shift actually changes for your extension code, what Java 25 in MAS 9.2 does and does not require of you, and a concrete plan to test and remediate. Then, because this is the last stop on a six-part journey, we will step back and look at why the extension model survived every one of these transitions — and where Maximo customization goes next.
The Runtime Moved Under You
Here is the single most important framing, and it is good news: the JVM upgrades changed the runtime, not the model. Everything you learned across this series — the four-file MBO pattern, MAXOBJECT.CLASSNAME pointing at your set class, PLUS prefixes, the inheritance chain, product.xml, the Customization Archive — is untouched by any JVM upgrade. A Mbo still extends Mbo. super.save() still propagates down the chain. Your custom validation class still hangs off the same field declaration in product.xml.
What moved is the language and runtime standard your bytecode is compiled against and executed on. The timeline is now three LTS steps long:
MAS release — Approx. GA — Java runtime
MAS 9.0 — 2023 — Java 11
MAS 9.1 — June 2025 — Java 17 — required, exclusive baseline for MAS 9.x core + Manage
MAS 9.2 — 25 June 2026 — Java 17 baseline + Java 25 at the platform / AI-Service level (Java 21 for some reference services)
That is the accumulation that matters. Each LTS step tightens the language: Java 17 is stricter about namespaces, stricter about reflection, and less forgiving of deprecated APIs than the Java 8 and Java 11 worlds most Maximo customizations were born in — and Java 25 continues in exactly the same direction.
💡 Key insight: The extension model is the stable interface; the JVM is the volatile implementation underneath it. Your customizations depend on both. The model gives you continuity across a decade; the runtime is what quietly changes beneath a continuous-delivery suite. A clean upgrade is mostly about auditing your dependence on the volatile layer.
What Java 25 in MAS 9.2 Actually Means
This is the part with the most upgrade-day confusion, so let's be precise, because the marketing line and the deployment reality are not the same sentence.
IBM describes MAS 9.2 as a "future-ready platform with Java 25 support." Read that carefully — it is support added, not Java 17 removed:
- Platform services and the AI Service component were upgraded to Java 25. IBM's own AI Service 9.2.0 notes state the component now runs on Java 25, and the MAS 9.2 platform materials list "upgrade to Java 25" (with Java 21 used for certain reference services).
- Manage and your customizations are still on the Java 17 baseline. IBM has published no Manage 9.2 statement that says "the Manage runtime now requires Java 25 and no longer supports Java 17." The Java 17 requirement introduced in 9.1 still underpins Manage extensions and industry solutions.
So the honest, deployment-level reading is this: MAS 9.2 is a mixed Java-17/Java-25 environment. The newer AI and platform services run on Java 25; the Manage runtime that executes your MBOs, your product.xml chain, and your custom Java remains Java 17.
💡 Key insight: For your custom Java, the decision does not change in 9.2: compile and validate on Java 17. Java 25 is the direction of travel, not this release's requirement for Manage code. But every hour you spend making code Java-17-clean is an hour of Java-25 readiness banked, because the two upgrades break the same kinds of things — just more of them.
"So should I skip Java 17 and jump straight to Java 25?"
No. Java 17 is the runtime your Manage extensions execute on in both 9.1 and 9.2. Target it. Treat Java 25 as the horizon you are walking toward, not the ground you are standing on — and write code that will survive the next step by avoiding the very things (deep reflection, internal-API access) that each JVM release encapsulates harder.
What Actually Changes in the JVM
Six categories of change are the ones that surface in real Maximo customizations — first with Java 17, and each one gets stricter, not looser, on the road to Java 25. Most of your code will sail through all six. The risk is concentrated in code that reaches around the framework — direct Java EE calls, reflection, older drivers, scripting engines.
Change — Impact on your extensions
`javax.*` → `jakarta.*` namespace — Any code using Java EE APIs directly must update its imports
JPMS module restrictions — Reflective access that worked silently in Java 8/11 is blocked — and encapsulated harder each LTS
Removed deprecated APIs — ClassNotFoundException or NoSuchMethodException at runtime; the removal list only grows toward Java 25
Tightened security defaults — JDBC / SSL handshakes may fail with older driver configurations
OpenJDK Nashorn — The JavaScript engine was removed — may affect legacy JS automation scripts
BIRT v4.16 — Reporting engine updated in the 9.x line — custom BIRT reports may need adjustment
A few of these deserve a closer look, because they behave differently from what a developer expects.
The namespace shift is a compile-time problem, which is the good kind. If your code imports javax.servlet, javax.xml.bind, javax.mail, or similar Java EE packages directly, those imports move to the jakarta.* namespace. You find every one of these the moment you attempt a Java 17 compile — the compiler simply refuses. That is a mechanical, bounded fix. Note that ordinary MBO code that only touches psdi.* classes does not hit this at all; it only bites code that talks to the enterprise APIs beneath Maximo.
Reflection is the sneaky one, because it fails at runtime, not compile time. Under Java 8 and 11, code that used reflection to reach into non-public fields or internal packages worked with, at most, a warning. Java 17's module system (JPMS) turns many of those warnings into hard failures, and Java 25 encapsulates the JDK internals even more aggressively. If a custom class ever did something clever with setAccessible(true) against an internal Maximo or JDK class, it will compile fine and then throw an access exception when that path executes — possibly only under a specific data condition. This is why "it compiled, ship it" is not a valid test strategy.
Deprecated-API removal is the second runtime landmine. APIs that were merely deprecated in Java 8 are gone in Java 17, and the removal list keeps growing toward Java 25. A call to a removed method compiled into an old JAR surfaces as a NoSuchMethodException or ClassNotFoundException at the exact moment that line runs. Again: compilation from source catches this immediately; a pre-compiled JAR dragged forward unchanged does not.
// Compiles clean, breaks at runtime under Java 17+ if the reflected
// internal is now encapsulated by the module system.
Field cache = someInternalClass.getDeclaredField("_privateCache");
cache.setAccessible(true); // silent in Java 8/11, throws InaccessibleObjectException in 17, harder still in 25
Object value = cache.get(instance);
// The framework-respecting equivalent has no such fragility —
// it uses the public MBO API, which IBM keeps stable across JVMs.
Object value2 = mbo.getMboValue("SOMEATTR");You Only Own Part of the Problem
This is the line that should lower your blood pressure: IBM remediates all PLUS extension code for each JVM as part of the release. Every industry solution and add-on you catalogued in Part 2 — Transportation (PLUST), HSE and Oil & Gas (PLUSG), Spatial (PLUSS), Nuclear (PLUSN), Aviation, Utilities, ACM, Calibration — ships JVM-clean for the release it targets. You do not remediate IBM's code.
Your remediation scope is exactly your own extensions and what you bundle with them:
- Custom Java MBO classes and MBO Set classes
- Custom MIF exit classes (user exits, processing classes on integration objects)
- Custom field validation classes
- Custom bean classes (app bean handlers)
- Any third-party Java libraries bundled inside your customizations
That last bullet is the one teams forget. Your own code might be pristine, but a bundled reporting library, PDF generator, or crypto helper from 2017 can be the thing that trips a JPMS or removed-API failure. Inventory the JARs you ship, not just the classes you wrote — and check that those libraries have releases that keep pace with Java 17 today and Java 25 tomorrow.
How to Test and Remediate — the Eight-Step Plan
The migration path is mechanical and repeatable. Follow it in order; the order matters because each step de-risks the next. Target Java 17 — the Manage baseline for both 9.1 and 9.2.
- Inventory all custom Java classes in your environment. You cannot remediate what you have not catalogued. Include bundled third-party JARs.
- Set up a Java 17 compilation environment — a JDK 17 toolchain matching the MAS 9.x Manage target.
- Attempt compilation and fix every error. This single step surfaces the entire
javax→jakartanamespace class and every removed-API reference. - Update namespace references (
javax.*→jakarta.*) wherever the compiler flagged them. - Remove deprecated API usage — find the modern equivalent for anything the JVM deleted, and prefer public MBO APIs over reflection so the code survives Java 25 too.
- Test under load. Some issues — reflection failures, concurrency-sensitive paths — only surface with concurrent access. A single-user smoke test is not enough.
- Repackage into a Customization Archive compiled against Java 17 (this is the packaging shift from Part 5 — the archive is now your unit of delivery).
- Test in a MAS 9.1 or 9.2 sandbox before production. Validate against the real runtime, not your laptop.
💡 Key insight: Steps 3 and 6 catch two different classes of failure. Compilation catches everything static — namespaces and removed APIs. Load testing catches everything dynamic — reflection blocks and concurrency issues that only appear when a specific code path runs under contention. Skip either and you will meet the failure in production instead.
A useful mental model: compile-time errors are your friends, runtime errors are your enemies. Every problem you can convert from runtime to compile-time — by recompiling from source instead of forwarding a JAR — is a problem you find in an afternoon instead of a Sev 1.
Why the Model Endured While Everything Else Modernized
Step back and look at what this series has walked through. Between Maximo 7.6 and MAS 9.2, nearly everything around your custom Java changed:
- The application server moved from WebSphere to Red Hat OpenShift.
- Deployment moved from dropping a JAR on a file system to a container image.
- Packaging moved from rebuilding an EAR to building a Customization Archive.
- The JVM moved from Java 8 → Java 11 → Java 17 → Java 25 (at the platform edge).
- The delivery cadence moved from multi-year upgrades to continuous delivery.
And through all of it, the thing you actually write — a class that extends Mbo, a set that extends MboSet, a Remote interface, a product.xml declaration — did not change. That is not luck. It is the payoff of a well-chosen abstraction. IBM held the extension interface stable so it could modernize the implementation freely underneath. Your super.save() does not know or care whether it is running on WebSphere or OpenShift, Java 8 or Java 25. It only knows the contract.
That is the deepest lesson of this series, and it is bigger than Maximo: durable interfaces are what make modernization survivable. The teams that got hurt in the MAS transition were the ones who bypassed the model — direct SQL, database triggers, file-system paths, reflection into internals. Every one of those is a dependency on the volatile layer instead of the stable one. Every one of them broke. The teams that stayed inside the MBO API mostly recompiled and moved on — and they will do it again from Java 17 to Java 25 with the same shrug.
The Ten Commandments of Maximo Extension Development in MAS 9
If this series distilled to a wall poster, this is it. Declarative, opinionated, and earned across six parts.
- Thou shalt know where thy class sits in the chain. The class in
MAXOBJECT.CLASSNAMEis the top of the chain, not necessarily thine. - Thou shalt respect the PLUS prefix. Custom code gets its own namespace; never squat on
PLUST,PLUSG, or any letter IBM owns. - Thou shalt call `super`, and know what happens when thou dost. Every layer below runs. That is a feature, not a surprise.
- Thou shalt read `product.xml` before troubleshooting a chain. The control file is the source of truth for what is registered and in what order.
- Thou shalt not bypass the application layer. No direct SQL, no triggers, no file-system paths, no reflection into internals. The MBO API is the only road — and it is the one that survives the next JVM.
- Thou shalt prefer configuration and automation scripts to custom Java. Reserve Java for what genuinely cannot be scripted.
- Thou shalt package as a Customization Archive. The EAR-drop is dead; the archive baked into an image is upgrade-safe.
- Thou shalt compile against the target JVM, from source, every time. Target Java 17 for Manage today; a forwarded JAR hides the errors a recompile reveals.
- Thou shalt test under load in a real sandbox. Reflection and concurrency bugs do not appear in single-user smoke tests.
- Thou shalt let IBM own IBM's code. PLUS extensions are already JVM-clean; remediate only what is thine.
Keep the ones that fit your shop. Argue about the rest. That argument is mature extension practice.
References
- IBM Maximo Application Suite — Releases information (MAS Core 9.2.0, 25 June 2026)
- IBM Maximo IT 9.2 — "Future-ready platform with Java 25 support"
- IBM MAS AI Service component release 9.2.0 — "upgraded to use Java 25"
- What is really new with MAS 9.1 — Java 17 becomes the required baseline (TRM)
- Getting ready to upgrade to MAS — recompile/refactor for Java 17 (IBM Community)
Series Navigation
Previous: — Part 5 — Deploying & Customizing Extensions in MAS 9
Next: — You have reached the end of the series — Back to the series index
About TheMaximoGuys: We help Maximo developers and teams navigate the move to MAS 9 with practical, no-hype guidance grounded in how the platform actually behaves.
Published by TheMaximoGuys | July 2026



