module $module_name {
requires $other_module;
exports $api_package;
}
Nicolai Parlog
interacting parts
parts have
names
dependencies
capabilities
creates a graph
parts are packaged as JARs
to the JVM JARs
have no names
dependencies are unexpressed
have no coherent surface
JVM rolls them into one big ball of mud
unexpressed, transitive dependencies
shadowing, version conflicts
complex class loading
slow
unsecure
maintenance nightmare
first discussions about modularity in JDK
Project Jigsaw is created
exploratory phase; ends with JSR 376
prototype is released
Java 9 gets released with Jigsaw
all is based on a prototype
everything can change
this is the time for community feedback
Reliable Configuration
Strong Encapsulation
Scalable Systems (esp. the JDK)
Security
Performance
Maintainability
Introducing modules, which
have a name
express dependencies
encapsulate internals
Everything else follows from here!
Modules, Readability, Accessibility
Implied Readability, Qualified Exports
Modular JARs, Module Path, Module Graph
Services
Unnamed Modules, Automatic Modules
Reflection, Layers
Runtime Images
These are the nodes in our graph.
Modules
have a unique name
express their dependencies
export specific packages
(and hide the rest)
Modules are JARs with a module-info.class
(aka Modular JAR)
gets generated from module-info.java
:
module $module_name {
requires $other_module;
exports $api_package;
}
this is called a Module Declaration or a
Module Descriptor
Readability brings edges into our graph.
It is the basis for Reliable Configuration.
For two modules A
and B
with
module A {
requires B;
}
we say
A
requires B
A
depends on B
A
reads B
B
is readable by A
Java will only compile/launch when
every dependency is fulfilled
there are no cycles
there is no ambiguity
Accessibility governs which types a module can see.
It builds on top of Readability.
It is the basis for Strong Encapsulation.
A type in one module is only accessible
by code in another module if
the type is public
the package is exported
the second module reads the first
public
is no longer public
even reflection doesn’t work
command line provides escape hatches
great boost for maintainability
also the major reason for community unrest
critical APIs might survive until Java 10
(e.g. sun.misc.Unsafe
— see JEP 260)
Find it on GitHub!
public static void main(String[] args) {
List<SurpriseF_> fac = asList(
new ChocolateF_(), new QuoteF_());
Calendar cal = Calendar.create(fac);
println(cal.asText());
}
modularization is not required
JARs continue to work as today!
(Unless you do forbidden things, more on that later.)
we can just put the application
on the class path as before
(Boring...)
module advent {
// java.base is implicitly required
// requires no other modules
// exports no API
}
(Still Boring...)
module surprise {
// requires no other modules
exports org.codefx.advent.surprise;
}
module calendar {
requires surprise;
exports org.codefx.advent.calendar;
}
module factories {
requires surprise;
exports org.codefx.advent.factories;
}
module advent {
requires calendar;
requires factories;
requires surprise;
}
# First compile/package the other modules
# ('surprise', 'calendar', 'factories')
# into folder 'mods'.
# Compile/package 'advent':
javac -mp mods -d classes/advent ${*.java}
jar -c --file=mods/advent.jar
--main-class=org.codefx.advent.Main
${*.class}
# Launch the application:
java -mp mods -m advent
most module systems are "in or out",
but modularized JDK and legacy JARs
have to cooperate!
so migration has to be possible
Migration is enabled by two features:
Unnamed Module(s)
Automatic Modules
And the fact that module and class path coexist:
modular JARs can be put on either
"regular" JARs can be put on either
The Unnamed Module
contains all JARs on the class path
(including modular JARs).
has no name (surprise!)
can read all modules
exports all packages
Put all your JARs on the class path.
what if your code was modularized?
and your dependencies were not?
proper modules can not depend on
"the chaos on the class path"
this is not possible:
module advent {
requires unnamed;
}
An Automatic Module
is created for each "regular" JAR
on the module path.
gets a name based on the file name
can read all modules
(including the Unnamed Module)
exports all packages
put guava-19.0.jar
on the module path
then this works:
module advent {
requires guava;
}
Class Path | Module Path | |
---|---|---|
Regular JAR | Unnamed Module | Automatic Module |
Modular JAR | Unnamed Module | Named Module |
Two strategies emerge:
bottom-up migration
top-down migration
Works best for Projects without
unmodularized dependencies
(libraries).
turn project JARs into modules
they still work on the class path
clients can move them to the module path
whenever they want
Required for Projects with
unmodularized dependencies
(applications).
turn project JARs into modules
modularized dependencies:
require direct ones
put all on the module path
unmodularized dependencies:
require direct ones with automatic name
put direct ones on the module path
put others on either path
When dependencies get modularized:
hopefully the name didn’t change
if they are already on the module path,
nothing changes
otherwise move them there
check their dependencies
Some internal changes can break existing code!
Just by running on JDK 9
(even without modularizing the application).
JEP 261 contains a list of risks.
internal APIs disappear:
all in sun.*
most in com.sun
(unless marked @jdk.Exported
)
critical APIs might survive until Java 10
(e.g. sun.misc.Unsafe
— see JEP 260)
six methods adding/removing
PropertyChangeListener
got removed
contact library developers
look for alternatives
(in the JDK or other libraries)
consider command line flag -XaddExports
turn to the Jigsaw mailing lists
packages should have a unique origin
no module must read the same package
from two modules
The current implementation is even stricter:
no two modules must contain
the same package (exported or not)
some libraries split java.xml.*
, e.g. xml-apis
some JBoss modules split, e.g.,
java.transaction
, java.xml.ws
jsr305 splits javax.annotation
search your code and dependencies
for java(x)
packages (jdeps
can help)
no tool support (yet?)
Note:
split packages on the class path will be inaccessible
is the split on purpose / necessary?
find other ways to solve the problem
upgradeable modules to replace run-time modules
command line -Xpatch
to add individual classes
new JDK/JRE layout
internal JARs are gone (e.g. rt.jar
, tools.jar
)
JARs are now JMODs
application class loader is no URLClassLoader
new URL schema for runtime image content
does the code rummage around
in the JDK / JRE folder?
search for casts to URLClassLoader
are URLs to JDK classes / resources handcrafted?
Endorsed Standards Override Mechanism
Extension Mechanism
Boot Class Path Override
The most relevant for most applications:
internal APIs
split packages
get your code in shape
(and prevent relapses)
check your dependencies and tools
if any are suspicious
(automatically true for IDEs, build tools):
make sure they’re alive
get them up to date!
or look for alternatives
get an EA-build and try it!
Java 9 Migration & Training
OSGi Bundles:
are JARs with a descriptor (MANIFEST.MF
)
have a name
import packages or bundles
define public API by exporting packages
Jigsaw | OSGi | |
---|---|---|
Versioning | not at all | packages and modules |
Runtime Behavior | mostly static | dynamic |
Services | declarative via | declarative or programmatically; |
Class Loaders | operates below | one per bundle |
puzzle-people: Kevin Dooley (CC-BY 2.0)
binary-code: Christiaan Colen (CC-BY-SA 2.0)
ball-of-mud-2: Andi Gentsch (CC-BY-SA 2.0)
jar-hell: Wellcome Library, London (CC-BY 4.0)
flag-amsterdam: George Rex (CC-BY-SA 2.0)
puzzle-cubed: David Singleton (CC-BY 2.0)
puzzle-piece-green: StockMonkeys.com (CC-BY 2.0)
puzzle-pieces-put-together:
Ken Teegardin
(CC-BY-SA 2.0)
iceberg: NOAA’s National Ocean Service (CC-BY 2.0)
class and module diagrams:
Nicolai Parlog
(CC-BY-NC 4.0)
keep-out: Brian Smithson (CC-BY 2.0)
garbage-only: Peter Kaminski (CC-BY 2.0)
golden-gate: Nicolas Raymond (CC-BY 2.0)
confusion: Procsilas Moscas (CC-BY 2.0)
module diagrams:
Nicolai Parlog
(CC-BY-NC 4.0)
broken-glass: Eric Schmuttenmaer (CC-BY-SA 2.0)
internals: David French (CC-BY 2.0)
cut: Jinx! (CC-BY-SA 2.0)
cells: Jonathan Lin (CC-BY-SA 2.0)
obsolete: Trevor King (CC-BY 2.0)
sign: Duncan Harris (CC-BY-SA 2.0)
question-mark: Milos Milosevic (CC-BY 2.0)
bundles: Danumurthi Mahendra (CC-BY 2.0)