Migrating to Java 9 Modules

By Sander Mak
Migrating to Java 9
Modules
@Sander_Mak
Migrating to Java 9
java -cp .. -jar myapp.jarJava 8
Migrating to Java 9
java -cp .. -jar myapp.jar
java -cp .. -jar myapp.jar
Java 8
Java 9
Migrating to Java 9 Modules
Migrating to Java 9 Modules
Today's journey
Running on Java 9
Java 9 modules
Migrating to modules
Modularising code
Migrating to Java 9
Let's try it!
java -cp .. -jar myapp.jar
java -cp .. -jar myapp.jar
Java 8
Java 9
Classpath migration problems
‣ Unresolved platform modules
‣ (Ab)use of platform internals
Missing platform modules
error: package javax.xml.bind does not exist
import javax.xml.bind.DatatypeConverter;
public class Main {
public static void main(String... args) {
DatatypeConverter.parseBase64Binary("SGVsbG8gd29ybGQh");
}
}
Modular JDK
Modular JDK
Modular JDK
Modular JDK
Modular JDK
‣ Classpath compile-time
“java.se” module is used
‣ This does not resolve:
java.activation
java.corba
java.transaction
java.xml.bind
java.xml.ws
java.xml.ws.annotation
Missing platform modules
Add unresolved platform modules
jdeps demo/Main.class
Main.class -> java.base
Main.class -> not found
<unnamed> -> java.lang java.base
<unnamed> -> javax.xml.bind not found
Find
javac --add-modules java.xml.bind demo/Main.java
Add unresolved platform modules
jdeps demo/Main.class
Main.class -> java.base
Main.class -> not found
<unnamed> -> java.lang java.base
<unnamed> -> javax.xml.bind not found
Find
Fix
javac --add-modules java.xml.bind demo/Main.java
Add unresolved platform modules
java --add-modules java.xml.bind demo/Main.java
jdeps demo/Main.class
Main.class -> java.base
Main.class -> not found
<unnamed> -> java.lang java.base
<unnamed> -> javax.xml.bind not found
Find
Fix
javac --add-modules java.xml.bind demo/Main.java
Add unresolved platform modules
java --add-modules java.xml.bind demo/Main.java
Let's try it!
public class Main {
public static void main(String... args) throws Exception {
sun.security.x509.X500Name name =
new sun.security.x509.X500Name("CN=user");
}
}
Using encapsulated APIs
public class Main {
public static void main(String... args) throws Exception {
sun.security.x509.X500Name name =
new sun.security.x509.X500Name("CN=user");
}
}
Using encapsulated APIs
Main.java:4: error: package
sun.security.x509 does not exist
sun.security.x509.X500Name name =
^
jdeps -jdkinternals Main.class
Main.class -> java.base
Main -> sun.security.x509.X500Name JDK internal API (java.base)
JDK Internal API Suggested Replacement
---------------- ---------------------
sun.security.x509.X500Name Use javax.security.auth.x500.X500Principal
@since 1.4
Use jdeps to find problems
Using encapsulated APIs
Compile with 1.8, run with 9:
Using encapsulated APIs
Exception in thread "main" java.lang.IllegalAccessError: class Main
(in unnamed module @0x4cdbe50f) cannot access class
sun.security.x509.X500Name (in module java.base) because module
java.base does not export sun.security.x509 to unnamed module
@0x4cdbe50f
at Main.main(Main.java:4)
Compile with 1.8, run with 9:
Using encapsulated APIs
java --add-exports java.base/sun.security.x509=ALL-UNNAMED Main
Exception in thread "main" java.lang.IllegalAccessError: class Main
(in unnamed module @0x4cdbe50f) cannot access class
sun.security.x509.X500Name (in module java.base) because module
java.base does not export sun.security.x509 to unnamed module
@0x4cdbe50f
at Main.main(Main.java:4)
Compile with 1.8, run with 9:
Using encapsulated APIs
Exception in thread "main" java.lang.IllegalAccessError: class Main
(in unnamed module @0x4cdbe50f) cannot access class
sun.security.x509.X500Name (in module java.base) because module
java.base does not export sun.security.x509 to unnamed module
@0x4cdbe50f
at Main.main(Main.java:4)
Compile with 1.8, run with 9:
java --permit-illegal-access Main
New 'kill-switch':
Back to Modules...
main
books.api
books.impl
bookstore
Mental picture of your app
Actual view of your app
main
books.api
books.impl
bookstore
Java 9 modules make this possible!
Migrating to modules
Top down migration
commons.lang3.3.4.jar demonstrator.jar
classpath
java.base module path
package com.javamodularity.demonstrator;
import org.apache.commons.lang3.StringUtils;
public class Demo {
public static void main(String args[]) {
String output = StringUtils.leftPad("Leftpad FTW!", 20);
System.out.println(output);
}
}
Classic classpath
package com.javamodularity.demonstrator;
import org.apache.commons.lang3.StringUtils;
public class Demo {
public static void main(String args[]) {
String output = StringUtils.leftPad("Leftpad FTW!", 20);
System.out.println(output);
}
}
Classic classpath
javac -cp lib/commons-lang3-3.4.jar
-d out $(find src -name '*.java')
java -cp out:lib/commons-lang3-3.4.jar
com.javamodularity.demonstrator.Demo
Compile
Run
Top down migration
commons.lang3.3.4.jar demonstrator.jar
classpath
java.base module path
Top down migration
commons.lang3.3.4.jar
demonstrator.jar
classpath
java.base module path
Can’t reference the classpath
from named modules!
Top down migration
demonstrator.jar
classpath
java.base module path
commons.lang
But this isn’t our code!
Automatic Modules
‣ A plain JAR on the module path becomes an
Automatic Module
‣ Module name derived from JAR name
‣ Exports everything
‣ Reads all other modules
module demonstrator {
requires commons.lang;
}
Using Automatic Modules
module demonstrator {
requires commons.lang;
}
Using Automatic Modules
javac --module-path lib
--module-source-path src
-d mods $(find src -name '*.java')
java --module-path mods:lib
-m demonstrator/com.javamodularity.demonstrator.Demo
Compile
Run
Migrating the books app
1. Create a “monolith module”
2. Declare exports
3. Figure out “requires”
4. Move some libs to Automatic Modules
Step 2
commons.pool
spring.context
classpath
Application code
module path
spring.tx
hibernate.core
hibernate.jpa
javax.inject
Automatic modules Named modules
commons.logging
spring.beans spring.aop
spring.core
hsqldb
spring.orm
…
commons.pool
spring.context
classpath
Application code
module path
spring.tx
hibernate.core
hibernate.jpa
javax.inject
Automatic modules Named modules
commons.logging
spring.beans spring.aop
spring.core
hsqldb
spring.orm
…
DEMO
Open Modules
‣ Reliable configuration like normal modules
‣ Requires for every dependency
‣ Opens all packages for deep reflection
‣ Easy compatibility with existing code and frameworks
‣ Allows reflection
Type Compile time Reflection on public Deep reflection
Exports
✓ ✓ ✘
Open
✘ ✓ ✓
Exports + Open
✓ ✓ ✓
Open Packages
Opens the package for deep reflection, but not compile
time access
A package can be both open and exported
Tip 1
Move libraries to module path one by one
Start with direct dependencies
Tip 2
open when no compile time dependency
should exist (possibly qualified)
Tip 3
requires only for direct dependencies
--add-modules for run-time dependencies
Tip 4
Use open modules for framework compatibility
Fine tune open later
Migrating the books app
1. Split monolith module
2. Move requires/exports
3. (optional) Move config files
Step 3
commons.pool
spring.context
classpath
Application code
module path
spring.tx
hibernate.core
hibernate.jpa
javax.inject
Automatic modules Named modules
commons.logging
spring.beans spring.aop
spring.core
hsqldb
spring.orm
…
commons.pool
spring.context
classpath
module path
spring.tx
hibernate.core
hibernate.jpa
javax.inject
Automatic modules Named modules
commons.logging
spring.beans spring.aop
spring.core
hsqldb
spring.orm
…
main books.api
books.impl
bookstore
Migration steps - recap
Migration steps - recap
‣ Migrate to Java 9 using classpath only
Migration steps - recap
‣ Migrate to Java 9 using classpath only
‣ Create a module around your whole app
Migration steps - recap
‣ Migrate to Java 9 using classpath only
‣ Create a module around your whole app
‣ Modularize your application!
Thank you.
bit.ly/java9book
@javamodularity
code @ bit.ly/java9mig
Thank you.
bit.ly/java9book
@javamodularity
http://bit.ly/java9course
Java 9 Modularity: First Look
code @ bit.ly/java9mig
1 of 60

Recommended

Java Modularity: the Year After by
Java Modularity: the Year AfterJava Modularity: the Year After
Java Modularity: the Year AfterSander Mak (@Sander_Mak)
913 views109 slides
Migrating to java 9 modules by
Migrating to java 9 modulesMigrating to java 9 modules
Migrating to java 9 modulesPaul Bakker
2.4K views37 slides
Coding Your Way to Java 12 by
Coding Your Way to Java 12Coding Your Way to Java 12
Coding Your Way to Java 12Sander Mak (@Sander_Mak)
2K views69 slides
Java modularity: life after Java 9 by
Java modularity: life after Java 9Java modularity: life after Java 9
Java modularity: life after Java 9Sander Mak (@Sander_Mak)
4.4K views47 slides
Desiging for Modularity with Java 9 by
Desiging for Modularity with Java 9Desiging for Modularity with Java 9
Desiging for Modularity with Java 9Sander Mak (@Sander_Mak)
1.9K views80 slides
Java 9 preview by
Java 9 previewJava 9 preview
Java 9 previewIvan Krylov
873 views55 slides

More Related Content

What's hot

Polygot Java EE on the GraalVM by
Polygot Java EE on the GraalVMPolygot Java EE on the GraalVM
Polygot Java EE on the GraalVMRyan Cuprak
1K views49 slides
Modular JavaScript by
Modular JavaScriptModular JavaScript
Modular JavaScriptSander Mak (@Sander_Mak)
4.1K views38 slides
Modular Java by
Modular JavaModular Java
Modular JavaMartin Toshev
3K views69 slides
Preparing your code for Java 9 by
Preparing your code for Java 9Preparing your code for Java 9
Preparing your code for Java 9Deepu Xavier
591 views32 slides
Preparing for java 9 modules upload by
Preparing for java 9 modules uploadPreparing for java 9 modules upload
Preparing for java 9 modules uploadRyan Cuprak
1.7K views71 slides
Node.js Development with Apache NetBeans by
Node.js Development with Apache NetBeansNode.js Development with Apache NetBeans
Node.js Development with Apache NetBeansRyan Cuprak
5.5K views44 slides

What's hot(20)

Polygot Java EE on the GraalVM by Ryan Cuprak
Polygot Java EE on the GraalVMPolygot Java EE on the GraalVM
Polygot Java EE on the GraalVM
Ryan Cuprak1K views
Preparing your code for Java 9 by Deepu Xavier
Preparing your code for Java 9Preparing your code for Java 9
Preparing your code for Java 9
Deepu Xavier591 views
Preparing for java 9 modules upload by Ryan Cuprak
Preparing for java 9 modules uploadPreparing for java 9 modules upload
Preparing for java 9 modules upload
Ryan Cuprak1.7K views
Node.js Development with Apache NetBeans by Ryan Cuprak
Node.js Development with Apache NetBeansNode.js Development with Apache NetBeans
Node.js Development with Apache NetBeans
Ryan Cuprak5.5K views
Modules in Java? Finally! (OpenJDK 9 Jigsaw, JSR376) by Mihail Stoynov
Modules in Java? Finally! (OpenJDK 9 Jigsaw, JSR376)Modules in Java? Finally! (OpenJDK 9 Jigsaw, JSR376)
Modules in Java? Finally! (OpenJDK 9 Jigsaw, JSR376)
Mihail Stoynov10.5K views
Java 9 Module System Introduction by Dan Stine
Java 9 Module System IntroductionJava 9 Module System Introduction
Java 9 Module System Introduction
Dan Stine785 views
Faster java ee builds with gradle [con4921] by Ryan Cuprak
Faster java ee builds with gradle [con4921]Faster java ee builds with gradle [con4921]
Faster java ee builds with gradle [con4921]
Ryan Cuprak2.4K views
Springboot introduction by Sagar Verma
Springboot introductionSpringboot introduction
Springboot introduction
Sagar Verma141 views
Java 9 New Features by Ali BAKAN
Java 9 New FeaturesJava 9 New Features
Java 9 New Features
Ali BAKAN196 views
Java11 New Features by Haim Michael
Java11 New FeaturesJava11 New Features
Java11 New Features
Haim Michael1.3K views
Java 10 New Features by Ali BAKAN
Java 10 New FeaturesJava 10 New Features
Java 10 New Features
Ali BAKAN350 views
Web application development using Play Framework (with Java) by Saeed Zarinfam
Web application development using Play Framework (with Java)Web application development using Play Framework (with Java)
Web application development using Play Framework (with Java)
Saeed Zarinfam3.8K views
Migrating a JSF-Based Web Application from Spring 3 to Java EE 7 and CDI by Mario-Leander Reimer
Migrating a JSF-Based Web Application from Spring 3 to Java EE 7 and CDIMigrating a JSF-Based Web Application from Spring 3 to Java EE 7 and CDI
Migrating a JSF-Based Web Application from Spring 3 to Java EE 7 and CDI
Java(ee) mongo db applications in the cloud by Shekhar Gulati
Java(ee) mongo db applications in the cloud Java(ee) mongo db applications in the cloud
Java(ee) mongo db applications in the cloud
Shekhar Gulati3.7K views

Similar to Migrating to Java 9 Modules

LausanneJUG 2017 - Jigsaw est prêt à tuer le classpath by
LausanneJUG 2017 - Jigsaw est prêt à tuer le classpathLausanneJUG 2017 - Jigsaw est prêt à tuer le classpath
LausanneJUG 2017 - Jigsaw est prêt à tuer le classpathAlexis Hassler
450 views86 slides
Modern Java Workshop by
Modern Java WorkshopModern Java Workshop
Modern Java WorkshopSimon Ritter
739 views142 slides
Java 9 and the impact on Maven Projects (JavaOne 2016) by
Java 9 and the impact on Maven Projects (JavaOne 2016)Java 9 and the impact on Maven Projects (JavaOne 2016)
Java 9 and the impact on Maven Projects (JavaOne 2016)Robert Scholte
7.4K views56 slides
Java 9 and the impact on Maven Projects (ApacheCon Europe 2016) by
Java 9 and the impact on Maven Projects (ApacheCon Europe 2016)Java 9 and the impact on Maven Projects (ApacheCon Europe 2016)
Java 9 and the impact on Maven Projects (ApacheCon Europe 2016)Robert Scholte
1.7K views52 slides
Apache Maven supports all Java (JokerConf 2018) by
Apache Maven supports all Java (JokerConf 2018)Apache Maven supports all Java (JokerConf 2018)
Apache Maven supports all Java (JokerConf 2018)Robert Scholte
201 views63 slides
Apache maven and its impact on java 9 (Java One 2017) by
Apache maven and its impact on java 9 (Java One 2017)Apache maven and its impact on java 9 (Java One 2017)
Apache maven and its impact on java 9 (Java One 2017)Robert Scholte
863 views55 slides

Similar to Migrating to Java 9 Modules(20)

LausanneJUG 2017 - Jigsaw est prêt à tuer le classpath by Alexis Hassler
LausanneJUG 2017 - Jigsaw est prêt à tuer le classpathLausanneJUG 2017 - Jigsaw est prêt à tuer le classpath
LausanneJUG 2017 - Jigsaw est prêt à tuer le classpath
Alexis Hassler450 views
Modern Java Workshop by Simon Ritter
Modern Java WorkshopModern Java Workshop
Modern Java Workshop
Simon Ritter739 views
Java 9 and the impact on Maven Projects (JavaOne 2016) by Robert Scholte
Java 9 and the impact on Maven Projects (JavaOne 2016)Java 9 and the impact on Maven Projects (JavaOne 2016)
Java 9 and the impact on Maven Projects (JavaOne 2016)
Robert Scholte7.4K views
Java 9 and the impact on Maven Projects (ApacheCon Europe 2016) by Robert Scholte
Java 9 and the impact on Maven Projects (ApacheCon Europe 2016)Java 9 and the impact on Maven Projects (ApacheCon Europe 2016)
Java 9 and the impact on Maven Projects (ApacheCon Europe 2016)
Robert Scholte1.7K views
Apache Maven supports all Java (JokerConf 2018) by Robert Scholte
Apache Maven supports all Java (JokerConf 2018)Apache Maven supports all Java (JokerConf 2018)
Apache Maven supports all Java (JokerConf 2018)
Robert Scholte201 views
Apache maven and its impact on java 9 (Java One 2017) by Robert Scholte
Apache maven and its impact on java 9 (Java One 2017)Apache maven and its impact on java 9 (Java One 2017)
Apache maven and its impact on java 9 (Java One 2017)
Robert Scholte863 views
Apache Maven supports ALL Java (Javaland 2019) by Robert Scholte
Apache Maven supports ALL Java (Javaland 2019)Apache Maven supports ALL Java (Javaland 2019)
Apache Maven supports ALL Java (Javaland 2019)
Robert Scholte310 views
Java9 and the impact on Maven Projects (JFall 2016) by Robert Scholte
Java9 and the impact on Maven Projects (JFall 2016)Java9 and the impact on Maven Projects (JFall 2016)
Java9 and the impact on Maven Projects (JFall 2016)
Robert Scholte1.6K views
Java 9 / Jigsaw - AJUG/VJUG session by Mani Sarkar
Java 9 / Jigsaw - AJUG/VJUG  sessionJava 9 / Jigsaw - AJUG/VJUG  session
Java 9 / Jigsaw - AJUG/VJUG session
Mani Sarkar1.8K views
How to run java program without IDE by Shweta Oza
How to run java program without IDEHow to run java program without IDE
How to run java program without IDE
Shweta Oza823 views
What we can expect from Java 9 by Ivan Krylov by J On The Beach
What we can expect from Java 9 by Ivan KrylovWhat we can expect from Java 9 by Ivan Krylov
What we can expect from Java 9 by Ivan Krylov
J On The Beach973 views
DevoxxFR17 - Préparez-vous à la modularité selon Java 9 by Alexis Hassler
DevoxxFR17 - Préparez-vous à la modularité selon Java 9DevoxxFR17 - Préparez-vous à la modularité selon Java 9
DevoxxFR17 - Préparez-vous à la modularité selon Java 9
Alexis Hassler360 views
Devoxx17 - Préparez-vous à la modularité selon Java 9 by Alexis Hassler
Devoxx17 - Préparez-vous à la modularité selon Java 9Devoxx17 - Préparez-vous à la modularité selon Java 9
Devoxx17 - Préparez-vous à la modularité selon Java 9
Alexis Hassler121 views
Moving to Module: Issues & Solutions by Yuichi Sakuraba
Moving to Module: Issues & SolutionsMoving to Module: Issues & Solutions
Moving to Module: Issues & Solutions
Yuichi Sakuraba1.4K views
OOP with Java by OmegaHub
OOP with JavaOOP with Java
OOP with Java
OmegaHub30 views
Apache Maven supports ALL Java JEEConf 2019 by Robert Scholte
Apache Maven supports ALL Java JEEConf 2019Apache Maven supports ALL Java JEEConf 2019
Apache Maven supports ALL Java JEEConf 2019
Robert Scholte216 views

More from Sander Mak (@Sander_Mak)

Scalable Application Development @ Picnic by
Scalable Application Development @ PicnicScalable Application Development @ Picnic
Scalable Application Development @ PicnicSander Mak (@Sander_Mak)
239 views20 slides
Coding Your Way to Java 13 by
Coding Your Way to Java 13Coding Your Way to Java 13
Coding Your Way to Java 13Sander Mak (@Sander_Mak)
414 views80 slides
Java 9 Modularity in Action by
Java 9 Modularity in ActionJava 9 Modularity in Action
Java 9 Modularity in ActionSander Mak (@Sander_Mak)
8.5K views49 slides
Provisioning the IoT by
Provisioning the IoTProvisioning the IoT
Provisioning the IoTSander Mak (@Sander_Mak)
4.4K views38 slides
Event-sourced architectures with Akka by
Event-sourced architectures with AkkaEvent-sourced architectures with Akka
Event-sourced architectures with AkkaSander Mak (@Sander_Mak)
27.8K views81 slides
TypeScript: coding JavaScript without the pain by
TypeScript: coding JavaScript without the painTypeScript: coding JavaScript without the pain
TypeScript: coding JavaScript without the painSander Mak (@Sander_Mak)
17K views61 slides

More from Sander Mak (@Sander_Mak)(20)

Recently uploaded

Electronic AWB - Electronic Air Waybill by
Electronic AWB - Electronic Air Waybill Electronic AWB - Electronic Air Waybill
Electronic AWB - Electronic Air Waybill Freightoscope
5 views1 slide
360 graden fabriek by
360 graden fabriek360 graden fabriek
360 graden fabriekinfo33492
162 views25 slides
AI and Ml presentation .pptx by
AI and Ml presentation .pptxAI and Ml presentation .pptx
AI and Ml presentation .pptxFayazAli87
14 views15 slides
Dapr Unleashed: Accelerating Microservice Development by
Dapr Unleashed: Accelerating Microservice DevelopmentDapr Unleashed: Accelerating Microservice Development
Dapr Unleashed: Accelerating Microservice DevelopmentMiroslav Janeski
13 views29 slides
nintendo_64.pptx by
nintendo_64.pptxnintendo_64.pptx
nintendo_64.pptxpaiga02016
6 views7 slides
Generic or specific? Making sensible software design decisions by
Generic or specific? Making sensible software design decisionsGeneric or specific? Making sensible software design decisions
Generic or specific? Making sensible software design decisionsBert Jan Schrijver
7 views60 slides

Recently uploaded(20)

Electronic AWB - Electronic Air Waybill by Freightoscope
Electronic AWB - Electronic Air Waybill Electronic AWB - Electronic Air Waybill
Electronic AWB - Electronic Air Waybill
Freightoscope 5 views
360 graden fabriek by info33492
360 graden fabriek360 graden fabriek
360 graden fabriek
info33492162 views
AI and Ml presentation .pptx by FayazAli87
AI and Ml presentation .pptxAI and Ml presentation .pptx
AI and Ml presentation .pptx
FayazAli8714 views
Dapr Unleashed: Accelerating Microservice Development by Miroslav Janeski
Dapr Unleashed: Accelerating Microservice DevelopmentDapr Unleashed: Accelerating Microservice Development
Dapr Unleashed: Accelerating Microservice Development
Miroslav Janeski13 views
Generic or specific? Making sensible software design decisions by Bert Jan Schrijver
Generic or specific? Making sensible software design decisionsGeneric or specific? Making sensible software design decisions
Generic or specific? Making sensible software design decisions
tecnologia18.docx by nosi6702
tecnologia18.docxtecnologia18.docx
tecnologia18.docx
nosi67025 views
predicting-m3-devopsconMunich-2023-v2.pptx by Tier1 app
predicting-m3-devopsconMunich-2023-v2.pptxpredicting-m3-devopsconMunich-2023-v2.pptx
predicting-m3-devopsconMunich-2023-v2.pptx
Tier1 app11 views
Bootstrapping vs Venture Capital.pptx by Zeljko Svedic
Bootstrapping vs Venture Capital.pptxBootstrapping vs Venture Capital.pptx
Bootstrapping vs Venture Capital.pptx
Zeljko Svedic15 views
Ports-and-Adapters Architecture for Embedded HMI by Burkhard Stubert
Ports-and-Adapters Architecture for Embedded HMIPorts-and-Adapters Architecture for Embedded HMI
Ports-and-Adapters Architecture for Embedded HMI
Burkhard Stubert29 views
Unlocking the Power of AI in Product Management - A Comprehensive Guide for P... by NimaTorabi2
Unlocking the Power of AI in Product Management - A Comprehensive Guide for P...Unlocking the Power of AI in Product Management - A Comprehensive Guide for P...
Unlocking the Power of AI in Product Management - A Comprehensive Guide for P...
NimaTorabi216 views
How Workforce Management Software Empowers SMEs | TraQSuite by TraQSuite
How Workforce Management Software Empowers SMEs | TraQSuiteHow Workforce Management Software Empowers SMEs | TraQSuite
How Workforce Management Software Empowers SMEs | TraQSuite
TraQSuite6 views
Fleet Management Software in India by Fleetable
Fleet Management Software in India Fleet Management Software in India
Fleet Management Software in India
Fleetable12 views
DRYiCE™ iAutomate: AI-enhanced Intelligent Runbook Automation by HCLSoftware
DRYiCE™ iAutomate: AI-enhanced Intelligent Runbook AutomationDRYiCE™ iAutomate: AI-enhanced Intelligent Runbook Automation
DRYiCE™ iAutomate: AI-enhanced Intelligent Runbook Automation
HCLSoftware6 views
Understanding HTML terminology by artembondar5
Understanding HTML terminologyUnderstanding HTML terminology
Understanding HTML terminology
artembondar57 views

Migrating to Java 9 Modules