35

Advanced modular development

Embed Size (px)

Citation preview

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

Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |

Question and Answers