Upgrade to Jakarta EE 10 – part 2: Transform Application Source Code

This entry is part 3 of 4 in the series Upgrading to Jakarta EE 10

In our previous article, we explored the initial steps of migrating Java EE 8 or Jakarta EE 8 applications to Jakarta EE 10. We transformed the final binary application using the Eclipse Transformer to deploy it on a Jakarta EE 10 runtime. Building upon that foundation, we now dive deeper into the next crucial phase of the upgrade process: transforming the application’s source code to use the Jakarta EE 10 APIs. This will enable you to use new features in Jakarta EE 10 as well as newer versions of external libraries that require Jakarta EE 10.

Why do we need tools to migrate from “javax.” to “jakarta.” ?

Although most of the transformation involves replacing imported packages that start with the "javax.” prefix by those that start with “jakarta.” prefix, the whole transformation is not that simple. For example, not all packages with the “javax.” prefix should be transformed, resource files like XML descriptors also need to be transformed, etc. Since Jakarta EE 10 also removed some deprecated APIs, mainly in Jakarta Faces (JSF), source code that uses the removed APIs needs to be refactored to use newer Jakarta EE APIs.

In this article, we’ll focus on transformation related to the changes in Jakarta EE 9 (related to the jakarta. prefix). We’ll explain how to replace APIs removed in Jakarta EE 10 in a future article.

Fortunately, we can automate most of the work to upgrade to Jakarta EE 9. If your application doesn’t use any of the APIs removed in Jakarta EE 10, this will be enough to migrate your source code to Jakarta EE 10. There are 2 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.

We 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. We’ll describe how to use both of these tools so that you can choose which of them you’d like to use.

Automate source code changes with Eclipse Transformer

For a single application, you’ll need to transform the source code only once. It’s not worth changing project configuration just for this single step. Therefore we’ll describe how to use Eclipse Transformer on command line to do this without adding any Maven plugin or configuration to your project. This also means that you can apply this procedure also if you use some other build tool other than Maven, e.g. Gradle.

Follow these steps to transform source code of your application:

  1. Download Eclipse Transformer CLI distribution artifact from Maven Central. Download the distribution.jar file of the latest version, not the plain jar file. For the version 0.5.0, here’s the direct download link: org.eclipse.transformer.cli-0.5.0-distribution.jar
  2. Unpack the JAR file into some directory, e.g. /path/to/transformer
  3. Go to you application’s project directory
  4. Run the following to transform the src directory (with source code, resources, test code and resources, etc…) to output_src directory: java -jar /path/to/transformer/org.eclipse.transformer.cli-0.5.0.jar src
  5. Move the contents of the output_src directory into src (overwrite files). On Linux and Mac OS, you can use RSync command line tool: rsync -a output_src/* src
  6. Edit pom.xml manually:
    • Increase the Jakarta EE version to 10, 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>

After performing these steps, your application source code should be completely compatible with Jakarta EE 9. You can try to build your application now. If your application is simple and without any third party dependencies, it should compile successfully and work well if you deploy it on a Jakarta EE 10 server.

However, it’s very likely you’ll need to do some more steps to finish the transformation, for example:

  • Upgrade third-party dependencies or transform them for Jakarta EE 10
  • Refactor source code to remove usages of APIs removed in Jakarta EE 10 (mainly related to JSF)

We’ll address these steps in future articles.

Alternative: Automate source code changes with OpenRewrite

As an alternative to using Eclipse Transformer, you can use Openrewrite to transform your application source code to be compatible with Jakarta EE 9. Although OpenRewrite produces a bit worse output than Eclipse Transformer and requires some manual actions to fix it, it allows you to create and use custom recipes. This allows for writing a recipe that improves the output of the transformation for Jakarta EE 9 and even add rules to refactor the code for Jakarta EE 10. If you’re willing to invest some effort to do it, it’s possible to enhance OpenRewrite so that it produces even better output than Eclipse Transformer. You could add transformations for APIs removed in Jakarta EE 10 and to upgrade dependencies to Jakarta EE 10 versions, which Eclipse Transformer doesn’t support.

Applying OpenRewrite is very easy. If you already have Maven installed, you can just use it as a Maven plugin configured on command line:

  1. Go to the application’s project directory
  2. 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 deploy on a Jakarta EE 9 runtime. But, based on our experience, at least the following fixes are necessary before you can do it:

  • Fixes in pom.xml:
    • OpenRewrite adds dependencies on each individual Jakarta specification. If you want to continue using the Jakarta Platform API or one of the Jakarta profiles API bundle, remove all jakarta dependencies in pom.xml added by OpenRewrite and just update the main Jakarta API dependency to version 10.0.0. This is the dependency for the Jakarta EE 10 Platform API:
      • <dependency>
        <groupId>jakarta.platform</groupId>
        <artifactId>jakarta.jakartaee-api</artifactId>
        <version>10.0.0</version>
        <scope>provided</scope>
        </dependency>
    • If you already have the jaxb-runtime dependency with “provided” scope, OpenRewrite adds a duplicate dependency on it with “runtime” scope. Remove the dependency added by OpenRewrite so that there’s only one jaxb-runtime dependency
  • Fixes in web.xml:
    • Update references to properties and packages with the “javax.faces.” prefix to the “jakarta.faces.” prefix
    • Update definitions with the “javax.jms.” prefix to the “jakarta.jms” prefix
  • Fixes in MDBs (Message-Driven Beans):
    • In MDB activation properties, update definitions with the “javax.jms.” prefix to the “jakarta.jms” prefix

After all this, there still might be something to update manually but these manual changes should cover most of the cases.

What you can’t automate (yet)

After applying all the automation described in this or in the previous articles, there are still some things to do, which can’t be automated with existing tools:

  • Deal with external libraries that require Java EE 8 or Jakarta EE 8 APIs
  • Refactor code that uses APIs removed in Jakarta EE 10

Sorting out dependencies is very crucial because they often provide non-trivial functionality and their code isn’t under our control. If the application doesn’t require such library at compile time, we can simple apply Eclipse Transformer on the final binary (e.g. WAR file) as described in the previous article and then deploy the application on a Jakarta EE 10 runtime. But if some libraries are required to compile the application, the compilation would fail after we transform the source code because of the change in the package prefix. We have several options to fix that:

  • Upgrade the library to a newer version, if it supports Jakarta EE 10
  • Transform the library with Eclipse Transformer into a new Maven artifact, which our application will use instead
  • Replace the library with some other similar library that supports Jakarta EE 10 and refactor our application to use that library instead

The simplest way is to upgrade the library. Nowadays, new versions of many popular libraries either switched to Jakarta EE 10 or provide a variant of the library that requires Jakarta EE 10. As an example, a very popular library Primefaces provides a Jakarta EE 10 Maven artifact under the “jakarta” classifier, as an alternative to the main artifact that requires Jakarta EE 8. You can use the Jakarta EE 10 variant with the following Maven dependency definition:

<dependency>
  <groupId>org.primefaces</groupId>
  <artifactId>primefaces</artifactId>
  <version>12.0.0</version>
  <classifier>jakarta</classifier>
</dependency>

Transforming a library with Eclipse Transformer is more complicated to set up in your project but may be required if the library doesn’t support Jakarta EE 10 or you’d like to postpone upgrading that library because it’s too risky.

In the future articles, we’ll provide a list of popular libraries that already support Jakarta EE 10 and how to add them to your project. We’ll also explain how to transform dependencies so that their transformed versions are available during compile time. And we’ll also explain how to deal with the breaking changes in Jakarta EE 10, which removed some obsoleted APIs.

Conclusion

Migrating your Java EE 8 or Jakarta EE 8 applications to Jakarta EE 10 involves not only transforming the final binary application but also updating the application’s source code to utilize the Jakarta EE 10 APIs. This enables you to leverage new features and ensure compatibility with external libraries that require Jakarta EE 10.

As we explained, it’s not only about replacing those old “javax.” packages with new “jakarta.” ones. Though, we can automate this to speed up this task and avoid manual errors.

First up, we have Eclipse Transformer, which can automate most of the work. It’s super handy and even takes care of resource files. All you need to do is download it, unpack it, and run the transformation command on your source code directory. If you want to define your own transformation recipes, you can use OpenRewrite instead.

Series Navigation<< Upgrade to Jakarta EE 10 – part 1: Transform Applications with Eclipse TransformerUpgrade to Jakarta EE 10 – part 3: Transform incompatible Dependencies >>

Leave a Comment

Your email address will not be published. Required fields are marked *

Captcha loading...