KEMBAR78
Modules in Java? Finally! (OpenJDK 9 Jigsaw, JSR376) | PPTX
Modules in Java? Finally!
Jigsaw
What is this talk all about? (Agenda)
• This talk is for a very important new feature in Java SE 9
• Code named Jigsaw, this feature modularizes the Java SE platform
• Agenda
• Who am I?
• Problems with monolithic java
• Solutions in Java SE 9
• Jigsaw in examples
• JDK9 Early Access with Jigsaw
• A modular example, transitivity
• Services and Custom JREs
Who am I? @mihailstoynov
• By day: sty.bz
• Java
• Security audits, web pen testing, sec tools
• Training, travelling ->
• By night: jug.bg
• Java evangelism
• Submitting Java patches, writing manuals,
early adoption
• jprime.io – organize big java conf in Sofia
• Co-authoring books, university courses
• Weekends
• Bikes
Problems with a monolithic Java
Why do we need jigsaw? 1
• "Small" devices can run Java,
but JRE size is a problem
• Clouds don't like wasting resources
loading a large JRE full of
unnecessary classes
Why do we need jigsaw? 2
• JDK is messy
Why do we need jigsaw? 3
• Classpath is messy
Why do we need jigsaw? 4
• People use sun.misc.* or *.internal.* APIs, which was not intended
• Securing the platform is difficult if everyone can read anything
Problem: source code is monolithic 201
• JRE source code itself is monolithic – it has no modules
• Solution (JEP 201)
• Reorganize mercurial repo
• src/share/classes/java/lang/Object.java
src/share/native/java/lang/Object.c
->
src/java.base/share/classes/java/lang/Object.java
src/java.base/share/native/java/lang/Object.c
• Rename solaris to unix
• Compile repo -> compile modules
• Enforce module boundaries at build time
Problem: JRE code is not modular 200
• JRE itself is not using modules
• Solution (JEP 200)
• Create modules for code governed by JCP (module java.base)
• Modules for other code in the JDK (module jdk.javadoc )
• Define requires public
• All reside in $JAVA_HOME/jmods
Offtopic: jmods are not for you
• .jmod format was created for the platform
• can have native code
• Overall very cool
• $ jmod list $JAVA_HOME/jmods/java.base.jmod
--list of classes—-
--native code too (so, dylib)--
• $ jmod describe $JAVA_HOME/jmods/java.base.jmod
• Describes what it exports, what it conceals, who it exports it too
and stuff
Problem: JRE code is not modular 200
Check out the java.compact{1..3}
Problem: Internal APIs 260
• Many are using internal APIs (example: sun.misc.Unsafe)
• Solution (JEP 260)
• Provide safe alternative (other JEPs)
• Non critical (Base64Decoder) are encapsulated or deprecated
• Critical APIs (Unsafe) are rewritten and encapsulated (JEP 259)
Problem: JRE is too big 282
• The JRE is too big
• Some distributions are over 100MB
• In mobile devices: CPU is strong enough for java, but little space
• Solution (JEP 282)
• In Java 9 we can create a "custom runtime image"
• A tool that can do that is called jlink
• The same tool can also add our
application modules
• Only the ones we need
Problem: Put it all together 261 (376)
• JSR 376 (Java Platform Module System) proposes changes and
extensions to
• the Java programming language
• the Java virtual machine
• the standard Java APIs
• JSR 376 Will be implemented in JEP 261
• JCP = Java Community Process (IBM, SAP, RedHat "participate")
• JSR = Java Specification Request (specifies new standards, JCP)
• JEP = Java Enhancement Process (implementations, non JCP)
More problems
• The base classes had a lot of cyclic dependencies
• They had to be unwounded
• It took several years to specify the module format
• Several abandoned formats so far
• It took several years to specify the scope of Jigsaw
• For example no dynamic loading/unloading
• No luck for OSGi
• Mark Reinhold said that this will not be implemented soon
Jigsaw in examples
Modules
JDK9 Early Access with Jigsaw
• jdk9.java.net/jigsaw
pre-Java9 class visibility
• Until Java 9 a class had the following visibility "levels":
• public
• friendly, package private (includes protected)
• protected
• private
post-Java9 class visibility
• In Java 9 new levels of "public" are provided:
• public
• To all
• To some modules (we specify them)
• Only to our module
• friendly, package private (includes protected)
• protected
• private
Creating a simple module bz.sty.logger
• Important note: just like packages, module names are dir names
• module-info.java
module bz.sty.logger {
requires java.base; //implicit
exports bz.sty.logger;
}
• Logger.java
package bz.sty.logger;
public class Logger {
public void log(String message) {
System.out.println("Logger: "+message);
}
}
• Compilation
$ javac -d mods/ 
Logger/bz.sty.logger/bz/sty/logger/Logger.java 
Logger/bz.sty.logger/module-info.java
Referencing the log module bz.sty.main
• module-info.java:
module bz.sty.main {
requires bz.sty.logger; //implicit
//exports bz.sty.logger;
}
• Program.java
public class Program {
public void main(String... args) {
new Logger.log("Hello, World!");
}
}
• Compilation
$ javac -d mods 
-modulepath mods/ 
Main/bz.sty.main/bz/sty/main/Program.java 
Main/bz.sty.main/module-info.java
Compile multiple modules at once
$ javac 
-d mods/ 
-modulesourcepath Logger/:Main/ 
$(find Logger/ Main/ -name *.java)
• What did we do here?
• All source paths are in modulesourcepath
• We use a bit of bash magic to add all java files
• All should be deployed
Running a multi module app
$ java 
-modulepath mods/ 
-m bz.sty.main/bz.sty.main.Program
Logger: Hello, World!
Support for Jigsaw
• Maven, Gradle
• None
• IntelliJ IDEA, Eclipse
• None
• I use IDEA modules and duplicate the dependencies
• NetBeans
• http://wiki.netbeans.org/JDK9Support
• But I don't like it, so we won't use it
• When will it be released
• With Java SE 9
• Used to be mid'2016, jigsaw delayed it to Q1'2017
• http://www.java9countdown.xyz/
• Nobody believes it will be on time
Packaging
$ mkdir mlib
$ jar --create 
--file=mlib/bz.sty.logger@2.0.jar 
--module-version=199.0 
-C mods/bz.sty.logger .
$ jar --create 
--file=mlib/bz.sty.main.jar 
--main-class=bz.sty.main.Program 
-C mods/bz.sty.main .
$ java -mp mlib -m bz.sty.main
Logger: Hello, World!
What's in the jar?
$ jar --print-module-descriptor 
--file=mlib/bz.sty.main.jar
bz.sty.main
requires bz.sty.logger
requires mandated java.base
conceals bz.sty.main
main-class bz.sty.main.Program
$ jar --print-module-descriptor 
--file=mlib/bz.sty.logger@2.0.jar
bz.sty.logger@199.0
requires java.base
exports bz.sty.logger
Transitivity ("requires public")
• We create a new module, called prettylogger
• public class PrettyLogger extends Logger
• We change dependencies so that main  prettylogger  logger
• The new main:
public class Program {
public static void main(String... args) {
Logger logger = new PrettyLogger();
logger.log("Hello, World!");
}
}
• module-info.java
module bz.sty.prettylogger {
requires public bz.sty.logger;
exports bz.sty.prettylogger;
}
Quering the JDK module system
• $ java –listmods
• List all modules in the JDK
• Shows the version
• $ jmod describe $JAVA_HOME/jmods/java.base.jmod
• Shows a very detailed description
• $ jmod list $JAVA_HOME/jmods/java.base.jmod
• A list of all classes in the jmod
Jigsaw in examples
Services
Services
• Services allow for loose coupling between service
consumers modules and service providers modules
• Since Java SE 6, ServiceLoader API allows extending applications
• SL detects implementations of an interface and loads them
• This solution still works nicely with Java modules
• It is now sufficient the modules to be present on module-path
• Basically we define an interface/abstract class and we state that we
depend on their implementations
• we cant run without an implementation
• Other modules implement that interface/abstract class
• All is defined in the module-info
The module and the provider
module bz.sty.pluggablelogger {
exports bz.sty.pluggablelogger;
exports bz.sty.pluggablelogger.spi;
uses bz.sty.pluggablelogger.spi.PluggableLoggerProvider;
}
public abstract class PluggableLoggerProvider {
protected PluggableLoggerProvider() { }
public abstract PluggableLogger getPluggableLogger();
}
PluggableLogger
public abstract class PluggableLogger {
public static PluggableLogger get() {
ServiceLoader<PluggableLoggerProvider> sl
= ServiceLoader.load(PluggableLoggerProvider.class);
Iterator<PluggableLoggerProvider> iter = sl.iterator();
if (!iter.hasNext())
throw new RuntimeException("No service providers found!");
PluggableLoggerProvider provider = iter.next();
return provider.getPluggableLogger();
}
protected PluggableLogger() { }
public abstract void log(String message);
}
SuperLogger (implementing module)
module bz.sty.superlogger {
requires bz.sty.pluggablelogger;
exports bz.sty.superlogger;
provides bz.sty.pluggablelogger.spi.PluggableLoggerProvider
with bz.sty.superlogger.SuperLoggerProvider;
}
public class SuperLoggerProvider extends PluggableLoggerProvider {
public PluggableLogger getPluggableLogger() {
return new SuperLogger();
}
}
public class SuperLogger extends PluggableLogger {
public void log(String message) {
System.out.println("SuperLogger: " + message);
}
}
Running it all together
$ javac -d mods –modulesourcepath 
PluggableLogger:PluggableLoggerImpl:PluggableLoggerMain
$(find Pluggable* -name *.java)
$ jar --create --file=X.jar –C mods/mdl .
$ java -mp mlib/ -m bz.sty.pluggableloggerexample
SuperLogger: Hello, World!
$ java -Xdiag:resolver
Jigsaw in examples
Custom JREs
(Jlink)
Create a custom JRE
• And now a drum roll for the coolest feature
• We hinted that it's now possible to create custom JREs
• The tool is called JLINK
• jlink takes the smallest set of needed jars and jmods and creates a
new JRE in a dir. Very WOW
jlink in action (example)
$ jlink --modulepath $JAVA_HOME/jmods:mlib 
--addmods bz.sty.pluggablelogger,
bz.sty.superlogger,
bz.sty.pluggableloggerexample 
--output CustomVM
$ CustomVM/bin/java -listmods
$ CustomVM/bin/java -m bz.sty.pluggableloggerexample
SuperLogger: Hello, World!
$ du –sh CustomVM/
30M
$ du -sh $JAVA_HOME
408M
Stuff we didn't discuss, but it's important
• Jdeps
• A tool to check if you use internal APIs
• Unnamed modules
• All old jars
• Automatic modules
• Making old jars to modules
• Migrating an application gradually
• Not difficult at all, but only after IntelliJ/Eclipse and maven support
• The console is difficult
• Mixing --classpath and --modulepath
• It takes some getting used to
Jigsaw in examples
Q&A

