Migrating to Java 9
Modules
| Paul Bakker
Why care about modules?
lib/nebula-4.0.12.jar:lib/netflix-gradle-lint-8.6.1.jar:lib/gretty-2.0.0.jar:lib/gradle-infamous-plugin-1.28.jar:lib/java-semver-0.9.0.jar:lib/guava-20.0.jar:lib/
nebula-core-4.0.1.jar:lib/commons-lang-2.6.jar:lib/joda-time-2.9.9.jar:lib/kotlin-reflect-1.1.4-3.jar:lib/nebula-common-4.0.12.jar:lib/nebula-repos-4.0.12.jar:lib/
nebula-publish-4.0.12.jar:lib/httpclient-4.5.3.jar:lib/jgrapht-core-0.9.2.jar:lib/build-info-extractor-gradle-4.1.1.jar:lib/ant-jsch-1.9.9.jar:lib/rest-api-client-
core-1.9.0.jar:lib/rest-api-client-httpclient-1.9.0.jar:lib/bakery-api-client-1.8.0.jar:lib/odin-2.0.0.jar:lib/artifactory-java-client-services-1.2.2.jar:lib/
kotlin-stdlib-jre8-1.1.4-3.jar:lib/gradle-contacts-plugin-3.0.1.jar:lib/gradle-dependency-lock-plugin-4.9.4.jar:lib/gradle-extra-configurations-
plugin-3.2.0.jar:lib/gradle-git-scm-plugin-3.0.1.jar:lib/gradle-info-plugin-3.6.0.jar:lib/gradle-java-cross-compile-plugin-0.9.0.jar:lib/gradle-lint-
plugin-8.3.1.jar:lib/gradle-metrics-plugin-6.0.0.jar:lib/gradle-ospackage-plugin-4.4.0.jar:lib/gradle-override-plugin-3.0.2.jar:lib/gradle-resolution-rules-
plugin-5.0.2.jar:lib/gradle-scm-plugin-3.0.1.jar:lib/gradle-stash-plugin-4.0.1.jar:lib/nebula-dependency-base-plugin-0.3.0.jar:lib/nebula-dependency-
recommender-5.0.0.jar:lib/nebula-grails-plugin-1.0.0.jar:lib/nebula-project-plugin-3.4.0.jar:lib/nebula-release-plugin-6.0.1.jar:lib/gradle-release-1.2.jar:lib/
gradle-cobertura-plugin-2.5.0.jar:lib/gretty-core-2.0.0.jar:lib/spring-boot-loader-tools-1.5.4.RELEASE.jar:lib/jetty-util-8.1.8.v20121106.jar:lib/httpclient-
cache-4.5.2.jar:lib/kotlin-stdlib-1.1.4-3.jar:lib/metatron-decrypt-1.108.0.jar:lib/nebula-publishing-plugin-5.1.3.jar:lib/httpcore-4.4.6.jar:lib/commons-
logging-1.2.jar:lib/commons-codec-1.9.jar:lib/ivy-2.2.0.jar:lib/build-info-extractor-2.5.5.jar:lib/ant-1.9.9.jar:lib/mail-1.4.4.jar:lib/frigga-0.13.jar:lib/
nekohtml-1.9.17.jar:lib/artifactory-java-client-api-1.2.2.jar:lib/groovy-xml-2.3.2.jar:lib/jcl-over-slf4j-1.7.2.jar:lib/kotlin-stdlib-jre7-1.1.4-3.jar:lib/
svnkit-1.8.12.jar:lib/asm-5.2.jar:lib/gpars-1.2.1.jar:lib/junit-4.12.jar:lib/jackson-datatype-joda-2.3.2.jar:lib/logstash-logback-encoder-4.5.1.jar:lib/
jest-0.1.7.jar:lib/fluent-hc-4.5.1.jar:lib/redline-1.2.5.jar:lib/jdeb-1.4.jar:lib/gradle-docker-plugin-3.0.1.jar:lib/commons-beanutils-core-1.8.3.jar:lib/jackson-
module-kotlin-2.7.5.jar:lib/maven-model-builder-3.5.0.jar:lib/grails-launcher-1.1.jar:lib/groovy-2.4.11.jar:lib/commons-cli-1.2.jar:lib/commons-
configuration-1.10.jar:lib/org.apache.servicemix.bundles.bcprov-jdk16-1.46_3.jar:lib/spring-boot-devtools-1.3.3.RELEASE.jar:lib/spring-core-4.3.9.RELEASE.jar:lib/
annotations-13.0.jar:lib/gson-2.8.0.jar:lib/protobuf-java-util-3.2.0.jar:lib/protobuf-java-3.2.0.jar:lib/grpc-core-1.3.0.jar:lib/javax.inject-1.jar:lib/metatron-
common-1.108.0.jar:lib/metatron-ipc-common-1.108.0.jar:lib/build-info-client-2.5.5.jar:lib/xstream-1.3.1.jar:lib/ant-launcher-1.9.9.jar:lib/multiverse-
core-0.7.0.jar:lib/jsr166y-1.7.0.jar:lib/hamcrest-core-1.3.jar:lib/logback-core-1.1.3.jar:lib/jest-common-0.1.7.jar:lib/httpcore-nio-4.4.1.jar:lib/
httpasyncclient-4.1.jar:lib/plexus-utils-3.0.24.jar:lib/plexus-interpolation-1.24.jar:lib/plexus-component-annotations-1.7.1.jar:lib/maven-model-3.5.0.jar:lib/
maven-artifact-3.5.0.jar:lib/maven-builder-support-3.5.0.jar:lib/spring-boot-1.3.3.RELEASE.jar:lib/spring-boot-autoconfigure-1.3.3.RELEASE.jar:lib/
error_prone_annotations-2.0.19.jar:lib/jsr305-3.0.0.jar:lib/grpc-context-1.3.0.jar:lib/instrumentation-api-0.3.0.jar:lib/grpc-protobuf-1.3.0.jar:lib/grpc-
stub-1.3.0.jar:lib/jackson-mapper-asl-1.9.12.jar:lib/build-info-api-2.5.5.jar:lib/xpp3_min-1.1.4c.jar:lib/spring-context-4.2.5.RELEASE.jar:lib/grpc-google-common-
protos-0.1.6.jar:lib/grpc-protobuf-lite-1.3.0.jar:lib/jackson-core-asl-1.9.12.jar:lib/spring-aop-4.2.5.RELEASE.jar:lib/spring-beans-4.2.5.RELEASE.jar:lib/spring-
expression-4.2.5.RELEASE.jar:lib/aopalliance-1.0.jar:lib/http-builder-0.7.1.jar:lib/json-lib-2.3-jdk15.jar:lib/xml-resolver-1.2.jar:lib/commons-
beanutils-1.8.0.jar:lib/commons-collections-3.2.1.jar:lib/ezmorph-1.0.6.jar:lib/slf4j-api-1.7.25.jar:lib/commons-io-2.5.jar:lib/jackson-annotations-2.7.5.jar:lib/
jackson-databind-2.7.5.jar:lib/nebula-gradle-interop-0.5.0.jar:lib/org.eclipse.jgit.ui-4.6.1.201703071140-r.jar:lib/jsch.agentproxy.jsch-0.0.9.jar:lib/
jsch.agentproxy.pageant-0.0.9.jar:lib/jsch.agentproxy.sshagent-0.0.9.jar:lib/jsch.agentproxy.usocket-jna-0.0.9.jar:lib/jsch.agentproxy.usocket-nc-0.0.9.jar:lib/
jsch.agentproxy.core-0.0.9.jar:lib/jna-4.1.0.jar:lib/jna-platform-4.1.0.jar:lib/p4java-2015.2.1365273.jar:lib/jzlib-1.1.2.jar:lib/jsch.agentproxy.svnkit-trilead-
ssh2-0.0.7.jar:lib/trilead-ssh2-1.0.0-build220.jar:lib/jsch.agentproxy.connector-factory-0.0.7.jar:lib/sequence-library-1.0.3.jar:lib/sqljet-1.1.10.jar:lib/antlr-
runtime-3.4.jar:lib/commons-lang3-3.5.jar:lib/gradle-git-1.7.2.jar:lib/groovy-json-2.4.11.jar:lib/commons-compress-1.8.jar:lib/bcpg-jdk15on-1.51.jar:lib/bcprov-
jdk15on-1.51.jar:lib/xercesImpl-2.9.1.jar:lib/jackson-core-2.7.5.jar:lib/org.eclipse.jgit-4.6.1.201703071140-r.jar:lib/JavaEWAH-1.1.6.jar:lib/jsch-0.1.54.jar:lib/
grgit-1.9.3.jar:lib/xz-1.5.jar
module easytext.cli {
requires easytext.analysis;
}
module easytext.analysis {
exports analysis.api;
opens impl;
}
easytext.cli easytext.analysis
other
analysis.api
impl
reflection only!
Module primer.
module easytext.cli {
requires easytext.analysis;
}
module easytext.analysis {
exports analysis.api;
opens impl;
}
easytext.cli easytext.analysis
other
analysis.api
impl
reflection only!
Module primer.
Modules define dependencies
explicitly
module easytext.cli {
requires easytext.analysis;
}
module easytext.analysis {
exports analysis.api;
opens impl;
}
easytext.cli easytext.analysis
other
analysis.api
impl
reflection only!
Module primer.
Packages are encapsulated by
default
module easytext.cli {
requires easytext.analysis;
}
module easytext.analysis {
exports analysis.api;
opens impl;
}
easytext.cli easytext.analysis
other
analysis.api
impl
reflection only!
Module primer.
Packages can be “opened” for
deep reflection at run-time
Migrating to Java 9.
Java 8
Java 9
java -cp … -jar
MyApp.jar
java -cp … -jar
MyApp.jar
Our journey to modules.
Running on Java 9
Using existing libraries
Allowing reflection
Spring / Hibernate case study
Refactoring to increase modularity
Migrating builds
!"" lib
!"" run.sh
#"" src
!"" books
$   !"" api
$   $   !"" entities
$   $   $   #"" Book.java
$   $   #"" service
$   $   #"" BooksService.java
$   #"" impl
$   !"" entities
$   $   #"" BookEntity.java
$   #"" service
$   #"" HibernateBooksService.java
!"" bookstore
$   !"" api
$   $   #"" service
$   $   #"" BookstoreService.java
$   #"" impl
$   #"" service
$   #"" BookstoreServiceImpl.java
!"" log4j2.xml
!"" main
$   #"" Main.java
#"" main.xml
javac -cp [list of JARs in lib]
-d out -sourcepath src $(find src -name '*.java')
cp $(find src -name '*.xml') out
java -cp [list of JARs in lib]:out main.Main
Missing platform libraries.
import javax.xml.bind.DatatypeConverter;
public class Main {
public static void main(String... args) {
DatatypeConverter.parseBase64Binary("SGVsbG8gd29ybGQh");
}
}
java.lang.ClassNotFoundException: javax.xml.bind.JAXBException
The platform module graph.
java.se vs java.se.ee
Resolving JAXB.
java --add-modules java.xml.bind …
Illegal deep reflection.
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by
javassist.util.proxy.SecurityActions …
WARNING: Please consider reporting this to the maintainers of
javassist.util.proxy.SecurityActions
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 java.base/java.lang=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 com.fasterxml.jackson.databind.ObjectMapper;
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 = mapper.writeValueAsString(modularityBook);
System.out.println(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)
CP=lib/jackson-annotations-2.8.8.jar:
CP+=lib/jackson-core-2.8.8.jar
javac -cp $CP --module-path mods -d out --module-source-path src -m books
module books {
requires jackson.databind;
}
Case study
Sample app after migration.
Step 1 - Project structure.
!"" lib
!"" mods
!"" run.sh
#"" src
#"" bookapp
!"" books
$   !"" api
$   $   !"" entities
$   $   $   #"" Book.java
$   $   #"" service
$   $   #"" BooksService.java
$   #"" impl
$   !"" entities
$   $   #"" BookEntity.java
$   #"" service
$   #"" HibernateBooksService.java
!"" bookstore
$   !"" api
$   $   #"" service
$   $   #"" BookstoreService.java
$   #"" impl
$   #"" service
$   #"" BookstoreServiceImpl.java
!"" log4j2.xml
!"" main
$   #"" Main.java
!"" main.xml
#"" module-info.java
“mods” dir for automatic modules
Single module dir (for now)
Add module-info.java
javac -cp $CLASSPATH 
--module-path mods 
-d out 
--module-source-path src 
-m bookapp
Step 2 - Add requires.
BookstoreServiceImpl.java:7: error: package
org.springframework.stereotype is not visible
import org.springframework.stereotype.Component;
Compilation error
Our module needs explicit
dependencies!
Step 3 - Add missing compile time platform
modules.
HibernateBooksService.java:19: error: cannot access Referenceable
return sessionFactory.getCurrentSession().get(BookEntity.class, id);
^
class file for javax.naming.Referenceable not found
Compilation error
Hibernate should declare
requires transitive java.naming
Running.
java -cp $CLASSPATH
--module-path mods:out
-m bookapp/main.Main
Step 4 - Add missing platform modules.
java.lang.ClassNotFoundException: java.sql.SQLException
java -cp $CLASSPATH
--add-modules java.sql,java.xml.bind
--module-path mods:out
-m bookapp/main.Main
Step 5 - Open packages for reflection.
java.lang.IllegalAccessException: class
org.springframework.beans.BeanUtils cannot access class
books.impl.service.HibernateBooksService (in module bookapp)
because module bookapp does not export books.impl.service to
unnamed module @5c45d770
opens books.impl.entities;
opens books.impl.service;
opens bookstore.impl.service;
Step 6 - Illegal deep reflection.
java.lang.reflect.InaccessibleObjectException: Unable to make
protected final java.lang.Class
java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int
,java.security.ProtectionDomain) throws
java.lang.ClassFormatError accessible: module java.base does not
"opens java.lang" to module javassist
java -cp $CLASSPATH
--add-modules java.sql,java.xml.bind
--add-opens java.base/java.lang=javassist
--module-path mods:out
-m bookapp/main.Main
Refactor to
multiple modules
Multi module structure
main
books.api books.impl
bookstore
requires
requires
requires
Spring
main
books.api books.impl
bookstore.api
requires
requires
requires
Module System
uses provides
bookstore.impl
provides
Build tools. <artifactId>bookstore</artifactId>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>9</source>
<target>9</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>javamodularity</groupId>
<artifactId>books</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
module bookstore {
requires books;
exports bookstore.service.api;
uses books.api.service.BooksService;
provides bookstore.service.api.BookstoreService with
bookstore.service.impl.BookstoreServiceImpl;
}
Thank you.
Paul Bakker
@pbakker

