Migrating to Java 9
Modules
| Paul Bakker
Why care about modules?
lib/[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/
[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/
[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/rest-api-client-
[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/
[Link]:lib/[Link]:lib/[Link]:lib/gradle-extra-configurations-
[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/gradle-lint-
[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/gradle-resolution-rules-
[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/nebula-dependency-
[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/
[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/httpclient-
[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/commons-
[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/
[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/
[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/
[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/jackson-
[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/commons-
[Link]:lib/[Link]-jdk16-1.46_3.jar:lib/[Link]:lib/[Link]:lib/
[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/metatron-
[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/multiverse-
[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/
[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/
[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/
error_prone_annotations-[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/grpc-
[Link]:lib/[Link]:lib/[Link]:lib/xpp3_min-[Link]:lib/[Link]:lib/grpc-google-common-
[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/spring-
[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/commons-
[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/
[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/
[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/
[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/[Link]-trilead-
[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/antlr-
[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/bcprov-
[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/[Link]:lib/
[Link]:lib/[Link]
Module primer.
module [Link] {
module [Link] { exports [Link];
requires [Link]; opens impl;
} }
[Link] [Link]
[Link]
impl
reflection only!
other
Module primer.
module [Link] {
module [Link] { exports
Modules [Link];
dependencies
requires [Link]; opensexplicitly
impl;
} }
[Link] [Link]
[Link]
impl
reflection only!
other
Module primer.
module [Link] {
module [Link] { exports [Link];
requires [Link]; opens impl;
Packages are encapsulated by
} }
default
[Link] [Link]
[Link]
impl
reflection only!
other
Module primer.
module [Link] {
module [Link] { exports [Link];
requires Packages
[Link];
can be “opened” for opens impl;
} deep reflection at run-time }
[Link] [Link]
[Link]
impl
reflection only!
other
Migrating to Java 9.
Java 8
java -cp … -jar
[Link]
Java 9
java -cp … -jar
[Link]
Our journey to modules.
Running on Java 9
Using existing libraries
Allowing reflection
Spring / Hibernate case study
Refactoring to increase modularity
Migrating builds
!"" lib
!"" [Link]
#"" src
!"" books
$ !"" api
$ $ !"" entities
$ $ $ #"" [Link]
$ $ #"" service
$ $ #"" [Link]
$ #"" impl
$ !"" entities
$ $ #"" [Link]
$ #"" service
$ #"" [Link]
!"" bookstore
$ !"" api
$ $ #"" service
$ $ #"" [Link]
javac -cp [list of JARs in lib]
$ #"" impl -d out -sourcepath src $(find src -name '*.java')
$ #"" service
$ #"" [Link] cp $(find src -name '*.xml') out
!"" [Link]
!"" main java -cp [list of JARs in lib]:out [Link]
$ #"" [Link]
#"" [Link]
Missing platform libraries.
import [Link];
public class Main {
public static void main(String... args) {
DatatypeConverter.parseBase64Binary("SGVsbG8gd29ybGQh");
}
}
[Link]: [Link]
The platform module graph.
[Link] vs [Link]
Resolving JAXB.
java --add-modules [Link] …
Illegal deep reflection.
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by
[Link] …
WARNING: Please consider reporting this to the maintainers of
[Link]
WARNING: Use --illegal-access=warn to enable warnings of further
illegal reflective access operations
WARNING: All illegal access operations will be denied in a future
release
Type Compile time Reflection on public Deep reflection
Exports
✓ ✓ ✘
Open
✘ ✓ ✓
Exports + Open
✓ ✓ ✓
Fixing illegal deep reflection.
Use a library that doesn’t do this!
do you really need deep reflection on JDK types!?
Use command line flags to open packages
java --add-opens [Link]/[Link]=ALL-UNNAMED Main
Automatic
Modules
But we’re still on the classpath!
Let’s migrate our code to
modules
But how do we deal with
libraries?
package demo;
import [Link];
public class Main {
public static void main(String... args) throws Exception {
Book modularityBook =
new Book("Java 9 Modularity", "Modularize all the things!");
ObjectMapper mapper = new ObjectMapper();
String json = [Link](modularityBook);
[Link](json);
}
}
module books {
}
Automatic modules - A non-
modular JAR on the module
path
Exports all packages
Requires all resolved modules
Can read the class path (the unnamed module)
module books {
requires [Link];
}
CP=lib/[Link]:
CP+=lib/[Link]
javac -cp $CP --module-path mods -d out --module-source-path src -m books
Case study
Sample app after migration.
!"" lib
!""
!""
mods
[Link]
Step 1 - Project structure.
#"" src
#"" bookapp “mods” dir for automatic modules
!"" books
$ !"" api
Single module dir (for now)
$ $ !"" entities Add [Link]
$ $ $ #"" [Link]
$ $ #"" service
$ $ #"" [Link]
$ #"" impl
$ !"" entities
javac -cp $CLASSPATH \
$
$
$ #"" [Link]
#"" service
--module-path mods \
$ #"" [Link] -d out \
!"" bookstore
$ !"" api --module-source-path src \
$ $ #"" service
$ $ #"" [Link] -m bookapp
$ #"" impl
$ #"" service
$ #"" [Link]
!"" [Link]
!"" main
$ #"" [Link]
!"" [Link]
#"" [Link]
Step 2 - Add requires.
Compilation error
[Link]: error: package
[Link] is not visible
import [Link];
Our module needs explicit
dependencies!
Step 3 - Add missing compile time platform
modules.
Compilation error
[Link]: error: cannot access Referenceable
return [Link]().get([Link], id);
^
class file for [Link] not found
Hibernate should declare
requires transitive [Link]
Running.
java -cp $CLASSPATH
--module-path mods:out
-m bookapp/[Link]
Step 4 - Add missing platform modules.
[Link]: [Link]
java -cp $CLASSPATH
--add-modules [Link],[Link]
--module-path mods:out
-m bookapp/[Link]
Step 5 - Open packages for reflection.
[Link]: class
[Link] cannot access class
[Link] (in module bookapp)
because module bookapp does not export [Link] to
unnamed module @5c45d770
opens [Link];
opens [Link];
opens [Link];
Step 6 - Illegal deep reflection.
[Link]: Unable to make
protected final [Link]
[Link]([Link],byte[],int,int
,[Link]) throws
[Link] accessible: module [Link] does not
"opens [Link]" to module javassist
java -cp $CLASSPATH
--add-modules [Link],[Link]
--add-opens [Link]/[Link]=javassist
--module-path mods:out
-m bookapp/[Link]
Refactor to
multiple modules
Multi module structure
requires
[Link] [Link]
main requires
bookstore
requires Spring
requires
[Link] [Link]
main requires
[Link] [Link]
requires
provides
uses provides
Module System
Build tools. <artifactId>bookstore</artifactId>
<build>
<plugins>
<plugin>
<groupId>[Link]</groupId>
module bookstore {
<artifactId>maven-compiler-plugin</artifactId>
requires books;
<configuration>
<source>9</source>
exports [Link];
<target>9</target>
</configuration>
uses [Link];
</plugin>
</plugins>
provides [Link] with
</build>
[Link];
<dependencies>
}
<dependency>
<groupId>javamodularity</groupId>
<artifactId>books</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
Thank you.
Paul Bakker
@pbakker