Modules in Java? Finally! (OpenJDK 9 Jigsaw, JSR376)

  • 1.
    Modules in Java?Finally! Jigsaw
  • 2.
    What is thistalk all about? (Agenda) • This talk is for a very important new feature in Java SE 9 • Code named Jigsaw, this feature modularizes the Java SE platform • Agenda • Who am I? • Problems with monolithic java • Solutions in Java SE 9 • Jigsaw in examples • JDK9 Early Access with Jigsaw • A modular example, transitivity • Services and Custom JREs
  • 3.
    Who am I?@mihailstoynov • By day: sty.bz • Java • Security audits, web pen testing, sec tools • Training, travelling -> • By night: jug.bg • Java evangelism • Submitting Java patches, writing manuals, early adoption • jprime.io – organize big java conf in Sofia • Co-authoring books, university courses • Weekends • Bikes
  • 4.
    Problems with amonolithic Java
  • 5.
    Why do weneed jigsaw? 1 • "Small" devices can run Java, but JRE size is a problem • Clouds don't like wasting resources loading a large JRE full of unnecessary classes
  • 6.
    Why do weneed jigsaw? 2 • JDK is messy
  • 7.
    Why do weneed jigsaw? 3 • Classpath is messy
  • 8.
    Why do weneed jigsaw? 4 • People use sun.misc.* or *.internal.* APIs, which was not intended • Securing the platform is difficult if everyone can read anything
  • 9.
    Problem: source codeis monolithic 201 • JRE source code itself is monolithic – it has no modules • Solution (JEP 201) • Reorganize mercurial repo • src/share/classes/java/lang/Object.java src/share/native/java/lang/Object.c -> src/java.base/share/classes/java/lang/Object.java src/java.base/share/native/java/lang/Object.c • Rename solaris to unix • Compile repo -> compile modules • Enforce module boundaries at build time
  • 10.
    Problem: JRE codeis not modular 200 • JRE itself is not using modules • Solution (JEP 200) • Create modules for code governed by JCP (module java.base) • Modules for other code in the JDK (module jdk.javadoc ) • Define requires public • All reside in $JAVA_HOME/jmods
  • 11.
    Offtopic: jmods arenot for you • .jmod format was created for the platform • can have native code • Overall very cool • $ jmod list $JAVA_HOME/jmods/java.base.jmod --list of classes—- --native code too (so, dylib)-- • $ jmod describe $JAVA_HOME/jmods/java.base.jmod • Describes what it exports, what it conceals, who it exports it too and stuff
  • 12.
    Problem: JRE codeis not modular 200 Check out the java.compact{1..3}
  • 13.
    Problem: Internal APIs260 • Many are using internal APIs (example: sun.misc.Unsafe) • Solution (JEP 260) • Provide safe alternative (other JEPs) • Non critical (Base64Decoder) are encapsulated or deprecated • Critical APIs (Unsafe) are rewritten and encapsulated (JEP 259)
  • 14.
    Problem: JRE istoo big 282 • The JRE is too big • Some distributions are over 100MB • In mobile devices: CPU is strong enough for java, but little space • Solution (JEP 282) • In Java 9 we can create a "custom runtime image" • A tool that can do that is called jlink • The same tool can also add our application modules • Only the ones we need
  • 15.
    Problem: Put itall together 261 (376) • JSR 376 (Java Platform Module System) proposes changes and extensions to • the Java programming language • the Java virtual machine • the standard Java APIs • JSR 376 Will be implemented in JEP 261 • JCP = Java Community Process (IBM, SAP, RedHat "participate") • JSR = Java Specification Request (specifies new standards, JCP) • JEP = Java Enhancement Process (implementations, non JCP)
  • 16.
    More problems • Thebase classes had a lot of cyclic dependencies • They had to be unwounded • It took several years to specify the module format • Several abandoned formats so far • It took several years to specify the scope of Jigsaw • For example no dynamic loading/unloading • No luck for OSGi • Mark Reinhold said that this will not be implemented soon
  • 17.
  • 18.
    JDK9 Early Accesswith Jigsaw • jdk9.java.net/jigsaw
  • 19.
    pre-Java9 class visibility •Until Java 9 a class had the following visibility "levels": • public • friendly, package private (includes protected) • protected • private
  • 20.
    post-Java9 class visibility •In Java 9 new levels of "public" are provided: • public • To all • To some modules (we specify them) • Only to our module • friendly, package private (includes protected) • protected • private
  • 21.
    Creating a simplemodule bz.sty.logger • Important note: just like packages, module names are dir names • module-info.java module bz.sty.logger { requires java.base; //implicit exports bz.sty.logger; } • Logger.java package bz.sty.logger; public class Logger { public void log(String message) { System.out.println("Logger: "+message); } } • Compilation $ javac -d mods/ Logger/bz.sty.logger/bz/sty/logger/Logger.java Logger/bz.sty.logger/module-info.java
  • 22.
    Referencing the logmodule bz.sty.main • module-info.java: module bz.sty.main { requires bz.sty.logger; //implicit //exports bz.sty.logger; } • Program.java public class Program { public void main(String... args) { new Logger.log("Hello, World!"); } } • Compilation $ javac -d mods -modulepath mods/ Main/bz.sty.main/bz/sty/main/Program.java Main/bz.sty.main/module-info.java
  • 23.
    Compile multiple modulesat once $ javac -d mods/ -modulesourcepath Logger/:Main/ $(find Logger/ Main/ -name *.java) • What did we do here? • All source paths are in modulesourcepath • We use a bit of bash magic to add all java files • All should be deployed
  • 24.
    Running a multimodule app $ java -modulepath mods/ -m bz.sty.main/bz.sty.main.Program Logger: Hello, World!
  • 25.
    Support for Jigsaw •Maven, Gradle • None • IntelliJ IDEA, Eclipse • None • I use IDEA modules and duplicate the dependencies • NetBeans • http://wiki.netbeans.org/JDK9Support • But I don't like it, so we won't use it • When will it be released • With Java SE 9 • Used to be mid'2016, jigsaw delayed it to Q1'2017 • http://www.java9countdown.xyz/ • Nobody believes it will be on time
  • 26.
    Packaging $ mkdir mlib $jar --create --file=mlib/bz.sty.logger@2.0.jar --module-version=199.0 -C mods/bz.sty.logger . $ jar --create --file=mlib/bz.sty.main.jar --main-class=bz.sty.main.Program -C mods/bz.sty.main . $ java -mp mlib -m bz.sty.main Logger: Hello, World!
  • 27.
    What's in thejar? $ jar --print-module-descriptor --file=mlib/bz.sty.main.jar bz.sty.main requires bz.sty.logger requires mandated java.base conceals bz.sty.main main-class bz.sty.main.Program $ jar --print-module-descriptor --file=mlib/bz.sty.logger@2.0.jar bz.sty.logger@199.0 requires java.base exports bz.sty.logger
  • 28.
    Transitivity ("requires public") •We create a new module, called prettylogger • public class PrettyLogger extends Logger • We change dependencies so that main  prettylogger  logger • The new main: public class Program { public static void main(String... args) { Logger logger = new PrettyLogger(); logger.log("Hello, World!"); } } • module-info.java module bz.sty.prettylogger { requires public bz.sty.logger; exports bz.sty.prettylogger; }
  • 29.
    Quering the JDKmodule system • $ java –listmods • List all modules in the JDK • Shows the version • $ jmod describe $JAVA_HOME/jmods/java.base.jmod • Shows a very detailed description • $ jmod list $JAVA_HOME/jmods/java.base.jmod • A list of all classes in the jmod
  • 30.
  • 31.
    Services • Services allowfor loose coupling between service consumers modules and service providers modules • Since Java SE 6, ServiceLoader API allows extending applications • SL detects implementations of an interface and loads them • This solution still works nicely with Java modules • It is now sufficient the modules to be present on module-path • Basically we define an interface/abstract class and we state that we depend on their implementations • we cant run without an implementation • Other modules implement that interface/abstract class • All is defined in the module-info
  • 32.
    The module andthe provider module bz.sty.pluggablelogger { exports bz.sty.pluggablelogger; exports bz.sty.pluggablelogger.spi; uses bz.sty.pluggablelogger.spi.PluggableLoggerProvider; } public abstract class PluggableLoggerProvider { protected PluggableLoggerProvider() { } public abstract PluggableLogger getPluggableLogger(); }
  • 33.
    PluggableLogger public abstract classPluggableLogger { public static PluggableLogger get() { ServiceLoader<PluggableLoggerProvider> sl = ServiceLoader.load(PluggableLoggerProvider.class); Iterator<PluggableLoggerProvider> iter = sl.iterator(); if (!iter.hasNext()) throw new RuntimeException("No service providers found!"); PluggableLoggerProvider provider = iter.next(); return provider.getPluggableLogger(); } protected PluggableLogger() { } public abstract void log(String message); }
  • 34.
    SuperLogger (implementing module) modulebz.sty.superlogger { requires bz.sty.pluggablelogger; exports bz.sty.superlogger; provides bz.sty.pluggablelogger.spi.PluggableLoggerProvider with bz.sty.superlogger.SuperLoggerProvider; } public class SuperLoggerProvider extends PluggableLoggerProvider { public PluggableLogger getPluggableLogger() { return new SuperLogger(); } } public class SuperLogger extends PluggableLogger { public void log(String message) { System.out.println("SuperLogger: " + message); } }
  • 35.
    Running it alltogether $ javac -d mods –modulesourcepath PluggableLogger:PluggableLoggerImpl:PluggableLoggerMain $(find Pluggable* -name *.java) $ jar --create --file=X.jar –C mods/mdl . $ java -mp mlib/ -m bz.sty.pluggableloggerexample SuperLogger: Hello, World! $ java -Xdiag:resolver
  • 36.
  • 37.
    Create a customJRE • And now a drum roll for the coolest feature • We hinted that it's now possible to create custom JREs • The tool is called JLINK • jlink takes the smallest set of needed jars and jmods and creates a new JRE in a dir. Very WOW
  • 38.
    jlink in action(example) $ jlink --modulepath $JAVA_HOME/jmods:mlib --addmods bz.sty.pluggablelogger, bz.sty.superlogger, bz.sty.pluggableloggerexample --output CustomVM $ CustomVM/bin/java -listmods $ CustomVM/bin/java -m bz.sty.pluggableloggerexample SuperLogger: Hello, World! $ du –sh CustomVM/ 30M $ du -sh $JAVA_HOME 408M
  • 39.
    Stuff we didn'tdiscuss, but it's important • Jdeps • A tool to check if you use internal APIs • Unnamed modules • All old jars • Automatic modules • Making old jars to modules • Migrating an application gradually • Not difficult at all, but only after IntelliJ/Eclipse and maven support • The console is difficult • Mixing --classpath and --modulepath • It takes some getting used to
  • 40.

Editor's Notes

  • #4 SOFIA JUG ?! OPEN JUG.bg