module java.sql {
requires transitive java.logging
requires transitive java.xml
uses java.sql.Driver
exports java.sql
exports javax.sql
exports javax.transaction.xa
}
this is about bringing a Java 8 app
into the future
we’re mostly looking at the bad and the ugly
slides at slides.codefx.org
code on GitHub at
CodeFX-org/demo-java-9-migration
JARs have:
no name the JVM cares about
no explicit dependencies
no well-defined API
no concept of versions
Some consequences:
NoClassDefFoundError
no encapsulation across JARs
version conflicts
Modules are like JARs but have:
proper names
explicit dependencies
a well-defined API
no concept of versions 😭
Important goals:
reliable configuration
strong encapsulation
A file module-info.java
:
module java.sql {
requires transitive java.logging
requires transitive java.xml
uses java.sql.Driver
exports java.sql
exports javax.sql
exports javax.transaction.xa
}
module java.sql {
requires transitive java.logging
requires transitive java.xml
}
Module system enforces:
all required modules are present
no ambiguity
no static dependency cycles
no split packages
module java.sql {
exports java.sql
exports javax.sql
exports javax.transaction.xa
}
Say you want to access java.sql.ResultSet
.
Module system only grants access if:
ResultSet
is public
java.sql
is exported by java.sql
your module reads java.sql
decoupling via services
finer grained dependencies and exports
open packages and modules (for reflection)
unnamed and automatic modules (for migration)
layers (for containers)
jlink
to create runtime images
Modularized JDK and legacy JARs have to cooperate.
Two requirements:
for the module system to work,
everything needs to be a module
for compatibility, the class path
and regular JARs have to keep working
The Unnamed Module
contains all JARs on the class path
(including modular JARs).
has no name (surprise!)
can read all modules
exports all packages
Inside the unnamed module
"the chaos of the class path" lives on.
Some internal changes break existing code!
Just by running on JDK 9+
(even without modularizing the application).
internal APIs are:
all in sun.*
most in com.sun.*
(unless marked @jdk.Exported
)
encapsulated at compile time
accessible at run time
for some time
critical APIs may survive longer
(e.g. sun.misc.Unsafe
)
JDeps can report internal dependencies:
$ jdeps --jdk-internals
-recursive --class-path 'libs/*'
scaffold-hunter-2.6.3.jar
> batik-codec.jar -> JDK removed internal API
> JPEGImageWriter -> JPEGCodec
> guava-18.0.jar -> jdk.unsupported
> Striped64 -> Unsafe
> scaffold-hunter-2.6.3.jar -> java.desktop
> SteppedComboBox -> WindowsComboBoxUI
look for reflection, especially
Class::forName
AccessibleObject::setAccessible
recursively check your dependencies!
fix your code
contact library developers
look for alternatives
(in the JDK or other libraries)
consider command line flags
--add-exports
, --add-opens
, or
--illegal-access
java.activation (javax.activation
)
java.corba (CORBA packages)
java.transaction (javax.transaction
)
java.xml.bind (javax.xml.bind.*
)
java.xml.ws (JAX-WS packages)
java.xml.ws.annotation (javax.annotation
)
These were
deprecated for removal in ⑨
removed in ⑪
JDeps shows dependencies on platform modules:
$ jdeps -summary sh-2.6.3.jar
> sh-2.6.3.jar -> java.base
> sh-2.6.3.jar -> java.datatransfer
> sh-2.6.3.jar -> java.desktop
> sh-2.6.3.jar -> java.logging
> sh-2.6.3.jar -> java.prefs
> sh-2.6.3.jar -> java.sql
> sh-2.6.3.jar -> java.xml
packages should have a unique origin
no module must read the same package
from two modules
The implementation is even stricter:
no two modules must contain
the same package (exported or not)
split packages on class path
are inaccessible
some libraries split java.xml.*
, e.g. xml-apis
some JBoss modules split, e.g.,
java.transaction
, java.xml.ws
jsr305 splits javax.annotation
JDeps reports split packages:
$ jdeps -summary
-recursive --class-path 'libs/*'
project.jar
> split package: javax.annotation
> [jrt:/java.xml.ws.annotation,
> libs/jsr305-3.0.2.jar]
Your artifacts:
rename one of the packages
merge package into the same artifact
merge the artifacts
place both artifacts on the class path
Otherwise:
upgrade the JDK module with the artifact
--patch-module
with the artifact’s content
new JDK/JRE layout
internal JARs are gone (e.g. rt.jar
, tools.jar
)
JARs are now JMODs
application class loader is no URLClassLoader
(no way to append to its class path)
new URL schema for run-time image content
does the code rummage around
in the JDK / JRE folder?
are URLs to JDK classes / resources handcrafted?
search for casts to URLClassLoader
Compact Profiles
Extension Mechanism
Endorsed Standards Override Mechanism
Boot Class Path Override
JRE version selection with -version:N
Yes, yes, there’s more:
Java 9 Migration Guide
(tiny.cc/java-9-migration)
Background:
And there are new version strings:
goodbye 1.9.0_31
, hello 9.0.1
The most relevant for most applications:
internal APIs
split packages
Java EE modules
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
download Java 11 and try it!
Java 10 contains few breaking changes:
mostly removal of deprecated methods
and command line options
bytecode level increases to 54.0
Every release will do that.
⇝ Get used to updating ASM, et al.
Java 11 contains few breaking changes:
removal of deprecated classes/methods
and command line options
removal of deprecated Java EE modules
bytecode level increases to 55.0
java.activation (javax.activation
)
java.corba (CORBA packages)
java.transaction (javax.transaction
)
java.xml.bind (javax.xml.bind.*
)
java.xml.ws (JAX-WS packages)
java.xml.ws.annotation (javax.annotation
)
⇝ Pick a third-party implementation
only rely on standardized behavior
heed deprecation warnings (jdeprscan
)
keep dependencies and tools up to date
build on each release (including EA)
report problems
⇜ Get my book!
You can hire me:
training (Java 8-11, JUnit 5)
consulting (Java 8-11)