Java Development Kit

The Java Development Kit is an implementation of the Java platform. It provides the Java Virtual Machine (JVM) and the Java Runtime Environment (JRE).

Editions

The JDK exists in different editions:

As Java is evolving and also complex maintaining a JVM requires a lot of energy. Therefore many alternative JDK editions are unable to cope with this and support latest Java versions and according compatibility. Unfortunately OpenJDK only maintains a specific version of Java for a relative short period of time before moving to the next major version. In the end, this technically means that OpenJDK is continuous beta and can not be used in production for reasonable software projects. As OracleJDK changed its licensing model and can not be used for commercial usage even during development, things can get tricky. You may want to use OpenJDK for development and OracleJDK only in production. However, e.g. OpenJDK 11 never released a version that is stable enough for reasonable development (e.g. javadoc tool is broken and fixes are not available of OpenJDK 11 - fixed in 11.0.3 what is only available as OracleJDK 11 or you need to go to OpenJDK 12+, what has other bugs) so in the end there is no working release of OpenJDK 11. This more or less forces you to use OracleJDK what requires you to buy a subscription so you can use it for commercial development. However, there is Adoptium that provides forked releases of OpenJDK with bug-fixes what might be an option.

The easiest way to get all this setup for developers is using devonfw-ide.

Garbage Collection

A key feature of Java is automatic garbage collection (GC). Over time different garbage collectors have been implemented within the JVM. The good news is that usually you do not have to care about all this. However, at some point you might get an OutOfMemoryError or other effects related to GC and heap issues. You should also be aware that when a lot of heap is consumed, a full GC may pause the JVM for some time causing other issues like performance problems or even connection timeouts. Therefore, we strongly recommend you to do continous logging of your GC activity in your environments up to production. These GC logging does not cause relevant overhead so it can be enabled 7x24. Whenever you might have heap issues or a memory leak, you can simply analyze these GC logs. Simply transfer the logs from the environment server to your local machine. As the GC logs do not contain data that is sensitive to your app (regarding GPDR, customer data, etc.) this should be relatively easy to arrange. To analyze these GC logs, we recommend GCViewer. If you are already using devonfw-ide, that integrates all cool developer tools you may need, you can just call this command:

devon gcviewer

In the UI of GCViewer, simply open your GC logfile and you will get a visualization of the heap activity over time. For more details see here.

Thread Dump

Sometimes you may face concurrency issues or even deadlocks where threads block each other. In such case you should create a thread-dump. We even recommend you to create a series of e.g. 3-5 thread-dumps with a short delay of e.g. a minute bettwen each of them. This will help you to trace down problems of waiting or blocked threads.

Upgrading

Until Java 8 compatibility was one of the key aspects for Java version updates (after the mess on the Swing updates with Java2 many years ago). However, Java 9 introduced a lot of breaking changes. This documentation wants to share the experience we collected in devonfw when upgrading from Java 8 to newer versions. First of all we separate runtime changes that you need if you want to build your software with JDK 8 but such that it can also run on newer versions (e.g. JRE 11) from changes required to also build your software with more recent JDKs (e.g. JDK 11 or 12).

Runtime Changes

This section describes required changes to your software in order to make it run also with versions newer than Java 8.

Classes removed from JDK

The first thing that most users hit when running their software with newer Java versions is a ClassNotFoundException like this:

Caused by: java.lang.ClassNotFoundException: javax.xml.bind.JAXBException

As Java 9 introduced a module system with Jigsaw, the JDK that has been a monolithic mess is now a well-defined set of structured modules. Some of the classes that used to come with the JDK moved to modules that where not available by default in Java 9 and have even been removed entirely in later versions of Java. Therefore you should simply treat such code just like any other 3rd party component that you can add as a (maven) dependency. The following table gives you the required hints to make your software work even with such classes / modules removed from the JDK (please note that the specified version is just a suggestion that worked, feel free to pick a more recent or more appropriate version):

Table 47. Dependencies for classes removed from Java 8 since 9+
Class GroupId ArtifactId Version

javax.xml.bind.*

javax.xml.bind

jaxb-api

2.3.1

com.sun.xml.bind.*

