Java rule S2095 bug reported for java.util.concurExecutorService even though is 17


SQ version: Enterprise EditionVersion 10.3 (build 82913)
SQ scanner version:
JAVA_HOME: /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/21.0.2-13/x64

We’re running SQ scan as part of a GHA workflow, java-version is set to 21. We’re using Maven and execute the scan with mvn sonar:sonar. Property maven.compiler.release is set to 17.

java.util.concurExecutorService starts implementing AutoCloseable with Java 19. SQ scan log says

[INFO] Configured Java source version ( 17, preview features enabled ( false

Or code wouldn’t even compile if we’d us try-with-resource as ExecutorService doesn’t implement AutoCloseable in Java 17. Is this a known problem, are we doing something wrong?

This rule violation was reported after we upgraded to Java 21. While this helped us identify we didn’t call ExecutorService.shutdown() in all possible cases, it’s impossible to fix this issue for SQ. SQ seems to insist the code calls ExecutorService.close()which isn’t available in Java 17. When setting maven.compiler.release to 21 and calling ExecutorService.close() instead of ExecutorService.shutdown() in one location, SQ marks this location as resolved.

1 Like

Hello @bschuhmann, and welcome to the Sonar Community!

If I understand you correctly, you are facing the following situations:

Code is not compiling when using the ExecutorService in a try-with-resource and setting maven.compiler.release to 17.

This is not an issue. According to the Maven specs, it is expected that the compilation generates errors in this case because ExecutorService doesn’t implement Autocloseable in Java version 17.

Code compiled with JDK 21 raises the issue S2095 because the ExecutorService is not closed.

This doesn’t seem to be an issue because the ExecutorService implements Autocloseable in Java version 21. The rule correctly applies since the ExecutorService is expected to be used in a try-with-resource or closed in a finally block.

The Java analyzer relies on the semantics of the compiled code; thus, the rule S2095 will:

  • Raise an issue when the code is compiled with JDK 19+ and the ExecutorService is not closed.

  • Not raise any issue when the code is compiled with JDK <19 and the ExecutorService is used since it is not an Autoclosable resource.

Those are the expected behaviors. The correct solution is to set maven.compiler.release to 21 and replace the ExecutorService.shutdown() with ExecutorService.close().


Hi Angelo, thanks for looking into this!

Also expected behaviour (from user perspective) however is this: if maven.compiler.release is set to 17 and code is compiled with JDK 21, the rule should not raise an issue, which is currently not the case.

You’re saying

The Java analyzer relies on the semantics of the compiled code…

but because maven.compiler.release is set to 17, the compiled code doesn’t have ExecutorService.close() and therefore the rule should not raise any issue - even though the code was compiled by JDK 21 javac. Maybe the Java analyzer doesn’t rely on the compiled code in this case and instead makes assumptions based on the JDK version used, which it shouldn’t?

Setting maven.compiler.release to 21 and compiling with JDK 21 is obviously avoiding the problem, but that’s not what we want - we actually want to compile with JDK 21 but retain language and RT compatibility at Java 17.

1 Like

Hello @bschuhmann, sorry for being inaccurate previously.

The option maven.compiler.release set to 17 ensures that the code does not use any API from JDK versions above 17.

When compiling with JDK 21, the Java binaries from version 21 are downloaded. Thus, the available ExecutorService is from Java version 21. You can quickly check this by looking up the ExecutorService dependency used by the compiled class from within the target folder.

The Java analyzer finds the ExecutorService that implements Autoclosable, thus, it raises an error for not closing it.