MODULSYSTEM JIGSAW IN JAVA 9 14. DEZEMBER 2016 | MARTIN LEHMANN, DR. RÜDIGER GRAMMES| IT-TAGE 2016, FRANKFURT AM MAIN EIN GEDULDSSPIEL! DAS EINSTEIGER-PUZZLE FÜR ENTWICKLER
Modularisierung und Jigsaw Reliable Configuration Ablösung des Classpath (fehleranfällig, wenn Klassen mehrfach enthalten sind – Reihenfolge). Neu: explizite Definition von Abhängigkeiten. Strong Encapsulation Eine Komponente kann ihr öffentliches API definieren und verhindern, dass auf Implementierungsgeheimnisse zugegriffen wird. Scalable Java SE Platform Die Java-Plattform selber wird modularisiert. Damit kann man individuell angepasste und „schlanke“ Plattformen bauen.
Menge von Java-Packages & Resources. Wird in ein „Modular JAR“ kompiliert. Dieses liegt im neuen Module-Path. Modul-Namen müssen eindeutig sein (. und _ sind im Namen erlaubt, - nicht) • „read“-Abhängigkeitsbeziehungen zu einem oder mehreren anderen Modulen • „exports“: Welche Packages des Moduls werden exportiert? (Default: nichts!) moda Ein Modul wird ein „First-Class-Citizen“ in Java modb read exports pkg a pkg b pkgb inter nal
Java 9: Readability und Accessibility read moda pkg a Check zu Compile-Zeit und zur Laufzeit von 1. neu: Readability „ich benötige dieses Module, will darauf zugreifen“ 2. neu: Accessibility „worauf dürfen andere zugreifen?“ (unabhg. von Classloadern!) 3. Check der „alten“ Sichtbarkeitsmodifier public,protected,<package>,private de.my. package. ximpl de.my. package. internal de.my. package exports modb
pkga1/ A1.java pkga2/ A2.java pkga3/ A3.java pkgainternal/ InternalA.java modb/ module-info.java pkgb/ B.java modc/ module-info.java pkgc/ C.java modmain/ module-info.java pkgmain/ Main.java Modul-Definition eines Modules liegt in Datei module-info.java im obersten Module-Sourcenverzeichnis. Wird kompiliert zu .class-File! Wird mit in das JAR-File paketiert. Beispiel: Vier Module moda, modb, modc, modmain und ihr Sourcenbaum module-info.java
Laufzeit- Fehler beim Start Kein „Split“ eines Packages auf zwei Modules erlaubt! Gilt auch, wenn das Package nicht exportiert ist. Selbst dann, wenn es keine Klassen-Duplikate in den beiden Modules gibt. Split Package: Modules müssen disjunkte Packages haben. Ausnahme: Gilt nicht für The Unnamed Module. src\modmainfoo\module-info.java:1: error: module modmainfoo reads package pkgfoo from both modsplitfoo1 and modsplitfoo2 module modmainfoo { ^ 1 error Error occurred during initialization of VM java.lang.reflect.LayerInstantiationException: Package pkgbar in both module modsplitbar1 and module modsplitbar2 at java.lang.reflect.Layer.fail(java.base@9-ea/Layer.java:449) at java.lang.reflect.Layer.checkBootModulesForDuplicatePkgs(java.base@9-ea/Layer.j at java.lang.reflect.Layer.defineModules(java.base@9-ea/Layer.java:357) at jdk.internal.module.ModuleBootstrap.boot(java.base@9-ea/ModuleBootstrap.java:29 at java.lang.System.initPhase2(java.base@9-ea/System.java:1925) Gilt nur für Module in einer gemeinsamen Configuration – nur auf Module-Path OK.
mit Reflection? … und mit Serialisierung, Dependency- Injection, Bytecode-Enhancement, ...? Zur Erinnerung 1. Check: Readable, über requires? 2. Check: Accessible, über exports? 3. Check von public,protected,<package>,private Gilt alles auch bei Reflection! Convenience bei Reflection: read-Beziehung ist immer vorhanden. Aber Accessibility-Checks greifen auch „scharf“ bei Reflection: Klassen von nicht exportierten Packages sind nicht zugreifbar. • Gilt für newInstance, getField, getMethod • Gilt auch für setAccessible(true)
Zugriff nur zur Laufzeit, nicht zur Compile-Zeit opens öffnet für „Deep Reflection“ mit setAccessible(true) Spezialfall „open module“: alle Packages des Moduls sind „open“ opens öffnet ein Package zur Laufzeit Zugriff … Compile-Zeit Reflection (Shallow) Reflection (Deep) exports pkg Erlaubt Erlaubt Nicht Erlaubt opens pkg Nicht Erlaubt Erlaubt Erlaubt exports pkg und opens pkg Erlaubt Erlaubt Erlaubt
Modules modfib : 4 Varianten Ein Whitebox-Test benötigt zum Test interne Klassen von modfib. Das Package pkgfib.internal ist aber nicht exportiert. modfib exports pkgfib internal pkgfib
Module modtest.whitebox Wie erhält es Zugriff auf die nicht-exportierten Klassen von modfib? Whitebox-Test eines Modules modfib : Varianten 1a, b Statische Abhängigkeit zu Testcode Etwas besser. Aber: Pflege der Skripte?! module modfib { exports pkgfib; exports pkgfibinternal to modtest.whitebox; } a) Mit „exports to“ der zu testenden Packages an modtest.whitebox javac --add-exports modfib/pkgfib.internal=modtest.whitebox java --add-exports modfib/pkgfib.internal=modtest.whitebox b) Dynamischer Export der zu testenden Packages mit --add-exports
enthält auch die Testklassen. Aber wo verwaltet man diese? Whitebox-Test eines Modules modfib : Varianten 2a, 2b Testcode wird ebenfalls paketiert und deployed a) Testklassen direkt bei modfib ablegen. Testklassen können so alle zu testenden Klassen aus modfib sehen. b) Testklassen getrennt ablegen. Zu Compile-Zeit und zur Test-Laufzeit dem Module modfib hinzufügen („Patchen“)
„echtes“ Module: Explicit Module Explicit Module in einem JAR liegt auf dem Module-Path enthält module-info Open Module ist Spezialfall eines Explicit Modules modb java. base modmain
in ein Module umwandeln: Automatic Module Module-Path modb java. base Automatic Module JAR auf den Module-Path legen modmain junit Automatisch: „reads“ auf alle Module, „exports“ aller Packages (incl. „opens“) Ein Explicit Module muss ein Automatic Module requiren. Automatischer Name: - . junit-4.12.jar junit Named Modules := Explicit Modules + Automatic Modules
Classpath: The Unnamed Module The Unnamed Module Alle JARs auf dem Classpath sind ein einziges Module Module-Path modmain modb The Unnamed Module java. base Exports aller Packages Readable durch alle(!) Automatic Modules, aber nicht durch Explicit Modules „reads“ auf alle Modules junit b.jar hibernate .jar
und The Unnamed Module interagieren Module-Path modb modmain java. base junit 1 The Unnamed Module b.jar Suchreihenfolge Module-Path The Unnamed Module Vorsicht bei gleichzeitiger Verwendung von Module-Path und The Unnamed Module! 2 hibernate .jar 1 2 pkgb. B pkgb. B Klasse pkgb.B wird in modb gefunden! Keine Fehler- meldung wie bei Split Package!
zur Visualisierung eines Modul-Graphen Ideen: req-transitive (n-transitiv), Filter auf einzelne Beziehungen, Uses/Provides, Packages, Hashes, Open, nur Module der Configuration, mehr Konfiguration mit Farben & Co … https://github.com/accso/java9-jigsaw-depvis Basiert auf GraphViz http://www.graphviz.org/ mit Java-API https://github.com/kohsuke/graphviz-api DepVis kann visualisieren: … Module im Module-Path … Module im System … mit Black- & Whitelisting … Explicit Modules und Automatic Modules … requires, requires-transitive (1-transitiv), requires-mandated, exports-to
plus Java9-Plugin (BETA): • Eclipse startet mit Java 9 • module-info: Das meiste wird erkannt, auch Sichtbarkeiten. Code-Completion für requires-Module, exports-Packages • Es fehlt: Launch-Einstellungen für Module-Path, Automatic Modules, .... Maven, Gradle, Netbeans, … bieten Unterstützung für Java 9 Mühsame Pflege wird hoffentlich durch IDEs und Build-Tools erledigt: • requires-Pflege Maven-POM Eclipse-.classpath • exports -Pflege Package-Konventionen wie „…internal“ (?) • Alle Kommandozeilenoptionen für javac und java Wie steht‘s um Tools?
noch nicht final, Diskussionen u.a. noch zu … Exporte nur zur Laufzeit, v.a. für Reflection (dynamic->Weak->Open)? Module-Abhängigkeiten nur zur Compile-Zeit („requires static“)? Laufzeit-Beziehungen lazy auflösen? Annotations für Module Deprecation für Module > 1 Module in 1 JAR (so wie Fat-JARs), dazu Multi-Release-JARs? ... Teilweise sehr fundamentale Kritik auf den Mailinglisten.
public != accessible Erster Accessibility-Level ist nun das „Package“. (Warum eigentlich?) Abhängigkeitsmodell ist sehr statisch über Namen. Kein Alias für ein Module möglich (außer --patch-module) Warum keine Scopes wie „Test“ und „Runtime“ (vgl. Maven)? Zugriffsschutz ist sehr restriktiv. Opt-in oder Opt-out? Leider keine Unterstützung von Exports-Package-Wildcards! Ein Module hat keine (echten) Versionen - nur informell module-info wird zu .class-File kompiliert. Ist aber doch gar keine Klasse. Warum nicht MANIFEST.MF? Oder wenigstens Human-Readable-Format? Modules sind nicht gruppierbar. Keine Hierarchie möglich (vgl. parent.pom) Kritik …
requires transitive Der richtige Schritt zur echter Komponentenorientierung! Jigsaw und Java 9 sind sehr stabil. Allerdings ändern sich immer noch Implementierungen (und auch Konzepte, gerade zu Reflection) Migration ist gut machbar, aber wird mühsam! • Module-Kategorien: „wo kommt was her?“ ist nicht trivial! • MP & CP: Bekommen wir das jemals richtig aussortiert? … und Lob!