Download - Advanced modular development
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
Advanced Modular Development
The current state of the Module System
Srinivasan RaghavanSenior Member of Technical StaffJava Platform [email protected] 18, 2016
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
Safe Harbor StatementThe following is intended to outline our general product direction. It is intended for information purposes only, and may not be incorporated into any contract. It is not a commitment to deliver any material, code, or functionality, and should not be relied upon in making purchasing decisions. The development, release, and timing of any features or functionality described for Oracle’s products remains at the sole discretion of Oracle.
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
Program Agenda
Project Jigsaw Introduction
Reliable configuration and Strong encapsulation
Module Types
Modules and Services
Q and A
1
2
3
4
5
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
Project Jigsaw
• JEP 200: The Modular JDK• JEP 201: Modular Source Code• JEP 220: Modular Run-Time Images• JEP 260: Encapsulate Most Internal APIs• JEP 261: Module System• JEP 282: jlink: The Java Linker
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
• java.activation@9-ea
• java.annotations.common@9-ea
• java.base@9-ea
• java.compact1@9-ea
• java.compact2@9-ea
• java.compact3@9-ea
• java.compiler@9-ea
• java.corba@9-ea
• java.datatransfer@9-ea
• java.desktop@9-ea
• java.httpclient@9-ea
• java.instrument@9-ea
• java.jnlp@9-ea
• java.logging@9-ea
• java.management@9-ea
• java.naming@9-ea
• java.prefs@9-ea
• java.rmi@9-ea
• java.scripting@9-ea
• java.se@9-ea
• java.se.ee@9-ea
• java.security.jgss@9-ea
• java.security.sasl@9-ea
• java.smartcardio@9-ea
• java.sql@9-ea
• java.sql.rowset@9-ea
• java.transaction@9-ea
• java.xml@9-ea
• java.xml.bind@9-ea
• java.xml.crypto@9-ea
• java.xml.ws@9-ea
• javafx.base@9-ea
• javafx.controls@9-ea
• javafx.deploy@9-ea
• javafx.fxml@9-ea
• javafx.graphics@9-ea
• javafx.media@9-ea
• javafx.swing@9-ea
• javafx.web@9-ea
• jdk.accessibility@9-ea
• jdk.attach@9-ea
• jdk.charsets@9-ea
• jdk.compiler@9-ea
• jdk.crypto.ec@9-ea
• jdk.crypto.pkcs11@9-ea
• jdk.deploy@9-ea
• jdk.deploy.controlpanel@9-ea
• jdk.deploy.controlpanel.fx@9-ea
• jdk.dynalink@9-ea
• jdk.hotspot.agent@9-ea
• jdk.httpserver@9-ea
• jdk.internal.le@9-ea
• jdk.internal.opt@9-ea
• jdk.jartool@9-ea
• jdk.javadoc@9-ea
• jdk.javaws@9-ea
• jdk.jcmd@9-ea
• jdk.jconsole@9-ea
• jdk.jdeps@9-ea
• jdk.jdi@9-ea
• jdk.jdwp.agent@9-ea
• jdk.jfr@9-ea
• jdk.jlink@9-ea
• jdk.jshell@9-ea
• jdk.jsobject@9-ea
• jdk.jstatd@9-ea
• jdk.jvmstat@9-ea
• jdk.localedata@9-ea
• jdk.management@9-ea
• jdk.management.cmm@9-ea
• jdk.management.jfr@9-ea
• jdk.management.resource@9-ea
• jdk.naming.dns@9-ea
• jdk.naming.rmi@9-ea
• jdk.net@9-ea
• jdk.pack200@9-ea
• jdk.packager@9-ea
• jdk.packager.services@9-ea
• jdk.plugin@9-ea
• jdk.plugin.dom@9-ea
• jdk.plugin.server@9-ea
• jdk.policytool@9-ea
• jdk.rmic@9-ea
• jdk.scripting.nashorn@9-ea
• jdk.scripting.nashorn.shell@9-ea
• jdk.sctp@9-ea
• jdk.security.auth@9-ea
• jdk.security.jgss@9-ea
• jdk.snmp@9-ea
• jdk.unsupported@9-ea
• jdk.vm.cds@9-ea
• jdk.vm.ci@9-ea
• jdk.xml.bind@9-ea
• jdk.xml.dom@9-ea
• jdk.xml.ws@9-ea
• jdk.zipfs@9-ea
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
Accessibility (JDK 1 – JDK 8)
• public
• protected
• <package>
• private
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
Accessibility (JDK 9 –)
• public to everyone
• public but only to specific modules • public only within a module
• protected
• <package>
• private
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
Let’s take a configuration
m1 m2 Appm2 requires m1 App requires m2
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
Accessibility
m1 m2 App exports com.m1.p1;
exports com.m1.p2 to m2
exports com.m1.p3;
exports com.m1.p1;
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
module m1 { exports com.m1.p1; exports com.m1.p2 to m2;}
module m2 { requires transitive m1; exports com.m2.p3;}
module app{ requires m2; exports com.app.p1; }
The module m1 and m2 module-info.java
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
package com.m1.p1;
public class Type1 {
public String whoAmI() { return " I am " + Type1.class.getSimpleName() +" from the module " + Type1.class.getModule().getName() + " from package " + Type1.class.getPackageName() + " Loaded by " + Type1.class.getModule().getClassLoader().toString(); }}
package com.m1.p2;public class Type2 { public String whoAmI() { return " I am " + Type2.class.getSimpleName() +" from the module " + Type2.class.getModule().getName() + " from package " + Type2.class.getPackageName() + " Loaded by " + Type2.class.getModule().getClassLoader().toString(); }}
The module m1 code
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
package com.m2.p3;import com.m1.p1.Type1;import com.m1.p2.Type2;
public class Type3 { private final Type1 type1 = new Type1(); private final Type2 type2 = new Type2(); public Type1 getMeType1() { return type1; } public String whoAmI() { return " I am " + Type3.class.getSimpleName() +" from the module " + Type3.class.getModule().getName() + " from package " + Type3.class.getPackageName() + " Loaded by " + Type3.class.getModule().getClassLoader().toString(); } public String whoisType2() { return type2.whoAmI(); }}
The module m2 code
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
package com.app.p1;import com.m1.p1.Type1;import com.m2.p3.Type3;class App1 { static final Type3 type3 = new Type3(); public static void main(String[] args) { System.out.println(type3.whoAmI()); System.out.println(type3.whoisType2()); System.out.println(type3.getMeType1().whoAmI()); }}
The app module code
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
$find src -name “*.java"
src//app/com/app/p1/App1.java src//app/module-info.java src//m1/com/m1/p1/Type1.java src//m1/com/m1/p2/Type2.java src//m1/module-info.java src//m2/com/m2/p3/Type3.java src//m2/module-info.java
How its structured
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
$javac -d mods --module-source-path src/ $(find src -name "*.java")
$java -p mods -m app/com.app.p1.App1 I am Type3 from the module m2 from package com.m2.p3 Loaded by jdk.internal.loader.ClassLoaders$AppClassLoader@5ae9a829 I am Type2 from the module m1 from package com.m1.p2 Loaded by jdk.internal.loader.ClassLoaders$AppClassLoader@5ae9a829 I am Type1 from the module m1 from package com.m1.p1 Loaded by jdk.internal.loader.ClassLoaders$AppClassLoader@5ae9a829
Build and run
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
$jlink --module-path $JDKMODS:mods --add-modules app --compress=2 --strip-debug --output myappimage
$myappimage/bin/java --list-modulesappjava.base@9-eam1m2$ myappimage/bin/java -m app/com.app.p1.App1 I am Type3 from the module m2 from package com.m2.p3 Loaded by jdk.internal.loader.ClassLoaders$AppClassLoader@5ae9a829 I am Type2 from the module m1 from package com.m1.p2 Loaded by jdk.internal.loader.ClassLoaders$AppClassLoader@5ae9a829 I am Type1 from the module m1 from package com.m1.p1 Loaded by jdk.internal.loader.ClassLoaders$AppClassLoader@5ae9a829
Create your own JDK
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
What we can infer• As we can see from the code and module-info Type2 is exported only to m2
which means app module cannot directly access it • Type1 is return value of a method in Type3 so Type1 is transitively exported
to app module• If the app says Type2 type = new Type2() would fail to compile • Type2 class code can be only accessible to m2 • This ensures a reliable configuration. It also ensures the Type2 is
encapsulated and its used only where it is meant to.
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
$javac -d mods --module-source-path src/ $(find src -name “*.java")
src/app/com/app/p1/App2.java:8: error: Type2 is not visible because package com.m1.p2 is not visibleimport com.m1.p2.Type2; ^src/app/com/app/p1/App2.java:18: error: cannot find symbol Type2 type = new Type2(); ^ symbol: class Type2 location: class App2src/app/com/app/p1/App2.java:18: error: cannot find symbol Type2 type = new Type2(); ^ symbol: class Type2 location: class App23 errors
Type2 accessed by the App module
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
Modules Types• Name Module - A module With module-info.java with both exports and
requires specified• Automatic Module - Any Jar in ModulePath. The module info is auto-
generated which exports all package and requires all other mods• Unnamed Module- All the jars which reside in the class-path togethers is
Unnamed Module
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
Accessibility and Class Loaders
Loader 1Class p1.Type1
Delegates
Loader 2Class p2.Type2
Loader 1Class p1.Type1
Loader 2Class p2.Type2
No access
No delegation
Access
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
Class Loading in JDK 9
BootStrap Loader
JVM
Application LoaderPlatform Loader
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
Layers and Loaders
BootStrap Loaderjava.base
java.logging
JVM
Application Loaderm1m2
Platform Loaderjava.sql
java. corba
Hadoop Layer hadoop
guava@11
Java Script Layerclosure-compiler
guava@18
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
Layers and Loaders• Boot layer is place where the entire JDK rest • More than one layers can be added• A Layer can have one class loader for each module in the layer • Layer can be used to get around the split package issue
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
public Unsafe getUnsafe() throws Exception {
Unsafe unsafe =Unsafe.getUnsafe(); }
public Unsafe someHowGetUnsafe() throws Exception {
Field field = Unsafe.class.getDeclaredField("theUnsafe"); field.setAccessible(true); Unsafe unsafe = (Unsafe) field.get(null); return unsafe; }
Problems with un encapsulated code
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
Problems with un encapsulated code• com.sun.misc.Unsafe is important code widely used inside JDK but not not
meant for out use• In Java8 getUnsafe() would fail with java.lang.SecurityException: Unsafe .
There would be clever check in code to see whether only Jdk classes call unsafe• But with some clever reflection hacks someHowGetUnsafe() would pass • In Java 9 both would fail with
java.lang.IllegalAccessError:jdk.internal.misc.Unsafe (in module java.base) because module java.base does not export jdk.internal.misc to unnamed module
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
Modules And Services• Services are first class citizens in the Module System• The provide the basic loose-coupling between the Service Types and the their
Implementation• Any Interface or abstract class be a Service Type• Service Types and the their Implementation can be in any module and they
follow the following semantics• when a module use a Service the module-info carries a “use” Service• when a module provide an Implementation for the Service the module-info
carries “provides” service “with” Impl
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
Modules And Servicesmodule m1 { exports com.m1.p1; exports com.m1.p2 to m2;}
module m2{requires public m1;exports com.m2.p3;provides com.m1.p1.Service1 with com.m2.p3.Impl1;provides com.m1.p1.Service1 with com.m2.p3.Impl2;
}
module app{requires m2;exports com.app.p1;uses com.m1.p1.Service1;
}
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
Modules And Services public static void main(String[] args) { getImpl("com.m2.p3.Imp1"); }
public static Service getImpl(String impl) { Service service = null; Optional<Provider<Service>> oprovider = ServiceLoader.load(Service.class) .stream() .fiter(p -> p.type().getName().equals(impl) .map(Provider::get) .findFirst(); if (oprovider.isPresent()) { Provider<Service> provider = oprovider.get(); service = provider.get(); } return service; }
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
ReflectiveAccessToNonExportedTypes
• Some libraries require reflective access to members of the non-exported types of other modules• Access to non-exported packages can, at present, only be done via
command-line flags• Providing an easier way for reflective code to access such non-exported
types is needed
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
AwkwardStrongEncapsulation
• A non-public element of an exported package can still be accessed via the `AccessibleObject::setAccessible` method of the core reflection API• The only way to strongly encapsulate such an element is to move it to a
non-exported package• This makes it awkward, at best, to encapsulate the internals of a package
that defines a public API
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
Open modules• Open modules make it easy to define modules whose internals will be
accessed at run time by reflection-based frameworks• A package in an open module can be exported explicitly, for use at compile
time• The internal packages are only exposed at run time for reflection
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
Open Module
open module foo.bar { exports com.foo.bar; requires hibernate.core; requires hibernate.entitymanager; }
module foo.bar { exports com.foo.bar; opens com.foo.bar.model; requires hibernate.core; requires hibernate.entitymanager; }
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
References• http://openjdk.java.net/projects/jigsaw/spec/issues/#ReflectiveAccessToN
onExportedTypes• http://openjdk.java.net/projects/jigsaw/spec/reqs/• http://hg.openjdk.java.net/jigsaw/jake• http://download.java.net/java/jigsaw/docs/api/index.html• http://openjdk.java.net/projects/jigsaw/talks/• https://www.youtube.com/channel/UCdDhYMT2USoLdh4SZIsu_1g/videos