CRC32C, JDK 17 and Netbeans
Even though the source level of /some/source/path is set to: 17, java.util.zip.CRC32C cannot be found on the system module path:
This one took me hours.
A while ago I migrated a major project to JDK17 and made many adjustments to ensure further development on it could be done in the latest Netbeans 17. As NB17 is bleeding edge, I regularly check the IDE log to make sure it’s not having a hard time. Unfortunately, doing almost any editing of the project caused warnings such as the message at the top of this post to appear. Hundreds of them. Flooding the log.
This didn’t cause any problems with my ANT build on Jenkins, but I noticed it was making Netbeans pause from time to time, and it worried me that this might also affect dev-time diagnostics and so on. I needed to figure out what was causing the logged message, and if I could stop it.
An online search, unfortunately, showed that this problem is just as perplexing to others, and despite some interesting theories nobody could offer an explanation, solution or work-around.
As my instance of Netbeans 17 is compiled from source by me, I had the source at hand to investigate. Tracking down the message to JavacParser.java was easy, but it revealed (over a thousand lines into the file) that the warning is a consequence of the parser deciding that the source should be downgraded to 1.8.
No, can’t be having that!
The next few hours led me down a rabbit hole of configuration nonsense. I was adamant that any fix I was going to determine would not require me rewriting Netbeans, as then either I’d have to apply a patch every time I updated/recompiled the source, or I would have to submit the change to the core Netbeans project. As the latter would mean I’d have to consider possible consequences way outside of my limited use cases, this was not an option.
One thing that puzzled me was the fact that the message ended with “the system module path:
” but was followed by a blank. No path was actually identified. Looking at the JavacParser
source I could see that the moduleBoot
variable was empty. This then led me to more time wasted trying to find ways to set that variable via external configuration, with the hope that if I could do that then I could point it at the JDK 17 modules (specifically the jmods/java.base.jmod
file where the CRC32C.class
file is located). I did not succeed, so I started climbing out of the rabbit hole in the hope that there might be another approach.
Indeed there was another approach. The key test determining the downgrade to 1.8 accompanied by the warning message was of the form:
!hasResource("java/util/zip/CRC32C", new ClassPath[] {moduleBoot}, new ClassPath[] {moduleCompile, moduleAllUnnamed}, new ClassPath[] {srcClassPath})
I had been concentrating on the new ClassPath[] {moduleBoot}
part, mainly because this is what was specifically mentioned in the warning message. However, the logic of the hasResource()
method revealed that it was searching for CRC32C.class
within the module path or the compile/unnamed paths, but also looking for CRC32C.java
within the source class path (srcClassPath
). Just to be clear, the CRC32C
class is available in the JDK17 modules, and Netbeans should be able to determine this and therefore decide that the project is being developed within and for a JDK17 environment. The test, in fact, looks for CRC32C
in order to decide if the source level is at least 9. If that passes, it then goes on to look for java.lang.Record
to decide if the source level is at least 15.
So, if it could find the source file (.java) instead of the class file (.class) then the test would pass. Fortunately the source path involved refers to the root(s) of where the project sources are located. So if I were to create a path java/util/zip
and place CRC32C.java
in there, the test would succeed. But wouldn’t having a copy of CRC32C.java
in the project create other problems? It would, if the file actually had anything in it. The test is only looking for the existence of the file. It doesn’t actually have to have a definition of the real class. So I simply added a java/util/zip/CRC32C.java
and (for good measure) a java/lang/Record.java
to my project, with both files containing this one-line comment:
/* Here to keep Netbeans happy */
I also updated my .gitignore to ensure this hack didn’t get pushed up to the repository.
Did it work? Yes, it worked.
In summary: Netbeans is looking for CRC32C in certain paths to confirm that the source level is at least Java 9, so to ensure that it passes this test I created a dummy (i.e. empty) java.util.net.CRC32C source file in the project, and a similar dummy java.lang.Record source file to ensure it also passes the Java 15 test.
Categorised as: Coding