Java 9 Modularity
in Action
By Paul Bakker & Sander Mak
@Sander_Mak
Today's journey
Modularity matters
Java 9 modules
Services
Linking
Migration
Modularity matters
Modularity is the ultimate
agile tool
Good fences
make good neighbours
Module
Service contract
Hide your internals!
Java 9: Jigsaw, JSR-376
Work in progress!
Goals
‣ Modularise the JDK
‣ Reliable application composition
‣ Strong encapsulation - hide platform internals
‣ Improved security
Current status
‣ JDK 9 modularised
‣ JSR 376 prototype (Jigsaw)
‣ No finalized spec yet
History of Jigsaw
JSR-294
Improved
Java 7: Java 8:
JSR-291 Modularity
No Jigsaw No Jigsaw
'OSGi 4.1' Support
2005 2006 2011 2014
JSR-277 JSR-376
Java Java Platform
Module Module
System System
JEP 200: The Modular JDK
Goodbye classpath
Reliable configuration
Goodbye classpath
Modules with explicit dependencies
requires
my-module other-module
Strong encapsulation
Hide your internals
java.base
requires java.lang
my-module java.time
java.util
com.sun.*
sun.*
jdk.internal.*
Access checks at VM level (even reflection)
Why not just use OSGi?
‣ OSGi is built on top of the JVM
‣ Can’t be used to modularise the JDK itself
Why not just use OSGi?
‣ OSGi is built on top of the JVM
‣ Can’t be used to modularise the JDK itself
Why not only modularise the JDK?
‣ Fair point :-)
‣ OSGi has never seen mass adoption, Java 9 will
bring modularity to all of us
Demo: EasyText
Analyze text complexity
easytext.cli
requires
easytext.analyis
Contracts & Services
MyInterface i = new MyImpl();
How to use code
that you can’t access?
Contracts & Services
Lookup
Register service
service Service
Provider Consumer
module Registry module
Return
service
instance
Use an interface as contract
JSR-376 services
module myApi {
exports com.api;
}
JSR-376 services
module myApi { module myConsumer {
exports com.api; requires myApi;
} uses com.api.MyService;
}
JSR-376 services
module myApi { module myConsumer {
exports com.api; requires myApi;
} uses com.api.MyService;
}
module myProvider {
requires myApi;
provides com.api.MyService
with myProvider.MyServiceImpl;
}
‣ Services resolved and wired by modular runtime
‣ Use with 'enhanced' ServiceLoader API
JSR-376 services
module myApi { module myConsumer {
exports com.api; requires myApi;
} uses com.api.MyService;
}
Iterable<MyService> services = module myProvider {
ServiceLoader.load(MyService.class); requires myApi;
provides com.api.MyService
for(MyService svc: services) { with myProvider.MyServiceImpl;
svc.doSomething(); }
}
‣ Services resolved and wired by modular runtime
‣ Use with 'enhanced' ServiceLoader API
Demo: EasyText
Extensibility
Demo: EasyText
Extensibility
Multiple algorithms:
‣ Flesch-Kincaid
‣ Coleman-Liau
Demo: EasyText
Extensibility
CLI & GUI?
Multiple algorithms:
‣ Flesch-Kincaid
‣ Coleman-Liau
Demo: EasyText
Application JDK
easytext.cli javafx.graphics
easytext.algorithm.api
easytext.gui javafx.controls
easytext.algorithm.kincaid
easytext.algorithm.coleman
Demo: EasyText
Application JDK
easytext.cli javafx.graphics
easytext.algorithm.api
easytext.gui javafx.controls
easytext.algorithm.kincaid
ServiceLoader
easytext.algorithm.coleman
JSR-376 linking
‣ Use a linking tool (jlink) to create a custom 'runtime
image' with only the modules you need
‣ Uses explicit dependencies from module-info.class
‣ Allows for whole-program optimization
jdk.base my.mod1
jdk.desktop my.mod2
JVM
Runtime image
Demo: EasyText linking
Preparing for Java 9
‣ Use jdeps to audit your code
‣ Escape hatch:
--add-exports java.base/javax.security.auth.x500=mymod
‣ Gradual migration possible
‣ Mix classpath & modulepath
‣ Automatic modules
Top down migration
commons.lang3.3.4.jar demonstrator.jar
classpath
java.base module path
Classic classpath
package com.javamodularity.demonstrator;
import org.apache.commons.lang3.StringUtils;
public class Demo {
public static void main(String args[]) {
String output = StringUtils.leftPad("Leftpad FTW!", 20);
System.out.println(output);
}
}
Classic classpath
package com.javamodularity.demonstrator;
import org.apache.commons.lang3.StringUtils;
public class Demo {
public static void main(String args[]) {
String output = StringUtils.leftPad("Leftpad FTW!", 20);
System.out.println(output);
}
}
Compile javac -cp lib/commons-lang3-3.4.jar
-d out $(find src -name '*.java')
Run java -cp out:lib/commons-lang3-3.4.jar
com.javamodularity.demonstrator.Demo
Top down migration
commons.lang3.3.4.jar demonstrator.jar
classpath
java.base module path
Top down migration
commons.lang3.3.4.jar
classpath
Can’t reference the classpath
from named modules!
demonstrator.jar
java.base module path
Top down migration
classpath
demonstrator.jar
commons.lang
But this isn’t our code!
java.base module path
Automatic Modules
‣ A plain JAR on the module path becomes an
Automatic Module
‣ Module name derived from JAR name
‣ Exports everything
‣ Reads all other modules
Using Automatic Modules
module demonstrator {
requires commons.lang3;
}
Using Automatic Modules
module demonstrator {
requires commons.lang3;
}
Compile javac --module-path lib
--module-source-path src
-d mods $(find src -name '*.java')
Run java --module-path mods:lib
-m demonstrator/com.javamodularity.demonstrator.Demo
Open issues
‣ List of open issues
http://openjdk.java.net/projects/jigsaw/
spec/issues/
‣ Optional dependencies
‣ Resource Encapsulation
‣ 'Open' Reflection
‣ Module versioning
Java 9's promise
‣ JSR-376 forces module-aware tooling
‣ Modularity throughout all
development phases
Java 9's promise
‣ JSR-376 forces module-aware tooling
‣ Modularity throughout all
development phases
Spotlight on modularity == good
Thank you.
see: bit.ly/java9book
Follow @javamodularity