This talk is for a very important new feature in Java SE 9. Code named Jigsaw, this feature modularizes the Java SE platform.
The coolest thing we do here is to create a custom JRE
Code: https://bitbucket.org/stybz/jigsaw.sty/
PPT: https://www.slideshare.net/mihailstoynov/modules-in-java-finally-openjdk-jigsaw
Video: https://www.youtube.com/watch?v=W5LeNPtPrqw
2. 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
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
5. 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
7. Why do we need jigsaw? 3
⢠Classpath is messy
8. 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
9. 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
10. 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
11. 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
12. Problem: JRE code is not modular 200
Check out the java.compact{1..3}
13. 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)
14. 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
15. 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)
16. 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
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 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
22. 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
23. 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
24. Running a multi module 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
27. 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
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 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
31. 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
32. 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();
}
33. 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);
}
34. 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);
}
}
35. 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
37. 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
39. 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