module-info.java compile fail with maven-compiler-plugin and automatic modules - java

I'm using v3.7.0 of the plugin as required and JDK 9.0.1. I have added two requires statements, each referring to a jar in the class path (automatic module). The module-info.java compiles successfully in Eclipse after I moved the jars to Modulepath. However, Maven gives me a compiler error saying one of them is missing (strangely, not the first one which is just one line before). I tried to check the automatic module name but I get an error from the commands just for this jar. What does this error mean and how do I fix it so that I can discover the proper module name?
I replaced my username in the output below. The jar in question does use a ServiceLoader but is not compiled with Java 9.
computerName:Commander-java username$ jar --file=/Users/username/.m2/repository/com/username/rcf/1.0/rcf-1.0.jar --describe-module
Unable to derive module descriptor for: /Users/username/.m2/repository/com/username/rcf/1.0/rcf-1.0.jar
Provider class com.username.rcf.server.TestCmdChain not in module
computerName:Commander-java username$ java -p /Users/username/.m2/repository/com/username/rcf/1.0/rcf-1.0.jar --list-modules
Error occurred during initialization of boot layer
java.lang.module.FindException: Unable to derive module descriptor for /Users/username/.m2/repository/com/username/rcf/1.0/rcf-1.0.jar
Caused by: java.lang.module.InvalidModuleDescriptorException: Provider class com.username.rcf.server.TestCmdChain not in module
The answer in How to deal with java keywords in auto generated module names in Java 9? has a different error related to using a Java identifier in the module name. The automatic jar name for my module should just be rcf since the jar name is rcf-1.0.jar. The error I'm getting is different also.

While deriving module description the contents of any
META-INF/services configuration files are mapped to provides
declarations.
The packages scanned for the services are the ones containing class files.
Also, the package name for individual classes is derived from their fully qualified name. From the shared logs com.username.rcf.server shall be the expected package name for the service to be provided and this shall turn into
provides x.y.z.TestCmdChainInterface with com.username.rcf.server.TestCmdChain
Seems like there is no such package com.username.rcf.server existing in your module.

Related

An SPI class of type org.apache.lucene.codecs.DocValuesFormat with name 'Memory' does not exist

Getting error:
Diag message: User class threw exception: java.lang.IllegalArgumentException: An SPI class of type org.apache.lucene.codecs.DocValuesFormat with name 'Memory' does not exist.
You need to add the corresponding JAR file supporting this SPI to your classpath.
The current classpath supports the following names: [Lucene54]
at org.apache.lucene.util.NamedSPILoader.lookup(NamedSPILoader.java:116)
at org.apache.lucene.codecs.DocValuesFormat.forName(DocValuesFormat.java:108)
I have tried running the jar with various newer versions of lucene-core (along with backward-compatibility jar) but no success. Currently, we are using 6.5.0 version.
The Lucene-index we are trying to read contains files like - _4o08_Memory_0.mdvd & _4o08_Memory_0.mdvm which are the real issue.
Solution - add maven dependency https://mvnrepository.com/artifact/org.apache.lucene/lucene-codecs/6.5.0 & make sure its a runtime dependency & not limited to test scope.

FindException in connecting with Mysql database

I'm using ubuntu system, and using Mysql 8.0. I trying to connect database with jdbc class but having an error,although I added the mysql-connector.jar file,
The error I mentioned below,
-->Error occurred during initialization of boot layer
java.lang.module.FindException: Error reading module: /home/surya/eclipse-workspace/Advancedjava/bin
Caused by: java.lang.module.InvalidModuleDescriptorException:
mysql_conntn.class found in top-level directory (unnamed package not allowed in module)
You have a module-info.java in your project making it a modular Java project. However, you also have a class (mysql_conntn) in the default (unnamed) package, and this is not allowed in a modular project.
Either you need to make your project non-modular by removing module-info.java, or you need to move the class mysql_conntn to a named package.

Resolving to correct dependencies when loading classes with custom classloaders

So I have this generic backend server that loads shaded jars in memory and then loads it through a custom Classloader.
E.g.
MyClass class = c.newInstance();
It works fine until the shaded Jar dependencies conflicts with the server classes.
E.g.
Server contains (with Custom Classloader):
com.fasterxml.jackson.jackson-databind:2.6.0
While the shaded jar contains
com.fasterxml.jackson.jackson-databind:2.9.9
When the method in the class that requires the said library e.g. class.doSomeThing(); it throws an error Caused by java.lang.NoSuchFieldError: because the loaded jackson-databind is 2.6.0 instead of 2.9.9
The question here is when the class is loaded from the shaded jar is there a way to make sure that the shaded dependencies are the ones used?
The question here is when the class is loaded from the shaded jar is there a way to make sure that the shaded dependencies are the ones used?
If you are using the default Class loader then the order of resolution will work as the order of the classpath. Within your code you can use
System.out.println(System.getProperty("system.class.path").replaceAll(":", "\n"));
And inspect the classpath. Usually such runtime environment (for example apache spark) has such features to allow you to prepend the classpath. You can check with your runtime server environment for such feature.

