Java 9 automatic module with example
In previous posts we were exploring how new module system works.
Java 9 using exports and requires
Export to specific modules only
Transitive Dependency in Java 9
But in the real world we will use different jars which may or may not be modularized. In this post we will talk about what happens if you want to use jars that are not modularized yet.
For this example we will be working with following directory structure
├── jars
│ └── guava-23.0.jar
├── run.sh
└── src
└── com.moduleone
├── com
│ └── moduleone
│ └── ModuleOne.java
└── module-info.java
Let’s write some code on ModuleOne that uses google-guava library.
package com.moduleone;
import java.util.List;
import com.google.common.collect.FluentIterable;
class ModuleOne {
public static void main(String[] args) {
FluentIterable.from(List.of(1, 2, 3, 4, 5, 6, 7))
.filter(input -> input % 2 == 0)
.stream()
.forEach(System.out::println);
}
}
We could have done above code using Java Stream API but for this example we are using google-guava library.
Fill in module-info.java
module com.moduleone{
}
Because we are using external jar we need to make sure we load it. We can load it alongside our app using --module-path
javac -d mods --module-path ./jars/ --module-source-path src $(find src -name "*.java")
Notice on --module-path
we are using ./jars/
, that is where we are storing our external jars.
If we run the command above now, we will get the following error
src/com.moduleone/com/moduleone/ModuleOne.java:4: error: package com.google.common.collect is not visible
import com.google.common.collect.FluentIterable;
^
(package com.google.common.collect is declared in module guava, but module com.moduleone does not read it)
1 error
Error clearly says that the code we are trying to use is not specified as requires
dependency. If you read my previous posts, you should know that we need to use requries
here. But what module do we require. All we did we added a jar on the module path.
So if we add a external jars that are not modularized to --module-path
we will be using Java 9 automatic modules
feature. Basically what that means is, that list of exported packages is simply set to be all packages in the jar file.
So does that mean we add requires external.library.package
? In this case NO. This is kind of odd but when we add external jar that is not modularied, and if we want to use that library we add requires filename
without version numbers.
In this scenario our file name is guava-23.0.jar
so we add requires guava;
to our module-info.java
module com.moduleone{
requires guava;
}
So we know from above that external jar version numbers are trimmed off. But what if our jar name was like guava-all.23.0.jar
. We we try to add requires guava-all
Java compiler will yell at us. So, what Java does is it trims out the version number and if those jars have any dashes (-) it will be converted to dot (.) . So in our scenerio if our jar file was named guava-all.23.0.jar
we add requires guava.all;
in our module-info.java
.
So to run we need to add jar to --module-path
like we did when we compiled our code.
java --module-path ./jars/:mods -m com.moduleone/com.moduleone.ModuleOne
If we forget to add our external jar on --module-path
when we run our program we will get error
Error occurred during initialization of boot layer
java.lang.module.FindException: Module guava not found, required by com.moduleone
Well, this is it for Java 9 automatic module. Cheers!!