org.glassfish.jaxb

jaxb-runtime

2.3.1

java.activation.*

javax.activation

javax.activation-api

1.2.0

java.transaction.*

javax.transaction

javax.transaction-api

1.2

java.xml.ws.*

javax.xml.ws

jaxws-api

2.3.1

javax.jws.*

javax.jws

javax.jws-api

1.1

javax.annotation.*

javax.annotation

javax.annotation-api

1.3.2

3rd Party Updates

Further, internal and inofficial APIs (e.g. sun.misc.Unsafe) have been removed. These are typically not used by your software directly but by low-level 3rd party libraries like asm that need to be updated. Also simple things like the Java version have changed (from 1.8.x to 9.x, 10.x, 11.x, 12.x, etc.). Some 3rd party libraries were parsing the Java version in a very naive way making them unable to be used with Java 9+:

Caused by: java.lang.NullPointerException
   at org.apache.maven.surefire.shade.org.apache.commons.lang3.SystemUtils.isJavaVersionAtLeast (SystemUtils.java:1626)

Therefore the following table gives an overview of common 3rd party libraries that have been affected by such breaking changes and need to be updated to at least the specified version:

Table 48. Minimum recommended versions of common 3rd party for Java 9+
GroupId ArtifactId Version Issue

org.apache.commons

commons-lang3

3.7

LANG-1365

cglib

cglib

3.2.9

102, 93, 133

org.ow2.asm

asm

7.1

2941

org.javassist

javassist

3.25.0-GA

194, 228, 246, 171

ResourceBundles

For internationalization (i18n) and localization (l10n) ResourceBundle is used for language and country specific texts and configurations as properties (e.g. MyResourceBundle_de.properties). With Java modules there are changes and impacts you need to know to get things working. The most important change is documented in the JavaDoc of ResourceBundle. However, instead of using ResourceBundleProvider and refactoring your entire code causing incompatibilities, you can simply put the resource bundles in a regular JAR on the classpath rather than a named module (or into the lauching app). If you want to implement (new) Java modules with i18n support, you can have a look at mmm-nls.

Buildtime Changes

If you also want to change your build to work with a recent JDK you also need to ensure that test frameworks and maven plugins properly support this.

Findbugs

Findbugs does not work with Java 9+ and is actually a dead project. The new findbugs is SpotBugs. For maven the new solution is spotbugs-maven-plugin:

<plugin>
  <groupId>com.github.spotbugs</groupId>
  <artifactId>spotbugs-maven-plugin</artifactId>
  <version>3.1.11</version>
</plugin>
Test Frameworks
Table 49. Minimum recommended versions of common 3rd party test frameworks for Java 9+
GroupId ArtifactId Version Issue

org.mockito

mockito-core

2.23.4

1419, 1696, 1607, 1594, 1577, 1482

Maven Plugins
Table 50. Minimum recommended versions of common maven plugins for Java 9+
GroupId ArtifactId (min.) Version Issue

org.apache.maven.plugins

maven-compiler-plugin

3.8.1

x

org.apache.maven.plugins

maven-surefire-plugin

2.22.2

SUREFIRE-1439

org.apache.maven.plugins

maven-surefire-report-plugin

2.22.2

SUREFIRE-1439

org.apache.maven.plugins

maven-archetype-plugin

3.1.0

x

org.apache.maven.plugins

maven-javadoc-plugin

3.1.0

x

org.jacoco

jacoco-maven-plugin

0.8.3

663

Maven Usage

With Java modules you can not run Javadoc standalone anymore or you will get this error when running mvn javadoc:javadoc:

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-javadoc-plugin:3.1.1:javadoc (default-cli) on project mmm-base: An error has occurred in Javadoc report generation:
[ERROR] Exit code: 1 - error: module not found: io.github.mmm.base
[ERROR]
[ERROR] Command line was: /projects/mmm/software/java/bin/javadoc @options @packages @argfile

As a solution or workaround you need to include the compile goal into your build lifecycle so the module-path is properly configured:

mvn compile javadoc:javadoc

We want to give credits and say thanks to the following articles that have been there before and helped us on our way:

Last updated 2023-11-20 10:37:01 UTC