How to let a java class on classpath access a class belonging to a module on module-path

I am trying out the various access rules about who can access and what and I saw this statement in The State of the module system document,
The unnamed module reads every other module. Code in any type loaded from the class path will thus be able to access the exported types of all other readable modules, which by default will include all of the named, built-in platform modules.
So, I wrote the following code to test it out with the following structure:
moduleA/modA.A --> automod/automod.Foo --> nonmodular.Junk --> moduleX/modX.X
Basically,
moduleA's modA.A calls a method on a non-modular class automod.Foo. automod.Foo is packaged into automod.jar and put on the module-path. module-info for moduleA has requires automod; clause. This works fine, as expected.
automod.Foo calls a method on nonmodular.Junk class. nonmodular.Junk is packaged into nonmodular.jar and put on classpath. This works fine, as expected.
nonmodular.Junk calls a method on moduleX's modX.X. modX.X is packaged into moduleX.jar.
It is this step that has a problem. It works if I put moduleX.jar on classpath but not if I put moduleX.jar on module-path. (module-info for moduleX does have exports modX; clause.)
In other words, the following command works:
java --module-path moduleA.jar;automod.jar; -classpath nonmodular.jar;moduleX.jar --module moduleA/modA.A
With the following output:
In modA.A.main() Calling automod.Foo()
In automod.Foo()
In modA.A.main() Calling automod.foo.main()
In automod.Foo.main() Calling nonmodular.Junk()
In automod.Foo.main() Calling nonmodular.Junk.main()
In nonmodular.Junk.main calling new modX.X()
In modX.X()
But the following command doesn't work:
java --module-path moduleA.jar;automod.jar;moduleX.jar -classpath nonmodular.jar; --module moduleA/modA.A
Here is the output:
In modA.A.main() Calling automod.Foo()
In automod.Foo()
In modA.A.main() Calling automod.foo.main()
In automod.Foo.main() Calling nonmodular.Junk()
In automod.Foo.main() Calling nonmodular.Junk.main()
In nonmodular.Junk.main calling new modX.X()
Exception in thread "main" java.lang.NoClassDefFoundError: modX/X
at nonmodular.Junk.main(Junk.java:5)
at automod/automod.Foo.main(Foo.java:10)
at moduleA/modA.A.main(A.java:10)
Caused by: java.lang.ClassNotFoundException: modX.X
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:583)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
... 3 more
Any idea why? Any class loaded from the classpath should be able to access any classes exported by a module.
When you start a Java application with the --module command, the value you pass is a "root" module. The same is true of modules added via --add-modules. The module system determines the entire module graph from these root modules. In other words, it reads the module-info file, finds the requires directives, and then searches the modulepath for those required modules. It does this transitively. Some modules also declare one or more uses directives on a service. Any modules on the modulepath that provides any of those services will also be loaded, regardless of if any module requires them.
This means if there's a module on the modulepath that isn't required by any loaded module and doesn't provide any services needed by any loaded module then said module won't be loaded. If you're interested in seeing what modules are resolved you can use the following command:
java --show-module-resolution --dry-run -p [MODULEPATH] -m [MODULE]
In your case I can only assume that none of your other modules require modularX, so when its on the modulepath it doesn't get loaded. However, when its on the classpath things work differently and its found by your non-modular code that's also on the classpath. You can still use the modulepath though, just make sure your moduleX module is loaded. This can be forced by using --add-modules:
java -p moduleA.jar;automod.jar;moduleX.jar --add-modules moduleX -cp nonmodular.jar -m moduleA/modA.A
Note you can also limit the modules via --limit-modules.

How to use 3rd party library in Java9 module?

I have some java9 module that uses 3rd party library that is not Java9 module, just a simple utility jar.
However, the compiler complains that it can't find a package from my utility.
What should I do in module-info.java to enable usage of my 3rd party library?
You can use your library as an automatic module. An automatic module is a module that doesn't have a module descriptor (i.e. module-info.class).
But what name do you need to specify to refer to an automatic module? The name of the automatic module is derived from the JAR name (unless this JAR contains an Automatic-Module-Name attribute). The full rule is quite long (see Javadoc for ModuleFinder.of), so for simplicity, you just have to drop the version from its name and then replace all non-alphanumeric characters with dots (.).
For example, if you want to use foo-bar-1.2.3-SNAPSHOT.jar, you need to add the following line to module-info.java:
module <name> {
requires foo.bar;
}
To put it in simple steps, to use a 3rd party jar (e.g. log4j-api-2.9.1.jar below) in your module:-
Execute the descriptor command of jar tool
jar --file=/path/to/your/jar/log4j-api-2.9.1.jar --describe-module
This would provide you an output similar to
No module descriptor found. Derived automatic module.
log4j.api#2.9.1 automatic
In your module descriptor file, declare a requires to that module name as:-
module your.module {
requires log4j.api;
}
That's it.

Categories