I’ve been looking at converting a large gradle project to use java modules and hit one glitch.
Some of the libraries I am using as dependencies have no module-info, nor any name in the manifest. IntelliJ & Java use a computed name for the module – for example ‘kafka.clients’ for the kafka client jar (maven dependency), or the first one I hit:
Is there any reason not to follow the logic Gradle is employing, putting non-modular jars without explicit automatic module name on the classpath?
If so, you can either just configure the module path explicitly to contain all runtime classpath jars, or you can use for example the plugin Gradle - Plugin: de.jjohannes.extra-java-module-info that can transform non-modular jars into modular jars.
Yes, the JAR file Specification specifies what should happen if you put a non-modular jar file on the module path.
But that does not make it a good idea.
Non-modular jar files are often not JPMS ready.
They might have split-packages.
They might use things that cannot work if they are on the module path.
They might have a name with an illegal identifier that makes it impossible to derive a module name from the jar name.
The module name changes if you rename the jar file.
The module name changes if later the author of that library decides to make it a module and so the module name used in consumer module info files is wrong and cannot be used with the newer version of the library, …
There is just so much shenenigans and non-determinism if you put non-modular jars on the module path, that the Gradle guys wisely decided to not put non-modular jars on the module path, but at most such that declare an automatic module name in the manifest which should be a sign that the library author at least thought about it and at least made it JPMS compatible.
But as always Gradle just provides sane defaults and gives you the flexibility to easily do whatever you want, so if you really want to put those files on the module path for your project, then just configure your build however you like it.
Thanks for the reply. I was able to get this working (at least as a prototype) by adding a small number of module definitions using the plugin mentioned.
I was confused by the difference in default behaviour though between gradle and plain java in terms of automatic modules. I wonder if this needs calling our more clearly in the docs (maybe I missed it) as it caught me out.
I was confused by the difference in default behaviour though between gradle and plain java in terms of automatic modules.
I wouldn’t actually say there is a difference.
If you put all jars on the module path with Gradle, it will behave the same as if you put all jars on the module path with plain Java as Gradle just forwards this to “plain Java” as Gradle is a layer on top, not something in parallel.
The difference is, that if you do it with “plain Java”, you tell Java to put all jars on the module path.
And if you use Gradle, it is more intelligent and only puts those jars on the module path that at least have an automatic module name.
I wonder if this needs calling our more clearly in the docs (maybe I missed it) as it caught me out.
A third case are traditional libraries that provide no module information at all — for example commons-cli:commons-cli:1.4 . Gradle puts such libraries on the classpath instead of the module path. The classpath is then treated as one module (the so called unnamed module) by Java.