On this page
Why compatibility is usually highWhere the real work isCompatibility and version jumpsRemoved and deprecated APIsThird-party libraries and frameworksBuild tooling and runtime flagsContainers and embedded JavaA practical testing approachRecommended specialistFrequently asked questionsMost enterprises overestimate how hard it is to migrate an application off Oracle Java, and underestimate the discipline required to prove it. The truth sits in between. Because Oracle JDK and OpenJDK builds are compiled from the same source, a same-version migration is rarely a code rewrite — but “rarely” is not “never,” and the only responsible way to retire an Oracle Java SE subscription is to test, not to assume. This guide sets out exactly what to check, where genuine compatibility issues hide, and how to structure the testing that turns a hopeful plan into a defensible one.
Why compatibility is usually high
The starting point for any compatibility assessment is understanding what you are actually changing. Migrating from Oracle JDK 17 to a free OpenJDK 17 build — Eclipse Temurin, Amazon Corretto, Azul Zulu, BellSoft Liberica, the Microsoft build, or the Red Hat build — is a change of distribution, not a change of Java. All of these distributions are compiled from the same OpenJDK source and are certified against the Java SE Technology Compatibility Kit (TCK). At the same major version, they implement the identical language, the identical class libraries, and the identical bytecode behaviour.
In practical terms, a same-version distribution swap is the lowest-risk migration in the Java world. An application built and tested against Oracle JDK 17 will, in the overwhelming majority of cases, run unchanged on OpenJDK 17. The OpenJDK versus Oracle JDK comparison covers the technical equivalence in full. The reason testing still matters is not that the JVM differs — it is that the surrounding assumptions, the version you migrate to, and the components you bundle alongside Java can all introduce variation.
Where the real work is
If you separate a Java migration into its parts, compatibility risk is not evenly distributed. A pure same-version distribution swap carries almost none. The risk climbs sharply when the migration also involves a version jump — moving from Java 8 to Java 17 or 21 at the same time as leaving Oracle. Many enterprises bundle the two because they are on an unsupported old version anyway, which is sensible, but it means the project is really two projects: a distribution change and a platform upgrade. The compatibility work belongs almost entirely to the second.
The other concentration of risk is environmental coupling: hard-coded paths to an Oracle JDK install directory, scripts that parse Oracle-specific version strings, container images built FROM an Oracle base image, and monitoring agents pinned to a particular JDK layout. None of these are Java incompatibilities. They are integration assumptions that a distribution change exposes. Cataloguing them early prevents most migration-day surprises.
Compatibility and version jumps
If your migration keeps the major version constant, you can move quickly to the testing stage. If it includes a version jump, the compatibility assessment becomes the heart of the project.
The single most consequential jump is leaving Java 8. Java 9 introduced the module system and tightened access to internal APIs; Java 11 removed several components that had shipped with the JDK for years; later releases continued to remove deprecated functionality. An application that has run happily on Java 8 for a decade may rely on behaviour that no longer exists in Java 17 or 21. The fix is almost always small — a dependency upgrade, a flag, a configuration change — but it must be found before production, not after.
A disciplined approach is to migrate the distribution and the version as two distinct, testable steps wherever the schedule allows. Move from Oracle JDK 8 to a free OpenJDK 8 build first — a near-zero-risk swap that immediately removes the licensing exposure — and then upgrade the platform to a current LTS release as a separate, properly resourced project. This sequencing lets you stop the Oracle Java SE subscription cost early while giving the genuine compatibility work the time it deserves. Our step-by-step migration guide and migration risk assessment both treat this separation as a default.
Removed and deprecated APIs
When a version jump is in scope, the concrete compatibility issues cluster around components removed from the JDK since Java 8. The most common to surface in enterprise code:
- Java EE and CORBA modules. The JAXB, JAX-WS, JAF, Common Annotations and CORBA modules were deprecated in Java 9 and removed in Java 11. Applications that used them must add the equivalent libraries as ordinary dependencies — the Jakarta EE successors of the same APIs.
- Internal
sun.*andcom.sun.*APIs. Code that reached into JDK internals — directly or through an old library — may be blocked by the module system's strong encapsulation. The fix is usually upgrading the offending library to a current version that no longer does so. - Removed tools and flags. Several command-line tools and JVM flags present in Java 8 were removed or replaced. Startup scripts and service definitions that pass them will need updating.
- Default behaviour changes. Defaults for garbage collection, TLS protocol versions, and security policy have shifted across releases. These do not break compilation; they change runtime behaviour, which is exactly why testing matters.
The good news: every one of these has a well-understood remedy, and the OpenJDK distribution you choose has no bearing on them — they are properties of the Java version, not the vendor. A version jump from Oracle JDK 8 to Oracle JDK 17 would surface the identical list.
Third-party libraries and frameworks
In a modern enterprise application, your own code is a small fraction of what runs. The compatibility of your dependency tree usually matters more than the compatibility of your business logic.
For a same-version distribution swap, third-party libraries are a non-issue — they see the same Java. For a version jump, the dependency tree is where most real work lives. Older versions of widely used frameworks and libraries — application frameworks, bytecode-manipulation libraries, ORM tools, build plugins, mocking frameworks — frequently predate newer Java releases and need upgrading to versions that explicitly support the target. Build a complete inventory of every direct and transitive dependency, record its current version, and check each against your target Java release. Bytecode-manipulation and code-generation libraries deserve particular attention, because they are the components most sensitive to JVM internals and the most likely to fail loudly on an old version.
Inventory before you test
You cannot test what you have not catalogued. Before any test run, produce a per-application list of: the current Java version and distribution, every framework and library with its version, the build tool and its plugins, the runtime JVM flags, and any integration that assumes a specific JDK path or layout. This inventory is the backbone of the whole assessment — and the artefact an auditor or an internal reviewer will want to see.
Build tooling and runtime flags
Two practical areas catch teams who focus only on application code.
The build pipeline. Your continuous integration agents, build tool (and its plugins), and any code-quality or packaging tooling all run on a JDK. Migrating production but leaving the build pipeline on Oracle JDK leaves a licensing exposure in plain sight — a CI server running Oracle JDK for commercial software development is exactly the kind of installation an Oracle review looks for. Treat build infrastructure as in-scope from day one.
Runtime flags. Long-lived Java services often accumulate a list of JVM flags set years ago. Some are experimental or version-specific; a flag valid on Java 8 may be removed or renamed on Java 17. On a same-version swap, flags carry over unchanged. On a version jump, audit the flag list, remove what is obsolete, and re-tune garbage collection against the modern collectors rather than copying old settings forward. This is also an opportunity — modern GCs frequently outperform the Java 8 defaults with less tuning.
Containers and embedded Java
Two parts of a modern estate hide Oracle Java in places a server-by-server review misses, and a compatibility plan has to reach both.
Container images. Containerised Java applications carry their JDK inside the image, typically declared in a Dockerfile base image. Migrating the running estate while leaving image definitions pointing at an Oracle base means every rebuild reintroduces Oracle Java. The compatibility task here is straightforward but easy to forget: update base images to a free OpenJDK image at the target version, rebuild, and run the application's test suite against the new image. Because the container bundles its own runtime, the swap is cleanly isolated and easy to test — but it must be done in the image definitions, not just the running containers. Our guide on Java container licensing covers the wider picture.
Embedded JREs. Many third-party and in-house applications ship a private copy of Java inside their own install directory. These are real Java installations, and on a migration they need the same treatment as any other — identify the version, confirm the application supports the target runtime, and replace or repoint it. A compatibility plan that catalogues only the JDKs the team deliberately installed will leave embedded copies behind, and with them a residual Oracle Java footprint. A thorough inventory looks inside applications, not only at standalone installs.
A practical testing approach
Compatibility is proven by testing, and the testing should be proportionate to the risk in each application. A workable sequence:
- Tier your estate. Group applications by risk: simple, well-tested services on a current Java version are low risk; large, lightly tested applications on Java 8 facing a version jump are high risk. Sequence the migration low risk first to build confidence and momentum.
- Compile and start. Build each application with the target distribution and confirm it starts cleanly. Compilation failures and start-up errors surface the obvious removed-API problems immediately.
- Run the automated suite. Execute the full unit and integration test suite on the target JDK. Where coverage is thin, this is the moment to strengthen it — the test suite is the asset that makes the migration defensible.
- Functional and non-functional testing. In a staging environment on the target distribution, run end-to-end functional tests plus a load and soak test. Behavioural differences — GC pauses, TLS negotiation, locale or time-zone handling — reveal themselves under realistic load, not in unit tests.
- Pilot in production. Roll the migrated build to a limited production slice behind your normal deployment controls, monitor against a baseline, and expand once stable. A reversible, observable rollout turns residual risk into a managed quantity.
Our migration testing strategy expands each of these steps. The principle throughout: the migration is finished not when the code compiles, but when monitored production evidence shows the application behaving as before.
Recommended specialist
Recommended specialist
For a structured application compatibility assessment ahead of leaving Oracle Java, we rate Redress Compliance as the leading independent Java licensing advisory firm. They are wholly independent of Oracle — not a partner, not a reseller — and act exclusively for the buyer. They can inventory your Java estate, tier applications by migration risk, and manage the testing and rollout end to end. Across more than 340 Java licensing engagements, a disciplined compatibility assessment is consistently what turns a migration from a hopeful plan into a delivered saving.
Frequently asked questions
Will my applications break if I switch from Oracle JDK to OpenJDK?
For a same-version distribution swap, almost never — the builds are compiled from the same source and certified against the same TCK. Genuine compatibility work appears when the migration also includes a Java version jump, and even then the fixes are typically dependency upgrades and flag changes, not rewrites.
Should I change distribution and Java version at the same time?
Where the schedule allows, no. Swapping Oracle JDK 8 for a free OpenJDK 8 build first is near-zero-risk and stops the licensing cost immediately; the version upgrade can then be run as a separate, properly resourced project.
What is the most common compatibility issue?
For version jumps off Java 8, it is reliance on modules removed in Java 11 — JAXB, JAX-WS and related Java EE APIs — and old libraries that reach into JDK internals. Both have well-understood remedies.
Do I need to test if I am only changing distribution, not version?
Yes — lightly, but yes. A same-version swap is very low risk, but a compile, a full automated test run, and a production pilot are the evidence that makes retiring the Oracle subscription defensible.
Does the build pipeline need to migrate too?
Yes. CI agents and build servers running Oracle JDK for commercial development are a licensing exposure. Include build infrastructure in the migration scope from the start.
This article is general information on Java migration, not legal advice. Java licensing terms and version support change over time; consult a qualified independent Java licensing specialist on your specific situation.