Migrating to java 9 modules

  • 1.
    Migrating to Java9 Modules | Paul Bakker
  • 2.
    Why care aboutmodules? lib/nebula-4.0.12.jar:lib/netflix-gradle-lint-8.6.1.jar:lib/gretty-2.0.0.jar:lib/gradle-infamous-plugin-1.28.jar:lib/java-semver-0.9.0.jar:lib/guava-20.0.jar:lib/ nebula-core-4.0.1.jar:lib/commons-lang-2.6.jar:lib/joda-time-2.9.9.jar:lib/kotlin-reflect-1.1.4-3.jar:lib/nebula-common-4.0.12.jar:lib/nebula-repos-4.0.12.jar:lib/ nebula-publish-4.0.12.jar:lib/httpclient-4.5.3.jar:lib/jgrapht-core-0.9.2.jar:lib/build-info-extractor-gradle-4.1.1.jar:lib/ant-jsch-1.9.9.jar:lib/rest-api-client- core-1.9.0.jar:lib/rest-api-client-httpclient-1.9.0.jar:lib/bakery-api-client-1.8.0.jar:lib/odin-2.0.0.jar:lib/artifactory-java-client-services-1.2.2.jar:lib/ kotlin-stdlib-jre8-1.1.4-3.jar:lib/gradle-contacts-plugin-3.0.1.jar:lib/gradle-dependency-lock-plugin-4.9.4.jar:lib/gradle-extra-configurations- plugin-3.2.0.jar:lib/gradle-git-scm-plugin-3.0.1.jar:lib/gradle-info-plugin-3.6.0.jar:lib/gradle-java-cross-compile-plugin-0.9.0.jar:lib/gradle-lint- plugin-8.3.1.jar:lib/gradle-metrics-plugin-6.0.0.jar:lib/gradle-ospackage-plugin-4.4.0.jar:lib/gradle-override-plugin-3.0.2.jar:lib/gradle-resolution-rules- plugin-5.0.2.jar:lib/gradle-scm-plugin-3.0.1.jar:lib/gradle-stash-plugin-4.0.1.jar:lib/nebula-dependency-base-plugin-0.3.0.jar:lib/nebula-dependency- recommender-5.0.0.jar:lib/nebula-grails-plugin-1.0.0.jar:lib/nebula-project-plugin-3.4.0.jar:lib/nebula-release-plugin-6.0.1.jar:lib/gradle-release-1.2.jar:lib/ gradle-cobertura-plugin-2.5.0.jar:lib/gretty-core-2.0.0.jar:lib/spring-boot-loader-tools-1.5.4.RELEASE.jar:lib/jetty-util-8.1.8.v20121106.jar:lib/httpclient- cache-4.5.2.jar:lib/kotlin-stdlib-1.1.4-3.jar:lib/metatron-decrypt-1.108.0.jar:lib/nebula-publishing-plugin-5.1.3.jar:lib/httpcore-4.4.6.jar:lib/commons- logging-1.2.jar:lib/commons-codec-1.9.jar:lib/ivy-2.2.0.jar:lib/build-info-extractor-2.5.5.jar:lib/ant-1.9.9.jar:lib/mail-1.4.4.jar:lib/frigga-0.13.jar:lib/ nekohtml-1.9.17.jar:lib/artifactory-java-client-api-1.2.2.jar:lib/groovy-xml-2.3.2.jar:lib/jcl-over-slf4j-1.7.2.jar:lib/kotlin-stdlib-jre7-1.1.4-3.jar:lib/ svnkit-1.8.12.jar:lib/asm-5.2.jar:lib/gpars-1.2.1.jar:lib/junit-4.12.jar:lib/jackson-datatype-joda-2.3.2.jar:lib/logstash-logback-encoder-4.5.1.jar:lib/ jest-0.1.7.jar:lib/fluent-hc-4.5.1.jar:lib/redline-1.2.5.jar:lib/jdeb-1.4.jar:lib/gradle-docker-plugin-3.0.1.jar:lib/commons-beanutils-core-1.8.3.jar:lib/jackson- module-kotlin-2.7.5.jar:lib/maven-model-builder-3.5.0.jar:lib/grails-launcher-1.1.jar:lib/groovy-2.4.11.jar:lib/commons-cli-1.2.jar:lib/commons- configuration-1.10.jar:lib/org.apache.servicemix.bundles.bcprov-jdk16-1.46_3.jar:lib/spring-boot-devtools-1.3.3.RELEASE.jar:lib/spring-core-4.3.9.RELEASE.jar:lib/ annotations-13.0.jar:lib/gson-2.8.0.jar:lib/protobuf-java-util-3.2.0.jar:lib/protobuf-java-3.2.0.jar:lib/grpc-core-1.3.0.jar:lib/javax.inject-1.jar:lib/metatron- common-1.108.0.jar:lib/metatron-ipc-common-1.108.0.jar:lib/build-info-client-2.5.5.jar:lib/xstream-1.3.1.jar:lib/ant-launcher-1.9.9.jar:lib/multiverse- core-0.7.0.jar:lib/jsr166y-1.7.0.jar:lib/hamcrest-core-1.3.jar:lib/logback-core-1.1.3.jar:lib/jest-common-0.1.7.jar:lib/httpcore-nio-4.4.1.jar:lib/ httpasyncclient-4.1.jar:lib/plexus-utils-3.0.24.jar:lib/plexus-interpolation-1.24.jar:lib/plexus-component-annotations-1.7.1.jar:lib/maven-model-3.5.0.jar:lib/ maven-artifact-3.5.0.jar:lib/maven-builder-support-3.5.0.jar:lib/spring-boot-1.3.3.RELEASE.jar:lib/spring-boot-autoconfigure-1.3.3.RELEASE.jar:lib/ error_prone_annotations-2.0.19.jar:lib/jsr305-3.0.0.jar:lib/grpc-context-1.3.0.jar:lib/instrumentation-api-0.3.0.jar:lib/grpc-protobuf-1.3.0.jar:lib/grpc- stub-1.3.0.jar:lib/jackson-mapper-asl-1.9.12.jar:lib/build-info-api-2.5.5.jar:lib/xpp3_min-1.1.4c.jar:lib/spring-context-4.2.5.RELEASE.jar:lib/grpc-google-common- protos-0.1.6.jar:lib/grpc-protobuf-lite-1.3.0.jar:lib/jackson-core-asl-1.9.12.jar:lib/spring-aop-4.2.5.RELEASE.jar:lib/spring-beans-4.2.5.RELEASE.jar:lib/spring- expression-4.2.5.RELEASE.jar:lib/aopalliance-1.0.jar:lib/http-builder-0.7.1.jar:lib/json-lib-2.3-jdk15.jar:lib/xml-resolver-1.2.jar:lib/commons- beanutils-1.8.0.jar:lib/commons-collections-3.2.1.jar:lib/ezmorph-1.0.6.jar:lib/slf4j-api-1.7.25.jar:lib/commons-io-2.5.jar:lib/jackson-annotations-2.7.5.jar:lib/ jackson-databind-2.7.5.jar:lib/nebula-gradle-interop-0.5.0.jar:lib/org.eclipse.jgit.ui-4.6.1.201703071140-r.jar:lib/jsch.agentproxy.jsch-0.0.9.jar:lib/ jsch.agentproxy.pageant-0.0.9.jar:lib/jsch.agentproxy.sshagent-0.0.9.jar:lib/jsch.agentproxy.usocket-jna-0.0.9.jar:lib/jsch.agentproxy.usocket-nc-0.0.9.jar:lib/ jsch.agentproxy.core-0.0.9.jar:lib/jna-4.1.0.jar:lib/jna-platform-4.1.0.jar:lib/p4java-2015.2.1365273.jar:lib/jzlib-1.1.2.jar:lib/jsch.agentproxy.svnkit-trilead- ssh2-0.0.7.jar:lib/trilead-ssh2-1.0.0-build220.jar:lib/jsch.agentproxy.connector-factory-0.0.7.jar:lib/sequence-library-1.0.3.jar:lib/sqljet-1.1.10.jar:lib/antlr- runtime-3.4.jar:lib/commons-lang3-3.5.jar:lib/gradle-git-1.7.2.jar:lib/groovy-json-2.4.11.jar:lib/commons-compress-1.8.jar:lib/bcpg-jdk15on-1.51.jar:lib/bcprov- jdk15on-1.51.jar:lib/xercesImpl-2.9.1.jar:lib/jackson-core-2.7.5.jar:lib/org.eclipse.jgit-4.6.1.201703071140-r.jar:lib/JavaEWAH-1.1.6.jar:lib/jsch-0.1.54.jar:lib/ grgit-1.9.3.jar:lib/xz-1.5.jar
  • 3.
    module easytext.cli { requireseasytext.analysis; } module easytext.analysis { exports analysis.api; opens impl; } easytext.cli easytext.analysis other analysis.api impl reflection only! Module primer.
  • 4.
    module easytext.cli { requireseasytext.analysis; } module easytext.analysis { exports analysis.api; opens impl; } easytext.cli easytext.analysis other analysis.api impl reflection only! Module primer. Modules define dependencies explicitly
  • 5.
    module easytext.cli { requireseasytext.analysis; } module easytext.analysis { exports analysis.api; opens impl; } easytext.cli easytext.analysis other analysis.api impl reflection only! Module primer. Packages are encapsulated by default
  • 6.
    module easytext.cli { requireseasytext.analysis; } module easytext.analysis { exports analysis.api; opens impl; } easytext.cli easytext.analysis other analysis.api impl reflection only! Module primer. Packages can be “opened” for deep reflection at run-time
  • 7.
    Migrating to Java9. Java 8 Java 9 java -cp … -jar MyApp.jar java -cp … -jar MyApp.jar
  • 8.
    Our journey tomodules. Running on Java 9 Using existing libraries Allowing reflection Spring / Hibernate case study Refactoring to increase modularity Migrating builds
  • 9.
    !"" lib !"" run.sh #""src !"" books $   !"" api $   $   !"" entities $   $   $   #"" Book.java $   $   #"" service $   $   #"" BooksService.java $   #"" impl $   !"" entities $   $   #"" BookEntity.java $   #"" service $   #"" HibernateBooksService.java !"" bookstore $   !"" api $   $   #"" service $   $   #"" BookstoreService.java $   #"" impl $   #"" service $   #"" BookstoreServiceImpl.java !"" log4j2.xml !"" main $   #"" Main.java #"" main.xml javac -cp [list of JARs in lib] -d out -sourcepath src $(find src -name '*.java') cp $(find src -name '*.xml') out java -cp [list of JARs in lib]:out main.Main
  • 10.
    Missing platform libraries. importjavax.xml.bind.DatatypeConverter; public class Main { public static void main(String... args) { DatatypeConverter.parseBase64Binary("SGVsbG8gd29ybGQh"); } } java.lang.ClassNotFoundException: javax.xml.bind.JAXBException
  • 11.
  • 12.
  • 13.
  • 14.
    Illegal deep reflection. WARNING:An illegal reflective access operation has occurred WARNING: Illegal reflective access by javassist.util.proxy.SecurityActions … WARNING: Please consider reporting this to the maintainers of javassist.util.proxy.SecurityActions 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
  • 15.
    Type Compile timeReflection on public Deep reflection Exports ✓ ✓ ✘ Open ✘ ✓ ✓ Exports + Open ✓ ✓ ✓
  • 16.
    Fixing illegal deepreflection. 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 java.base/java.lang=ALL-UNNAMED Main
  • 17.
  • 18.
    But we’re stillon the classpath!
  • 19.
    Let’s migrate ourcode to modules But how do we deal with libraries?
  • 20.
    package demo; import com.fasterxml.jackson.databind.ObjectMapper; publicclass 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 = mapper.writeValueAsString(modularityBook); System.out.println(json); } } module books { }
  • 21.
    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)
  • 22.
    CP=lib/jackson-annotations-2.8.8.jar: CP+=lib/jackson-core-2.8.8.jar javac -cp $CP--module-path mods -d out --module-source-path src -m books module books { requires jackson.databind; }
  • 23.
  • 24.
    Sample app aftermigration.
  • 25.
    Step 1 -Project structure. !"" lib !"" mods !"" run.sh #"" src #"" bookapp !"" books $   !"" api $   $   !"" entities $   $   $   #"" Book.java $   $   #"" service $   $   #"" BooksService.java $   #"" impl $   !"" entities $   $   #"" BookEntity.java $   #"" service $   #"" HibernateBooksService.java !"" bookstore $   !"" api $   $   #"" service $   $   #"" BookstoreService.java $   #"" impl $   #"" service $   #"" BookstoreServiceImpl.java !"" log4j2.xml !"" main $   #"" Main.java !"" main.xml #"" module-info.java “mods” dir for automatic modules Single module dir (for now) Add module-info.java javac -cp $CLASSPATH --module-path mods -d out --module-source-path src -m bookapp
  • 26.
    Step 2 -Add requires. BookstoreServiceImpl.java:7: error: package org.springframework.stereotype is not visible import org.springframework.stereotype.Component; Compilation error Our module needs explicit dependencies!
  • 27.
    Step 3 -Add missing compile time platform modules. HibernateBooksService.java:19: error: cannot access Referenceable return sessionFactory.getCurrentSession().get(BookEntity.class, id); ^ class file for javax.naming.Referenceable not found Compilation error Hibernate should declare requires transitive java.naming
  • 28.
    Running. java -cp $CLASSPATH --module-pathmods:out -m bookapp/main.Main
  • 29.
    Step 4 -Add missing platform modules. java.lang.ClassNotFoundException: java.sql.SQLException java -cp $CLASSPATH --add-modules java.sql,java.xml.bind --module-path mods:out -m bookapp/main.Main
  • 30.
    Step 5 -Open packages for reflection. java.lang.IllegalAccessException: class org.springframework.beans.BeanUtils cannot access class books.impl.service.HibernateBooksService (in module bookapp) because module bookapp does not export books.impl.service to unnamed module @5c45d770 opens books.impl.entities; opens books.impl.service; opens bookstore.impl.service;
  • 31.
    Step 6 -Illegal deep reflection. java.lang.reflect.InaccessibleObjectException: Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int ,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to module javassist java -cp $CLASSPATH --add-modules java.sql,java.xml.bind --add-opens java.base/java.lang=javassist --module-path mods:out -m bookapp/main.Main
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.