Project Structure
A simple java project with multiple java modules can be illustrated with the following structure. Each module must have module descriptor denoted with module-info.java
placed under the root folder. Either each source (src
) folder can have one module or under one source folder, multiple modules can be declared.
The following given Java9PlayArea project is available at Java9 Play Area.
Java9PlayArea project has four java modules, namely
com.tbc.java9.api
com.tbc.java9.repository
com.tbc.java9pa.domain
com.tbc.java9pa.service
Each module has its own source folder (src
) under which, we create a module descriptor (module-info.java
). Once module descriptors have been created for each module, we need to specify the dependencies among the modules. Without specifying dependencies and the packages that are accessible from a given module, a Java module wouldn't be visible to any other module of the application.
In non-modular Java application, bounding to the access specifiers, you can access packages, classes within the application. However, due to Java 9's strong encapsulation that doesn't happen anymore.
For instance, the module com.tbc.java9.api,
depends on com.tbc.java9pa.service.
To convey this message to Java compiler and runtime we have to explicate this relation through module descriptors of the respective modules.
module com.tbc.java9pa.service {
requires transitive com.tbc.java9.repository;
/*explictely telling JVM that com.tbc.java9pa.book package is accessible ONLY to com.tbc.java9.api module. This is called as qualified export.*/
exports com.tbc.java9pa.service.book to com.tbc.java9.api;
/*explicitely mentioning JVM that com.tbc.java9pa.service.author
package is available to be accessed by all other modules of the application.*/
exports com.tbc.java9pa.service.author;
}
Similarly, rest of the dependencies among the other modules need to be specified to access the classes available outside the calling module.
Simple Java 9 Project package structure
Fig: Simple java 9 multi modules application.
Now let's move on to understand how we can make both java 9 modules and maven modules to work together.
Multi Maven module with Java 9 modularity
We use maven as a build tool for building and managing Java projects. With Java 9 in the picture, maven dependency management alone doesn't work alone, but Java 9 modularity also needs to be considered.
As you are aware, using maven we can create a multi-module application. The above figure illustrates the same with Java 9. Let's consider a simple Java and Maven multi-module application.
It has four different maven modules: apigatewaydomain
, service
and repository
. Java9mavenmultimodule
is the parent maven module with packaging as pom.
The parent maven module now consists of four child modules. The following is parent's pom.xml.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
>
<modelVersion>4.0.0</modelVersion>
<groupId>com.tbc.java9maven</groupId>
<artifactId>java9-maven-multimodule</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>java9-maven-multimodule</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.target>1.9</maven.compiler.target>
<maven.compiler.source>1.9</maven.compiler.source>
</properties>
<modules>
<module>domain</module>
<module>apigateway</module>
<module>service</module>
<module>repository</module>
</modules>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
</plugin>
</plugins>
</build>
</project>
Now, under each maven child module's source directory (src
), we create a Java module by creating a respective module descriptor (module-info.java
).
Fig: Multi-module maven application with Java 9 modularity applied.
Maven’s standard source folder src/main/java
acts as the root folder for module descriptor. module-info.java
needs to be created under src/main/java
and specify module dependencies, if any.
Apart from specifying maven dependency in pom.xml,
Java modularity constraints have to be followed to access any package from the dependency. This way true encapsulation is maintained in java 9 modular programming. For instance, from above figure maven service module has a dependency on maven’s repository module. However, specifying repository dependency in service’s pom.xml doesn’t provide access to repository classes. Only the packages exported by java repository module(com.tbc.java9multimavenmodule.repositroy
) that was created under src/main/java
of maven repository module, are allowed to be accessed by service module. Provided, java module, com.java9multimavenmodule.service,
explicitly mentioned dependency in module descriptor java file. i.e.
1. repository
module must export the packages intended to be accessible by service.
module com.tbc.java9.mavenmultimodule.repository {
// Any dependency modules using requires / requires transitive
exports com.tbc.java9.mavenmultimodule.repository; // exporting package to outside world.
...
}
2. service'
s module descriptor must specify repository module as a required dependency.
module com.tbc.java9.mavenmultimodule.service {
...
requires com.tbc.java9.mavenmultimodule.repository; // dependent on repository module.
...
}
3. pom.xml
of service
module should have the repository
dependency configured.
<parent>
<artifactId>java9-maven-multimodule</artifactId>
<groupId>com.tbc.java9maven</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>service</artifactId>
<dependencies>
<!-- Specifying repository as maven dependency. This configuration should be suffiecient in non - modular Java application with maven-->
<dependency>
<groupId>com.tbc.java9maven</groupId>
<artifactId>repository</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
The similar approach goes with rest of the modules and their dependencies.
Source code is available at java9-maven-multi-module