Best Practices To Deal With Javax to Jakarta Migration
In this post, I’ll explain everything you need to know to upgrade to Jakarta EE 9+ successfully and in almost no time.
Join the DZone community and get the full member experience.
Join For FreeUpgrading to Jakarta EE 9 or newer from an older version of Jakarta EE or Java EE can be a bit tricky with the javax
to jakarta
prefix change. Some libraries may be still using the javax
package, which can cause conflicts when trying to run your applications on a Jakarta EE server like Eclipse GlassFish 7. You will likely encounter the same issues when upgrading to Spring Framework 6 or Spring Boot 3, Quarkus 3, and newer versions of many other frameworks, which now depend on Jakarta EE 9 APIs.
But don’t worry, I’ve got you covered! In this post, I’ll explain everything you need to know to upgrade to Jakarta EE 9+ successfully and in almost no time. By Jakarta EE 9+, I mean either Jakarta EE 9 or 10, which is currently the latest version of Jakarta EE.
Existing Tools To Automate Upgrade Steps
Fortunately, many of the challenges can be automated using free and open-source tools like Openrewrite, WindUp, and Eclipse Transformer. Openrewrite is a powerful tool that can automatically make changes to your application's source code, such as updating all references to the old javax
packages with the new jakarta
prefix.
Eclipse Transformer can do the same job, but it can also transform the final JAR, WAR, or EAR binary files in case your project is not ready for source code transformation yet. This is useful if you just want to try running your older application on a Jakarta EE 9+ runtime.
All these tools can save you time and effort when upgrading to Jakarta EE 9+, allowing you to focus on other important aspects of your application's development. However, it's still important to review and test the changes made by these tools to ensure that they don't introduce any unintended consequences.
Transform Applications With Eclipse Transformer
I recommend starting every migration with Eclipse Transformer so that you can quickly verify whether your application can be migrated to a Jakarta EE 10 runtime without changes or identify potential problems for the migration. Using Eclipse Transformer might also be essential in the later stages of your migration, especially if your application relies on dependencies that are not yet compatible with Jakarta EE 9+ or if it’s risky to upgrade them to a compatible version. In the end, transforming your application with Eclipse Transformer before you deploy it to a Jakarta EE 9+ runtime can work as a safety net, detecting and transforming any remaining classes and files that depend on older API packages. You can keep using Eclipse Transformed until you’re absolutely sure everything in your application has been migrated.
To demonstrate the ease of using Eclipse Transformer, we at OmniFish have prepared a sample application project at javax-jakarta-transform-whole-war
. This project showcases how to apply Eclipse Transformer to the build of a Maven project.
The key ingredient to applying the transformation in a Maven project is the Maven plugin transformer-maven-plugin. This plugin can be installed as an extension, and then it can hook into the standard Maven build mechanism and modify the final build artifact.
The Maven plugin provides two goals:
jar
– this goal transforms application packages, like JAR, WAR, and EAR files. It can either modify them in place or create their transformed version in a separate filetransform
– this goal transforms directories (before they are packed into JAR, WAR, or other application packages). It can be used on exploded directories before they are deployed to an app server
The example application uses both plugin goals. The jar
goal is used to transform the final artifact file, which is required to deploy the file later or deploy it to a Maven repository. The transform
goal is optional and is used to transform the exploded directory, which is often used during development by various IDEs to deploy the application. Using the transform
goal is optional but makes it easier to develop the application and deploy it easily from your IDE until it is fully migrated to Jakarta EE 9 and Eclipse Transformer is needed no more.
Besides using it as a Maven plugin, Eclipse Transformer can be also used on the command line and thus with any project or a continuous integration system.
To run Eclipse Transformer on the command line, first download the org.eclipse.transformer.cli distribution JAR file from Maven Central. Then, unpack this JAR, for example, into a folder named transformer
. Then you can transform your application file, for example, jakarta-ee-8-app.war
, into a new application file jakarta-ee-10-app-transformed.war
with the following command:
java -jar transformer/org.eclipse.transformer.cli-0.5.0.jar jakarta-ee-8-app.war jakarta-ee-10-app-transformed.war
The file to transform doesn't have to be a WAR file. It can be a directory, WAR, JAR, and many other package types that the Eclipse Transformer supports.
You can find more information on how to use Eclipse Transformer on the command line on the Github project. However, in most cases, you wouldn’t need anything else; the tool does a very good job, even with the default options.
Transform Dependencies Incompatible With jakarta
Prefix
Now, you'll need to upgrade or transform individual libraries used by your application. This solves two problems. First, it improves the build time of your application during development by removing the step to transform the final binary after each build. Second, it solves compilation problems you can face with some libraries after you adjust the source code of your application for Jakarta EE 9.
Libraries that have a version compatible with Jakarta EE 9 can be simply updated to this version. Most of the libraries widely used in enterprise projects already support Jakarta EE 9. However, some libraries maintain support for both Jakarta EE 9+ and older Jakarta EE and Java EE versions. Those libraries have two variants for the same library version. You'll need to choose the variant that supports Jakarta EE 9+. If you use Maven, then, in most cases, you'll need to use the jakarta
classifier like this:
<dependency>
<groupId>org.primefaces</groupId>
<artifactId>primefaces</artifactId>
<version>13.0.0</version>
<classifier>jakarta</classifier>
</dependency>
But it's not the case for every library. Some libraries provide the Jakarta EE 9 compatible Maven artifact under completely different coordinates, and you'll need to do some research to find them.
When it’s not possible to upgrade a library, you can transform individual libraries with the Eclipse Transformer using a similar technique to transforming the whole application WAR, which we explained in a previous article. You can use the Eclipse Transformer also on individual library JARs and then use the transformed JARs during the build. However, in modern Maven or Gradle-based projects, this isn’t straightforward because of transitive dependencies. There’s currently no tooling that would properly transform all the transitive dependencies automatically and install them correctly to a local repository. But you can use a trick – you can merge all JARs that need to be transformed into a single JAR (Uber JAR) with all the transitive dependencies, then transform it, and then install this single JAR into a Maven repository. Then, you’ll only need to change the application POM file to depend on this single artifact instead of depending on all the individual artifacts that were transformed.
You’ll need to create a new Maven project, e.g., transform-depenendencies
, next to our existing project. Then move all the dependencies you need to transform into this new project. Then remove all those dependencies from the original project and replace them with a single dependency on the new transform-depenendencies
project.
In the final WAR file, instead of having each JAR file separately in the WAR, like this:
- WEB-INF
- classes
- jasperreports.jar
- quartz.jar
- classes
We will end up with a single transformed JAR like this:
- WEB-INF
- classes
- transform-dependencies.jar
- classes
This transform-dependencies.jar
file will contain all the artifacts merged into it – it will contain all classes and files from all the artifacts.
In order to achieve this, we can use the Maven Shade plugin, which merges multiple JAR files into a single artifact produced by the project:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<shadedClassifierName>jakarta</shadedClassifierName>
<shadedArtifactAttached>true</shadedArtifactAttached>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"/>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
This plugin takes all the dependencies defined in the project, merges them into a single Uber JAR, and attaches the JAR to the project as an artifact with the jakarta
classifier.
Now we add the Transformer plugin to transform the Uber JAR to make it compatible with Jakarta EE 9+. We need to configure the Transformer plugin with the following:
- execute the goal “jar”
- use the “jakartaDefaults” rule to apply transformations for Jakarta EE 9
- define artifact with the classfier “jakarta” produced by the shade maven plugin. This will have the same groupId, artifactId and version as the current project
You'll need to build the transform-dependencies
project only once with mvn install
to transform the dependencies into a single artifact in your local Maven repository. When you build the original application project, it will use the transformed Uber JAR and add it to the final WAR instead of all individual (untransformed) JARs. Of course, this will likely introduce compilation failures because your source code still uses the Javax prefix. There's an easy solution to fix that, which I'll describe in the next section.
Transform Application Source Code
Yes, you could fix the compilation errors in your source code manually or with some simple find-and-replace mechanism. But I don't recommend that. Not all packages with the “javax.
” prefix should be transformed; resource files like XML descriptors also need to be transformed, etc. It's much easier and more bulletproof to use automation tools designed to transform code for Jakarta EE 9.
There are two free tools that can help us here:
- Eclipse Transformer – we used it earlier to transform the final application, but it’s also capable of transforming Java source files and resources
- Openrewrite – a tool that can automatically make changes to your application’s source code based on specified rules. It contains rules for Jakarta EE 9.
I recommend using Eclipse Transformer also for this step because it has a more complete set of transformation rules for Jakarta EE 9 than Openrewrite and can transform some resource files that Openrewrite ignores. However, the end result is very similar even with Openrewrite. You would just need to make a few additional manual changes to the source code if you use it instead. I’ll describe how to use both of these tools so that you can choose which of them you’d like to use.
For a single application, you’ll need to transform the source code only once. It’s not worth changing the project configuration just for this single step. Therefore we’ll describe how to use Eclipse Transformer on the command line to do this without adding any Maven plugin or configuration to your project. This also means that you can apply this procedure if you use some other build tool other than Maven, e.g., Gradle.
Follow these steps to transform the source code of your application:
- Download Eclipse Transformer CLI distribution artifact from Maven Central. Download the
distribution.jar
file of the latest version, not the plainjar
file. For the version 0.5.0, here’s the direct download link: org.eclipse.transformer.cli-0.5.0-distribution.jar - Unpack the JAR file into some directory, e.g.
/path/to/transformer
- Go to your application’s project directory.
- Run the following to transform the
src
directory (with source code, resources, test code and resources, etc…) tooutput_src
directory:java -jar /path/to/transformer/org.eclipse.transformer.cli-0.5.0.jar src
- Move the contents of the
output_src
directory intosrc
(overwrite files). On Linux and Mac OS, you can use RSync command line tool:rsync -a output_src/* src
- Edit
pom.xml
manually because the Eclipse Transformer doesn't do this:- Increase the Jakarta EE version to 9.0.0 or 10.0.0, so that your project depends on the following dependency (or an equivalent Web Profile or Core Profile dependency):
<dependency>
<groupId>jakarta.platform</groupId>
<artifactId>jakarta.jakartaee-api</artifactId>
<version>10.0.0</version>
<scope>provided</scope>
</dependency>
- Increase the Jakarta EE version to 9.0.0 or 10.0.0, so that your project depends on the following dependency (or an equivalent Web Profile or Core Profile dependency):
As an alternative to using Eclipse Transformer, you can use Openrewrite to transform your application source code to be compatible with Jakarta EE 9.
Applying OpenRewrite is very easy. If you already have Maven installed, you can just use it as a Maven plugin configured on the command line (note that your project doesn't have to be Maven-based, Maven is only required to run the transformation):
- Go to the application’s project directory
- Execute the following command:
mvn -U org.openrewrite.maven:rewrite-maven-plugin:run \
-Drewrite.recipeArtifactCoordinates=org.openrewrite.recipe:rewrite-migrate-java:LATEST \
-Drewrite.activeRecipes=org.openrewrite.java.migrate.jakarta.JavaxMigrationToJakarta
This will modify your application in place. Theoretically, it should be possible to build it now, and all should work as expected. But, based on my experience, I had to apply a few fixes in a Maven-based WAR project in pom.xml, web.xml, and Java annotations, which I didn't need to do after using the Eclipse Transformer.
Conclusion
After performing these steps, your application should be completely compatible with Jakarta EE 9. You can remove the transformation of your final application to save build time if all the non-transformed dependencies are compatible with Jakarta EE 9.
We needed to do these three steps:
- (optional step) Transform the final application using Eclipse Transformer and test if it runs with Jakarta EE 9+ server or framework.
- Upgrade dependencies to versions compatible with Jakarta EE 9.
- Transform dependencies using Eclipse Transformer if they can't be upgraded to Jakarta EE 9.
- Transform the application source code using Eclipse Transformer or OpenRewrite.
- (optional step) Remove transformation of the final application.
After all these steps are done, you should be able to build your application now. It should compile successfully and work well if you deploy it on a Jakarta EE 9+ server or run it with your framework of choice. Your project is fully transformed into Jakarta EE 9+, and you can continue working on it as before, as if it was designed for Jakarta EE 9+ since the beginning.
Published at DZone with permission of Ondro Mihalyi, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments