Tuesday, May 15, 2018

ConcurrentHashMap bug compiling on Java 8 for Java 7

It's been a long couple of months, but I'm back with another quirky discovery.

TL;DR - we changed all declarations of ConcurrentHashMap to Map.

The current project has a number of components. Some are to be deployed on a Java 7 runtime, others make use of newer capabilities on a Java 8 runtime. While trying to streamline the build process using Jenkins, this issue came up while I was switching over from Java 7 to 8. We'd normally assume that it'd suffice for Maven to build with the specific major version in mind using maven.compiler.source and maven.compiler.target configured either in the POM or over the command line. Despite these additions, the runtime would still complain of the following error somewhere in our codes:

java.lang.NoSuchMethodError: java.util.concurrent.ConcurrentHashMap.keySet()Ljava/util/concurrent/ConcurrentHashMap$KeySetView;

A bit of searching turned up this post that explained

Notably the Java 1.7 ConcurrentHashMap#keySet() returns a Set<K> while the 1.8 ConcurrentHashMap#keySet() returns a ConcurrentHashMap.KeySetView<K,V>.

The OP then proceeded to suggested to simply edit the declaration of the ConcurrentHashMap to Map as a workaround.

Other solutions I found mentioned
  1. configuring the -bootclasspath of the Maven build path to point to the rt.jar of the older JDK;
  2. setting up a separate Jenkins/Maven for both halves of the project targetting different Java versions;
Both solutions are not feasible essentially because besides the fact that I'm unwilling to break up the Jenkins for the components using Java 7 and 8 respectively, such a differentiation would eventually get lost in translation, and anybody on the team that tries building similarly on their own (using any combination of JDK/Maven/IDE) may still encounter the same problem unwittingly, thereby costing even more man-hours to investigate and fix.

Editing the declaration would still seem less painful in the long run.

Digging further turned up a bug report which was closed as "Not an issue". The workaround suggested was not exactly helpful, compared to the first article I'd located, but apparently it was related to JSR166.