Our (bumpy) road to Jakarta EE 10
Quarkus has been relatively silent on the Jakarta EE front until a few weeks ago, compared to some other frameworks who announced early clear plans with timelines. That doesn’t mean we were not actively preparing the transition and we have been incredibly busy making it a reality.
Most of you should have heard now about the coming EE 9/EE 10 transition in the Java ecosystem:
It is mostly known for the
jakarta.package change as it is the most visible change.
But Jakarta EE 10 comes with new features added to the specifications, and of course the implementations.
It might be obvious by now but we decided to skip Jakarta EE 9 entirely.
Jakarta EE 9 is a
import jakarta.* rebadged version of EE 8 with no real additional features.
Sure it can serve as a first step of a transition but it is also extremely disruptive for application developers:
They have to rework their codebase to switch from the
javax.packages to the
They need to make sure all their dependencies are actually supporting the new packages. Which wasn’t the case at first but the situation has vastly improved.
While we think EE 9 had a lot of value for framework developers (more on that a bit later), the value for application developers is far from being obvious.
Thus why we decided to skip it entirely in Quarkus, as far as our users are concerned.
So skipping Jakarta EE 9, right? Well, actually, no. We won’t publish any Jakarta EE 9-based version of Quarkus but… Jakarta EE 9 has actually been extremely useful in our migration process. It doesn’t change the APIs so it was considered a good first step of our migration process.
So we decided to target Jakarta EE 9, first.
As mentioned previously, the migration of Quarkus to Jakarta EE 9/10 is extremely disruptive:
Adjusting the packages, the service loader files can be relatively well automated thanks to the Eclipse Transformer. But of course it is not as simple for a code base as large and as complex as Quarkus. For instance, we do a lot of code generation in Quarkus and we had for instance hardcoded references in some generated code signatures (e.g.
Ljavax/enterprise/util/AnnotationLiteral<L%1$s;>;L%1$s;) which weren’t transformed.
We also had to adjust a ton of dependencies with various strategies:
Completely new projects
New versions, new artifacts, new projects might come with changes that require adjustments on the Quarkus side.
Updating dependencies might require adjusting our banned dependencies rule to make sure we do not end up with old EE 8 based dependencies.
Thus, we had to go through the whole set of Quarkus modules, in order, to make all the adjustments necessary to have them compiling and at least the basic tests passing.
The size and the complexity of the Quarkus project made things harder than what you would expect for your typical project. So if you are an application developer, the transition will be far easier and less traumatic, especially since we will provide tooling to automate most of the transition.
At this point, you might have understood that this process took several months to come up with a sorta working state, and that, while most adjustments are trivial, the changes are huge. Finally you might also have realized that we didn’t want to have a bunch of commits and rebase - and fix a gazillion of conflicts - every day.
That is why we have a migration process:
we have a transformation script that we run on top of Quarkus
We publish a branch and we run CI on it.
We do that daily to make sure nothing breaks the transformation.
The output of this (tedious yet interesting) work comes in multiple forms:
We applied patches directly in the
mainbranch to make the transformation easier and more reliable.
We have a set of OpenRewrite recipes to adjust our POM files (versions, artifacts, …).
We have our own fork of OpenRewrite as some of the behaviors were not compatible with how we had to do things (we contributed most of our changes to the OpenRewrite project though), mostly because of the complex structure of the Quarkus project.
We use the Jakarta Eclipse Transformer to rewrite most of the classes and service loader files.
We have a
transform.shscript to orchestrate and execute all that is needed, including some manual adjusments. This script is not particularly pretty but it works. And the fact that we run CI daily will catch any issue anyway.
That is with Jakarta EE 9. Now let’s have some fun with Jakarta EE 10.
This is our ultimate target for Quarkus 3. Jakarta EE 10 comes with some API changes and for, some of them, they require adjustments in the Quarkus codebase.
This is typically the case for CDI and our implementation ArC, or JAX-RS for which we made changes to both RESTEasy Classic and RESTEasy Reactive.
We decided it wasn’t a good idea to implement these API changes with OpenRewrite recipes and we went for a more simple approach: we are maintaining branches with these changes that we apply on top of our migration process.
Maintaining these branches is not a lot of work as the adjustments are not in areas where we do a lot of changes.
We are in a state where you can actually test this work and report back. We have also started making the extension ecosystem ready for Quarkus 3.
I will post the 3.0.0.Alpha1 announcement soon with more details instructions.
As mentioned in blog post explaining our plan for Quarkus 3, we will be releasing Alphas of Quarkus 3 starting now.
Except if a blocking issue is discovered:
We will release a new 3.0.0.AlphaX every month.
As a rule of thumb, each alpha will be based on
2.y.3.Finalof each minor version so will have the same feature set.
We will incorporate other changes along the way, such as the move to Hibernate ORM 6 or the move to the Flow API.
All the "code" for this work is published in the
jakarta root folder of the Quarkus repository.
You can consume it in several ways:
Use the Alphas we publish monthly.
Use our snapshots, they are published daily to https://s01.oss.sonatype.org/content/repositories/snapshots/ with the
jakarta-rewritebranch yourself, it is published daily with the result of the transformation from current
You can find more information about it in the README.md of the