Support for the `jakarta` namespace in Axon Framework 4.6

I don't blame you if you don't know what that means. Frameworks like Spring do a great job of preventing developers from knowing what's under the hood. That's the price to pay for convenience, I guess. But whether you are aware or not, most "modern & fancy" techs (Spring included) rely on some of the good old Java EE specifications and their respective implementations. So is Axon Framework. And there's been a long-ignored change in that space that we finally addressed.

A few months after releasing 4.6, we realized we could duplicate the annotations. From 4.7, we support `jakarta` this way, which means parts of this blog are outdated. If you are currently on 4.6, you might need to do some additional things to move to a newer version. We created a section in the reference guide to help you out. For anyone starting a new project, the latest version of Axon should work fine with Jakarta and Spring Boot 3, without any specific configuration needed.

The background

The above-mentioned significant change in the Java Enterprise space occurred a few years back. It's a consequence of Oracle donating Java EE to the Eclipse Foundation and the name changing to Jakarta EE. Since then, the larger Java community has been evolving the (42 as of Jakarta EE 10) specifications. Previously, many of the classes and interfaces defined in those specifications were located in sub-packages of the javax package. The namespace was used in many XML schemas too. Unfortunately, Oracle and the Eclipse Foundation did not reach an agreement allowing the community to modify the javax package namespace further. So in Jakarta EE 9, a replacement parent package was introduced - jakarta. New versions of the specifications forced their implementations to, sooner or later, make a significant breaking change in the respective codebases. Unsurprisingly many postponed implementing the latest versions for as long as possible.

The overall impact area

The change had a massive impact on almost all projects. Here are just the most popular specs with breaking changes :

  • Java Servlet
  • Java Server Pages
  • Java Faces
  • Java Messaging
  • CDI
  • Java XML Binding
  • Java XML Web Services
  • EJB
  • JAX-RS
  • JPA
  • JTA

If you are curious, here is an almost complete list of what needs to be replaced with what. 

The problem is manageable for products directly using one or a few specs. The true nightmare is when you depend on several libraries that exchange objects in those namespaces. It's not possible to upgrade one without upgrading all the others. This means upgrades need to wait until all dependencies support the new namespaces.  

The impact on Axon Framework

Most of the specifications mentioned above are out of the scope of Axon Framework. However, some features (state-stored aggregates, tracking tokens, persisting projections, etc.) use the JPA and JTA specifications to allow developers to put data in and query from relational databases. In such cases, the framework expects developers to add respective dependencies and configure proper instances of javax.persistence.EntityManager, javax.transaction.TransactionManager, and similar types. This is where the usage of the old namespace introduces issues. For example, it is impossible to use Axon Framework 4.5.x or earlier with newer versions of Hibernate (6.0.0 onwards). Furthermore, using any 3rd party libraries depending on the newer JPA and JTA implementations is also next to impossible.

As if that is not enough, the apparent solution - changing the package names - is not a solution. Doing so would make it impossible to use older versions of any 3rd party libraries and frameworks that still depend on the javax packages. The most notable example is Spring Framework. Thus, there needs to be a solution that allows developers to pick which package names they want to use.

The solution

As you may know, Axon Framework is a modular framework. Doing some analysis revealed that the namespace change impacts only three modules. Namely:

  • messaging
  • modeling
  • eventsourcing

So, much like many other frameworks, we decided to build and release a <NAME>-jakarta versions of those. But that introduces a problem with maintainability and evolvability. Duplicating the code means every functional change touching those areas would have to be done twice. Every test covering those areas would have to be cloned too.

Solving problems like this is where Eclipse Transformer comes in handy. This great tool (kudos to BJ Hargrave and everyone who worked on it) allows you to transform Java binaries, making changes to packages, type names, and related resource names. And it works like a charm. If you look at the source code of messaging-jakarta, modelling-jakarta, and eventsourcing-jakarta modules, you'll see nothing more than a POM and some properties.  During build time, the Maven plug-in uses the classes compiled by the original modules, replaces the names in the bytecode, and generates the respective <NAME>-jakarta versions. It also does this to the test classes, enabling us to run all the existing tests with the new namespaces. We went even further and applied the same approach to the integrationtests-jakarta module to ensure proper end-to-end testing after the bytecode changes.

How to use it

There are two popular ways to include Axon Framework in a project. 

If you are using Spring/SpringBoot, nothing really changes. At the time of writing, the Spring Framework does not support the jakarta namespace (according to their announcement, the change is planned for version 6, scheduled for Q4 2022). Thus the respective Spring modules in Axon Framework still depend on the original messaging, modeling, and eventsourcing modules.

If you are configuring Axon Framework yourself, starting with version 4.6.0, you have two options. You could keep using the original config module and stick to the javax namespace. To use the jakarta namespace, you simply replace the dependency in your POM with the config-jakarta module. That's it - an eight symbols difference.

What the future holds

I'm super happy and proud we found a way to introduce such a valuable improvement in a non-invasive, backward-compatible way without increasing the maintenance efforts.  

Assuming there are no significant hidden drawbacks waiting to be discovered, we'll stick to the approach for the upcoming releases. Long-term though, we'll likely make the jakarta namespace the default. Especially when we start providing support for Spring 6, that will be a necessary and expected move. Whether, at that point, there will still be a need for support for javax packages remains to be seen. We may, for example, reverse the process and provide <NAME>-javax autogenerated backward-compatible modules if that is the case. 

What's even more exciting about the future is that now we can help developers in many more ecosystems. The work on a Jakarta CDI 4 compatible extension is already in progress. I can't wait to see Axon Framework providing location transparency in various Quarkus, Micronaut, and Helidon microservices. Or be used to design the domain model or provide valuable "memories" to enterprise solutions based on one of the many Jakarta EE implementations

I'll keep you posted as things evolve. Stay tuned!

Milen Dyankov
Developer Advocate. Milen helps fellow Java developers to design and build clean, modular and future proof software. His primary focus is on advocating for developer communities.
Milen Dyankov