Recently we have upgraded the JDK in our project from Java 8 to Java 12 (the latest Java, released in March 2019). Our project is a docker based web application hosted in the AWS cloud, with fronted developed in AngularJS and backend in Java (Dropwizard, Spring, Hibernate), we use Maven as a build tool. In this blog post, I would like to share my thoughts on our recent big story of the Java upgrade from 8 to 12. It was the first such significant upgrade since the beginning of the project in the middle of 2016.

Java release schedule has changed…

The Java schedule release process has changed since the release of Java 9 in September 2017 – now every six months we get a new version of Java. The Java release process is far more Agile now. Java 8 is still widely used and is very popular, but since it is not supported, it becomes necessary to think about upgrading to the latest version of JDK.

Modularity – one of the most significant changes to Java ever

There are a lot of new enhancements and removals between Java 8 and 12, but the biggest one was modularity introduced in Java 9. The whole JDK has been modularized, and in Java 11 some of the modules have been removed from the JDK and moved to separate projects, with this the latest JDK is more lightweight.

Understanding modularity is a key to do a smooth and quick upgrade of JDK in your project. It is worth noting that upgrading to modularized JDK does not mean that you have to modularize your current application (if necessary, you can do this, later, in the future, but it is an entirely separate, optional thing).

What is a module, and how does it affect our upgrading process? A module organizes the code in such a way that it encapsulates some of the classes and it defines what classes it requires. Some of the classes that used to be publicly available on the classpath are not available anymore (they are encapsulated in modules of JDK) – this is the main challenge while upgrading. You have to find some replacements and add them to the pom files in your project. And some of the latest maven artifacts are also modularized (e.g. CXF). To better understand modularity I highly recommend the “Java 9 Modularity: First Look” course by Sander Mak on Pluralsight.

LTS (Long-time support) OracleJDK  vs OpenJDK – think about strategy

Since Java 11, both Oracle and Open JDK are pretty much the same – the main difference is in licensing – for OracleJDK you have to pay for a subscription. But what you get with OracleJDK is that some of the releases are LTS (long-time support, every three years) and in this case, you are not forced to upgrade your JDK every six months, but every three years instead, from LTS to LTS release. OracleJDK 11 is LTS, the next LTS will be OracleJDK 17 in 2021.

A short algorithm of upgrading JDK 8 to JDK 12 in our project

Below I will share with you some of the steps we made during JDK upgrade and the complete list of all the maven artifacts we updated to the latest versions or added completely new ones in our project pom files.

1. Install the latest JDK:

brew cask install Java

and set this as your default JDK:

/usr/libexec/java_home -V
export JAVA_HOME=`/usr/libexec/java_home -v 12`
java -version

2. Upgrade your IDE and build tool (in our case we upgraded the IntelliJ to 2019.1 and Maven to 3.6.0).

3. Try to compile and/or run your project – definitely, you will have to address some errors – some of the modules were removed during modularization in JDK 9 and some module removals in JDK 11 and you will have to add them as new pom or gradle dependencies. Below I attached the list of our maven dependencies and plugins that addressed all the issues in our project – maybe it will be helpful for you. In some unit, integration and functional tests, we encountered some problems with different date accuracy. We also had to rewrite some DB queries in some of our DAO classes from Hibernate Criteria to JPA CriteriaQuery API.

4. Upgrade the build server to JDK12 and Maven 3.6.0.

The table below contains all the dependencies and plugins that had to be updated or added (added because of modularization either of the JDK or dependencies) in our project.

