Migrating from JDK 11 to JDK 17: An Overview and Practical Guide

JDK Jun 23, 2023

Introduction:
Migrating all the java based microservices without impacting the business is a challenge. In this article we discuss the need for migrating to Java 17, planning the migration, steps involved during migration and our learnings during the migration. We will also cover the advantages of migrating from JDK 11 to JDK 17 and provide a step-by-step guide to help you migrate your Java microservices to JDK 17.

Why migrate to JDK 17?
The Java Platform, Standard Edition 17 Development Kit (JDK 17) is a feature release of the Java SE platform. It contains new features and enhancements in many functional areas.

Currently at Halodoc most backend services are written in Java using JDK11.

There are several reasons to migrate from JDK 11 to JDK 17 as outlined below:

  1. Improved performance and stability: JDK 17 introduces many new features, optimizations, and bug fixes that can enhance the performance and stability of your applications.
  2. Better security: JDK 17 provides more secure defaults and new security features to help protect your applications from vulnerabilities.
  3. New language features: JDK 17 introduces several new language features, such as sealed classes, pattern matching, and switch expressions, which can improve code readability and maintainability.
  4. Support for newer technologies: JDK 17 includes updated support for newer technologies, such as HTTP/2, TLS 1.3, and Unicode 13.0.
  5. Long-term support: JDK 17 is a long-term support (LTS) release, which means that Oracle will provide support and updates for it for an extended period (until at least September 2029). This can provide greater stability and predictability for your application development and maintenance.

Strategies and Planning for JDK 17 Migration:

1. Prioritize Common Libraries:

  • Start by migrating common libraries to Java 17.
  • Address any compatibility issues or necessary updates specific to these libraries.
  • Resolve any potential conflicts or disruptions during this phase.

2. Migration of Dependent Microservices:

  • Once the common libraries are successfully migrated, proceed with migrating dependent microservices.
  • These microservices can leverage the updated and compatible versions of the libraries.
  • This streamlined approach minimizes potential conflicts and disruptions during the migration process.

Migrating Java11 micro-services to Java17:

Environment Setup:

  1. Update your Java Development Kit (JDK) to version 17: Download and install the latest version of the JDK 17 from the OpenJDK website or through your package manager.
  2. Set the JDK 17 installation directory as your default JDK by updating your PATH environment variable. You can do this by adding the JDK 17 bin directory to your PATH variable. On Unix-based systems, you can edit the /etc/environment file and add the following line:

3. Check your project dependencies: Use a dependency management tool like Maven or Gradle to verify that all of your project's dependencies are compatible with Java 17. You can check the compatibility of each dependency by checking the project's documentation or release notes.

4. Update your project configuration files: In your project's configuration files (such as pom.xml for Maven or build.gradle for Gradle), update the Java version to 17. For example, if using Maven, update the <maven.compiler.target> and <maven.compiler.source> properties in the pom.xml file to version 17.

pom.xml file

5. Update Maven Surefire Plugin:Update the Surefire plugin version to a version that supports JDK 17. Add or update the maven-surefire-plugin configuration within the <build><plugins> section of your pom.xml file. For example:

6. Update your code: After updating your project configuration files, update your code to remove any code that is deprecated or removed in Java 17. You can use tools like your IDE's code analyzer, or external static code analysis tools, to help identify deprecated or removed code.

7. Update Docker file with Java 17 image.

Docker sample file pointing to JDK17 image

8. Update Jenkins file if using as a automation tool.

Jenkinsfile

9. To align with the default settings in JDK17, kindly adjust the run file for your project by removing the AggressiveOpts flag if it has been explicitly specified.

10. Test your code: Run your project's tests to verify that everything is working as expected. You can use automated testing tools like JUnit or TestNG to run your tests. Make sure to test all critical functionality of your application to ensure that there are no compatibility issues.

Note : It is crucial to emphasise the importance of thorough testing throughout the migration process. Before migrating your Java microservices from JDK 11 to JDK 17, it is essential to ensure that all unit, integration, and system tests pass successfully. This step is necessary to verify that your application functions as expected and that there are no compatibility or regression issues introduced by the JDK upgrade.
Similarly, after the migration is completed, it is vital to re-run all tests to confirm that the application remains stable and fully operational in the new JDK environment. This comprehensive testing helps identify any potential issues or discrepancies that may have emerged during the migration process.

