Upgrade to Pro — share decks privately, control downloads, hide ads and more …

in Geduldsspiel! Das Einsteiger-Puzzle für Entwickler. Das neue Modulsystem Jigsaw in Java 9

in Geduldsspiel! Das Einsteiger-Puzzle für Entwickler. Das neue Modulsystem Jigsaw in Java 9

Martin Lehmann, Rüdiger Grammes, Kristine Schaal: „Ein Geduldsspiel! Das Einsteiger-Puzzle für Entwickler. Das neue Modulsystem Jigsaw in Java 9“.
Vortrag bei der Java User Group Frankfurt, 21. Dezember 2016

https://sites.google.com/site/jugffm/home/21-12-2016-ein-geduldsspiel-das-1000-module-puzzle-fuer-entwickler---das-neue-modulsystem-jigsaw-in-java-9

Martin Lehmann

December 21, 2016
Tweet

More Decks by Martin Lehmann

Other Decks in Programming

Transcript

  1. Copyright © Accso – Accelerated Solutions GmbH 1 DAS NEUE

    MODULSYSTEM JIGSAW IN JAVA 9 21. DEZEMBER 2016 | DR. RÜDIGER GRAMMES, MARTIN LEHMANN, DR. KRISTINE SCHAAL | JUGF EIN GEDULDSSPIEL! DAS EINSTEIGER-PUZZLE FÜR ENTWICKLER
  2. Copyright © Accso – Accelerated Solutions GmbH 5 JSR 277

    (2005-2016) „Java Module System“ JSR 294 (2006-2016) „Improved Modularity Support” JSR 291 (2006-2007) „Dynamic Component Support“ JSR 376 (2014-2017) „Java Platform Module System“ Project Jigsaw für Java 9 geplant für Ende Juli 2017
  3. Copyright © Accso – Accelerated Solutions GmbH 6 Ziele von

    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.
  4. Copyright © Accso – Accelerated Solutions GmbH 9 Modul :=

    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
  5. Copyright © Accso – Accelerated Solutions GmbH 10 de.my.package ...

    Foo Bar XYZ Baz protected private <package> public Java 1.0 bis 8: Sichtbarkeitsmodifier von Klassen, Attributen, Methoden
  6. Copyright © Accso – Accelerated Solutions GmbH 11 Java 1.0

    bis 8: Sichtbarkeitsmodifier von Klassen, Attributen, Methoden
  7. Copyright © Accso – Accelerated Solutions GmbH 12 Java 9:

    Diese Sichtbarkeitsmodifier ändern sich nicht.
  8. Copyright © Accso – Accelerated Solutions GmbH 13 modb Neu

    in Java 9: Modul-Definition mit exportierten Packages exports
  9. Copyright © Accso – Accelerated Solutions GmbH 14 Neu in

    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
  10. Copyright © Accso – Accelerated Solutions GmbH 15 Beispiel: Vier

    Module moda, modb, modc, modmain und ihr Sourcenbaum moda/ module-info.java 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
  11. Copyright © Accso – Accelerated Solutions GmbH 16 moda/ module-info.java

    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
  12. Copyright © Accso – Accelerated Solutions GmbH 17 Alle Abhängigkeiten

    der vier Module moda, modb, modc, modmain moda/ module-info.java 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 module-info.java modmain
  13. Copyright © Accso – Accelerated Solutions GmbH 21 requires transitive

    für transitive Abhängigkeiten module moda { requires modb; requires transitive modc; ...
  14. Copyright © Accso – Accelerated Solutions GmbH 26 Auf Github:

    https://github.com/accso/java9-jigsaw-examples/ Java mit Jigsaw Build b144 (jdk1.9.0_ea-b144-x64_20161111_build5709) Eclipse 4.7 Oxygen (M4) plus Java9-Support (BETA) • Konvention: 1 Eclipse-Projekt == 1 Module • Module-Namen: mod*, Package-Namen: pkg* (interne *internal) • Module-Abhängigkeiten über Projekt-Abhängigkeiten in Eclipse nachmodelliert • Launch-Files starten die JAR-Files im Module-Path • Jedes Beispiel in einem eigenen Workspace *) Compile- und Run-Skripte für die Bash (auch für Windows, z.B. mit Babun) Unsere Beispiele *) Ein Workspace kann nicht 2 Projekte gleichen Namens enthalten.
  15. Copyright © Accso – Accelerated Solutions GmbH 28 Letztlich geht‘s

    immer um Typen-Sichtbarkeit. Auch bei Ableitung. Funktioniert: • Oberklasse Data ist sichtbar nach außen, weil Package pkga exportiert. • Ihre Methoden sind von außerhalb aufrufbar. • Unterklasse InternalData ist nicht sichtbar nach außen. • Ihre Methoden sind von außerhalb nicht aufrufbar. exports pkga inter nal pkga Data moda Inte rnal Data
  16. Copyright © Accso – Accelerated Solutions GmbH 30 pkga inter

    nal pkga moda Fact ory Inte rnal Data Data exports Funktioniert: Factory gibt Instanzen der Unterklasse InternalData zurück. Instanzen behalten natürlich ihren Typ. Es werden Methoden der Unterklasse aufgerufen, z.B. InternalData.toString() public class Factory { public Data createData() { return new Data(); } public Data createInternalData1() { return new InternalData(); } … Letztlich geht‘s immer um Typen-Sichtbarkeit. Auch bei Ableitung.
  17. Copyright © Accso – Accelerated Solutions GmbH 31 Gilt auch

    bei Ableitung Was passiert, wenn eine Methodensignatur eine nicht exportierte Klasse zurückgibt pkga inter nal pkga moda Fact ory public class Factory { public Data createData() { return new Data(); } public Data createInternalData1() { return new InternalData(); } // return type wird nicht exportiert! public InternalData createInternalData2() { return new InternalData(); } } Factory kompiliert. Code in anderem Module kompiliert nicht bei Aufruf: Inte rnal Data Data exports Factory.createInternalData2() Letztlich geht‘s immer um Typen-Sichtbarkeit. Auch bei Ableitung.
  18. Copyright © Accso – Accelerated Solutions GmbH 32 Letztlich geht‘s

    immer um Typen-Sichtbarkeit. Gilt auch bei Interfaces. exports pkga inter nal pkga IDat a moda Inte rnal Data Funktioniert: Factory gibt Instanzen der Unterklasse InternalData zurück. Instanzen behalten natürlich ihren Typ. Es werden Methoden der Implementierung aufgerufen. public class Factory { public IData createData() { return new InternalData(); } // return type wird nicht exportiert! public InternalData createInternalData2() { return new InternalData(); } … Fact ory
  19. Copyright © Accso – Accelerated Solutions GmbH 33 Interne Exceptions

    (deren Package nicht exportiert ist) MyInternalException MyInternalRuntimeException können nach außerhalb des Modules geworfen werden. Typ bleibt auch hier erhalten. Alles funktioniert „ganz normal“, nur eben kein catch auf den internen Exception-Typ. catch auf Oberklassen wie Exception, RuntimeException problemlos möglich. Letztlich geht‘s immer um Typen-Sichtbarkeit. Gilt auch bei Exception-Handling.
  20. Copyright © Accso – Accelerated Solutions GmbH 36 Was ist

    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)
  21. Copyright © Accso – Accelerated Solutions GmbH 37 opens erlaubt

    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
  22. Copyright © Accso – Accelerated Solutions GmbH 38 Compile- Fehler

    Laufzeit- Fehler beim Start Ein „Split“ von Packages auf mehrere Module ist nicht 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.
  23. Copyright © Accso – Accelerated Solutions GmbH 40 Zugriff auf

    Module-interne Resources möglich mit Funktioniert weiterhin: Resource-Encapsulation wird durchgesetzt (funktionierte lange nicht). Ein Module sollte auf Resources eines anderen Modules nicht zugreifen dürfen, scheint aber noch nicht zu funktionieren?! Resource-Schutz und -Handling in Modules this.class.getModule().getResourceAsStream("myapp.properties") this.getClass().getResource ("myapp.properties") ClassLoader.getPlatformClassLoader().getResource("myapp.properties") that.class.getModule().getResourceAsStream("that.properties")
  24. Copyright © Accso – Accelerated Solutions GmbH 44 Observable Modules

    System-Module-Path Observable Modules: „Was da ist“ java. base Module-Path modmain Alle Module auf dem Module-Path, sowie die System-Module bilden das „Universum“ der Observable Modules.
  25. Copyright © Accso – Accelerated Solutions GmbH 45 Die Configuration

    ist die transitive Hülle aller „reads“-Abhängigkeiten aller Root-Module der Observable Modules. Default-Root-Module hier: modmain Observable Modules System-Module-Path Configuration: „Was wirklich geladen wird“ Module-Path modmain java. base java --module-path mlib -m modmain/pkgmain.Main modmain java. base
  26. Copyright © Accso – Accelerated Solutions GmbH 46 Weitere Module

    kann man einer Configuration als Root-Module mit --add-modules hinzufügen: Observable Modules System-Module-Path Configuration: „Was wirklich geladen wird“ plus „addMods“ Module-Path modmain java. base modmain java. base java --module-path mlib --add-modules mlib/modx.jar -m modmain/pkgmain.Main modx modx
  27. Copyright © Accso – Accelerated Solutions GmbH 48 Separates Module

    modtest.blackbox testet äußere Schnittstelle von modfib. Braucht also keinen Zugriff auf interne Klassen. Blackbox-Test eines Modules modfib modfib modtest. blackbox read exports pkg black test pkgfib internal pkgfib java --module-path mlib\;amlib --add-modules hamcrest.core,modtest.blackbox -m junit/org.junit.runner.JUnitCore pkgblacktest.BlackBoxTest
  28. Copyright © Accso – Accelerated Solutions GmbH 49 „Du kommst

    hier nicht rein!“ ist nicht exportiert, nicht zugreifbar (sog. „concealed package“)! moda/ module-info.java pkga1/ A1.java pkga2/ A2.java pkga3/ A3.java pkgainternal/ AHelperImpl.java modb/ module-info.java pkgb/ B.java modc/ module-info.java pkgc/ C.java modmain/ module-info.java pkgmain/ Main.java moda/ module-info.java 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 pkgainternal/ InternalA.java pkgainternal Doch! Unschön JAR-File mit neuem module-info.class patchen ist i.d.R. keine Alternative (geht z.B. nicht bei Checksummen) Abhilfe Kommandozeilenoption --add-exports gibt Export zusätzlicher Packages an
  29. Copyright © Accso – Accelerated Solutions GmbH 50 Whitebox-Test eines

    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
  30. Copyright © Accso – Accelerated Solutions GmbH 51 1. Separates

    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
  31. Copyright © Accso – Accelerated Solutions GmbH 52 2. modfib

    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“)
  32. Copyright © Accso – Accelerated Solutions GmbH 53 Whitebox-Test Variante

    2b: modfib mit Testklassen patchen Testklassen erst beim Compile dem Module modfib hinzufügen modfib pkgfib internal pkgfib pkgfib …Test javac -Xmodule:modfib --add-reads modfib=junit -d patches/modfib ... src/modtest.whitebox/pkgfib/WhiteBoxTest.java
  33. Copyright © Accso – Accelerated Solutions GmbH 54 modfib pkgfib

    internal pkgfib pkgfib …Test Testklassen erst beim Test-Start dem Module modfib hinzufügen Whitebox-Test Variante 2b: modfib mit Testklassen patchen java --patch-module modfib=patches/modfib --add-reads modfib=junit ... -m junit/org.junit.runner.JUnitCore pkgfib.WhiteBoxTest
  34. Copyright © Accso – Accelerated Solutions GmbH 56 Module-Path Ein

    „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
  35. Copyright © Accso – Accelerated Solutions GmbH 57 Ein JAR

    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
  36. Copyright © Accso – Accelerated Solutions GmbH 58 Der alte

    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
  37. Copyright © Accso – Accelerated Solutions GmbH 59 Wie Module-Path

    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!
  38. Copyright © Accso – Accelerated Solutions GmbH 68 Auslesen der

    Module-Informationen aus JAR, aus module-info.class Oder Auslesen der Module-Informationen aus JMOD-Datei Auslesen der Module-Informationen einer module-info.class - Datei Module-Informationen auslesen jar --file mlib/modmain.jar --print-module-descriptor jdeps --module-path mlib mlib/modmain.jar jmod describe java.base.jmod javap -verbose module-info.class
  39. Copyright © Accso – Accelerated Solutions GmbH 74 „DepVis“: Tool

    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
  40. Copyright © Accso – Accelerated Solutions GmbH 78 Eclipse 4.6

    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?
  41. Copyright © Accso – Accelerated Solutions GmbH 83 http://openjdk.java.net/projects/jigsaw/ https://jdk9.java.net/jigsaw/

    http://openjdk.java.net/projects/jigsaw/spec/reqs/ http://openjdk.java.net/projects/jigsaw/spec/issues/ http://openjdk.java.net/projects/jigsaw/spec/sotms/ http://openjdk.java.net/projects/jigsaw/quick-start https://www.jcp.org/en/jsr/detail?id=376 http://openjdk.java.net/jeps/<NR> Zum Nachlesen Homepage Project Jigsaw Build Specification Diskussionsseite State of the Module System Quickstart Guide JSR376 JEPs 200 „The modular JDK“ 220 „Modular Runtime Images“ 260 „Encapsulate Most Internal APIs“ Mailinglisten jigsaw-dev, jdk9-dev, jpms-spec-comments, jpms-spec-experts, jpms-spec-observers 261 „Module System“ 275 „Modular Java App. Packaging“ 282 „jlink: The Java Linker“ http://mail.openjdk.java.net/mailman/listinfo
  42. Copyright © Accso – Accelerated Solutions GmbH 86 Jigsaw ist

    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.
  43. Copyright © Accso – Accelerated Solutions GmbH 91 Drastische Semantikänderung:

    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 …
  44. Copyright © Accso – Accelerated Solutions GmbH 92 Aggregator-Module über

    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!
  45. Copyright © Accso – Accelerated Solutions GmbH 95 95 Copyright

    © Accso GmbH Accso – Accelerated Solutions GmbH www.accso.de twitter.com/accso Berliner Allee 58 64295 Darmstadt Telefon: +49 (6151) 13029-0 Fax: +49 (6151) 13029-10 Moltkestraße 131 a 50674 Köln Telefon: +49 (221) 630691-0 Fax: +49 (221) 630691-10 Balanstraße 55 81541 München 95 @lemmi111171 de.slideshare.net/lemmi www.xing.com/profile/Martin_Lehmann3 www.xing.com/profile/Ruediger_Grammes MartinLehmann1971 accso https://github.com/accso/ java9-jigsaw-examples/ Rgrammes kristines @accso www.xing.com/profile/Kristine_Schaal