POM Dependencies and Plugins that were updated to latest versions
  • io.dropwizard
    • dropwizard-core 1.3.9
    • dropwizard-auth 1.3.9
  • org.springframework
    • spring-beans 5.1.6.RELEASE
    • spring-context 5.1.6.RELEASE
    • spring-web 5.1.6.RELEASE
  • org.hibernate
    • hibernate-entitymanager 5.4.2.Final
  • org.jacoco
    • jacoco-maven-plugin 0.8.3
  • com.fasterxml.jackson.dataformat
    • jackson-dataformat-xml 2.9.8
  • org.apache.maven.plugins
    • maven-compiler-plugin 3.8.0
    • maven-pmd-plugin 3.12.0
    • maven-surefire-plugin 3.0.0-M3
    • maven-failsafe-plugin 2.22.1
    • spotbugs-maven-plugin3.1.11 (this replaced findbugs-maven-plugin)
  • org.mockito
    • mockito-core 2.25.1
  • org.dbunit
    • dbunit 2.6.0
  • org.projectlombok
    • lombok 1.18.6
  • org.apache.cxf
    • cxf-codegen-plugin 3.3.1
  • org.modelmapper
    • modelmapper 2.3.2
  • org.aspectj
    • aspectjrt 1.9.2
    • aspectjweaver 1.9.2

 

POM Dependencies and Plugins that had to be added (because of JDK modularization and/or project dependencies modularization)
  • javax.xml.bind
    • ojaxb-api 2.3.1
  • javax.xml.ws
    • jaxws-api 2.3.1
  • javax.jws
    • javax.jws-api 1.1
  • javax.activation
    • javax.activation-api 1.2.0
  • org.javassist
    • javassist 3.23.1-GA
  • javax.servlet
    • javax.servlet-api 3.1.0
  • org.apache.cxf
    • cxf 3.3.1
    • cxf-rt-transports-http 3.3.1
    • cxf-rt-rs-client 3.3.1
    • cxf-rt-bindings-soap 3.3.1
    • cxf-core 3.3.1
    • apache-cxf 3.3.1
    • cxf-codegen-plugin 3.3.1
  • com.sun.org.apache
    • jaxp-ri 1.4
  • com.sun.xml.bind
    • jaxb-core 2.3.0.1
    • jaxb-impl 2.3.1
  • com.sun.xml.ws
    • rt 2.3.2
  • org.hibernate
    • hibernate-jpamodelgen 5.4.2.Final
  • com.github.ben-manes.caffeine
    • caffeine 2.7.0
  • com.fasterxml.jackson.datatype
    • jackson-datatype-jsr310 artifact 2.9.8
  • org.codehaus.mojo
    • build-helper-maven-plugin 1.9.1

5 lessons learned

Below is the list of 5 lessons learned by my team while working on the JDK upgrade from 8 to 12.

  1. Understand the modularity introduced in Java 9. Most errors while compiling and running your app for the first time after upgrading to JDK 9 and higher comes from encapsulation and removal of some of the modules from JDK. You have to find replacements and add them to your pom files (use jdeps tool).
  2. Think about JDK upgrade strategy – how often you can do this in your project, and what license of JDK you will use – depending on that you can do upgrades every six months (OpenJDK) or every three years (OracleJDK, LTS).
  3. Try to address all deprecation warnings after the upgrade to the latest JDK– with the next upgrades they will become errors and remember to create a tech debt list with some ideas to do in the future that will come to your mind while working on the upgrade.
  4. Develop all kinds of tests (unit, integration, etc.) in your project since the very beginning – in our case, this made the whole upgrading process much easier for the entire team, saved work and time of developers and testers and greatly reduced manual testing of the application after JDK upgrade.
  5. Properly estimate the upgrade JDK story. A difficult question – how to estimate such JDK upgrade story? We underestimated and gave 2-3 story points, and we all thought that this story would have taken a few days of development at most. In the end, beside JDK upgrade, we also upgraded Dropwizard, Spring and Hibernate frameworks, rewrote quite a lot of our DB queries from Hibernate API to JPA CriteriaQuery API, addressed failing unit, integration and functional tests in all our project maven modules (some of the problems here were related to increased date accuracy), updated all configuration files and scripts associated with deploying to Jenkins/AWS. So finally the whole Java upgrade process took longer than we expected and should have been estimated to 8 story points.

The Java upgrade from 8 to 12 was a huge story for our team because firstly it was the first such big upgrade since the beginning of the project in the middle of 2016, and secondly, we also upgraded other frameworks such as Dropwizard, Spring, Hibernate to the latest versions. As a team, we have gained a lot of experience during the upgrade story, and we are open to sharing our knowledge. If you have any questions related to upgrading of Java or other frameworks, you are always welcome to contact us.