11. Deploy and monitor: Deploy your application to your development or testing environment and monitor it for any issues. This is a good time to make any necessary performance optimizations, especially if your application is processing large amounts of data or has many users.

12. Production deployment: Once you have verified that your application is running smoothly in your development or testing environment, deploy your application to your production environment. Monitor your application carefully and address any issues that arise.

Challenges:

  • Guice 5.0.1 lacks support for Java 17. However, upgrading to version 5.1.0 provides support for Java 17.
  • Versions of Lombok prior to 1.18.22 do not support Java 11 or Java 17. Therefore, it is necessary to upgrade all previous versions to 1.18.22 or newer.
  • Powermock, being a deprecated project, is not compatible with Java versions beyond 8. Therefore, we should utilize Mockito instead.
  • The Surefire plugin needs to be version 2.21.0 or higher to be compatible with Java 17.
  • The migration process encountered an error during the forked process, resulting in the following error message:

Upon analyzing the pom file of the respective service, it was determined that the error was caused by a conflicting dependency named Jmockit, which was in conflict with Mockito. To resolve this issue, we upgraded the Jmockit version to 1.41 or grater. This update successfully resolved the error, allowing us to proceed with the project build.

  • During the migration process to JDK 17, we encountered the following error:

This error indicates that the class org.redisson.config.SingleServerConfig$Creator4JacksonDeserializera0f42aa4 attempted to access a method, void org.redisson.config.SingleServerConfig.<init>(), resulting in an IllegalAccessError. The issue arises from the class being in an unnamed module of the com.fasterxml.jackson.module.afterburner.util.MyClassLoader, while org.redisson.config.SingleServerConfig is in the unnamed module of the loader 'app'.

The issue was successfully resolved by avoiding conflicts between Redisson and Jackson dependencies. By analyzing the project dependencies, it was identified that the error was triggered by a clash between the Redisson library and the Jackson library. To resolve this conflict, we carefully examined the dependency versions and made necessary adjustments to ensure compatibility between Redisson and Jackson.

Upon updating the dependencies and aligning the versions, the java.lang.IllegalAccessError error was resolved. This allowed us to proceed with the migration process smoothly, without any further issues related to the Redisson and Jackson libraries.

Conclusion:

Migrating from JDK 11 to JDK 17 offers several benefits, such as access to new language features, improved performance optimizations, enhanced security, and bug fixes. However, it is essential to thoroughly plan and test the migration process to ensure a smooth transition.

In this article, we have taken a step-by-step approach to migrating a microservice from JDK 11 to JDK 17. We also discussed some of the challenges that we faced during migration and how we overcame them.

References:

Join us

Scalability, reliability and maintainability are the three pillars that govern what we build at Halodoc Tech. We are actively looking for engineers at all levels and if solving hard problems with challenging requirements is your forte, please reach out to us with your resumé at careers.india@halodoc.com.

About Halodoc

Halodoc is the number 1 all around Healthcare application in Indonesia. Our mission is to simplify and bring quality healthcare across Indonesia, from Sabang to Merauke.
We connect 20,000+ doctors with patients in need through our Tele-consultation service. We partner with 1500+ pharmacies in 50 cities to bring medicine to your doorstep. We've also partnered with Indonesia's largest lab provider to provide lab home services, and to top it off we have recently launched a premium appointment service that partners with 500+ hospitals that allows patients to book a doctor appointment inside our application.
We are extremely fortunate to be trusted by our investors, such as the Bill & Melinda Gates foundation, Singtel, UOB Ventures, Allianz, Gojek and many more. We recently closed our Series B round and In total have raised USD$100million for our mission.
Our team work tirelessly to make sure that we create the best healthcare solution personalised for all of our patient's needs, and are continuously on a path to simplify healthcare for Indonesia.

Jayendra Dubey

Software Development Engineer, Back End | Building Halodoc