Reflective Access, Maven On Java 9, And Speeding Through The Night
CodeFX Weekly #19 — 19th of May 2017
once again this weekly is full of Java 9. I discuss yesterday’s proposal to by default allow reflective access to internal APIs and then look at a hurdle I encountered when building a project with Maven and Java 9. The project of the week helps you unit test your architecture.
I send this newsletter out every Friday. Yes, as an actual email. Subscribe!
Java 9 News
Taking JPMS Into The Wrong Direction
As I’m sure you know by now, the module system brings strong encapsulation to the Java platform, where modules can hide their internals and not even reflection can work around that. If applications, be it their own code or their libraries and frameworks, depend on internal APIs, then they can get access to them by using the
--add-opens flag. And for a while, things were good.
Then people started complaining about
sun.misc.Unsafe, how everybody used it and how it was not fair to make users of it add such complicated flags. So it was decided that
Unsafe (and other critical APIs) will end up in a module
jdk.unsupported, so they are still freely accessible. And for a while, things were good.
Then people started complaining that they were using so many other internal types, too, and having to identify all of them was too much work and adding so many command line flags could not be expected from busy developers. So it was decided that there would be a “kill switch”, a flag
--permit-illegal-access, which would in one sweep allow all legacy code (i.e. the class path) to access JDK internals. As a trade off it would emit warning messages, informing you of your sin. And for a while, things were good.
Then came the JSR 376 vote and still people bitched that life was too hard and that even adding that one flag and having to live with warnings in the log is too much of a burden on the developer’s feeble mind. How could anybody be expected to do all that hard work of finding the place where to add
--permit-illegal-access? And anyway, why does Oracle never listen? You never listen!
So here comes Mark Reinhold’s newest proposal:
I hereby propose to allow illegal reflective access from code on the class path by default in JDK 9, and to disallow it in a future release.
In short, the existing “big kill switch” of the
--permit-illegal-accessoption  will become the default behavior of the JDK 9 run-time system, though without as many warnings. The current behavior of JDK 9, in which illegal reflective-access operations from code on the class path are not permitted, will become the default in a future release. Nothing will change at compile time.
I can’t even… Here’s my opinion on the matter:
I think making the lenient option the default is a bad decision, needlessly prolonging a proper clean-up of the ecosystem without any practical benefit!
Java’s stewards have been warning against using internal APIs for 20 years. Jigsaw announced to make them inaccessible for nigh two years now. Java 8 will be supported until at least July 2018 and even after that all that is needed to get around this specific Java 9 compatibility problem is to add
All that is not enough, though? Even adding that single flag is too hard? If spending an hour or two reading up on JPMS and then adding that flag is too much to ask, then how can one expect the same people to clean up their code?
With illegal access being permitted by default much fewer developers will be aware of the problem and much less pressure will be put on library and framework maintainers as well as on project management to invest into paying back this particular form of technical debt. So we get much less momentum to make the necessary changes in exchange for… not having to add a flag? That’s ridiculous, an Armutszeugnis for the Java community!
It looks like this will turn out to be a minority report, though — almost everybody else loves that their applications, libraries, and frameworks can continue to violate encapsulation without them having to change anything for Java 9.
Things will be different for Java 10, though, believe me. Everybody will have updated their code by then, so no one will complain when the JVM gets more restrictive.
I believe it when I see it.
Java 9 Code
What’s the difference between add-exports and add-opens?
--add-exportsthe package is exported, meaning all public types and members therein are accessible at compile and run time.
--add-opensthe package is opened, meaning all types and members (not only public ones!) therein are accessible at run time.
So the main difference at run time is that
--add-opens allows "deep reflection", meaning access of non-public members. You can typically identify this kind of access by the reflecting code making calls to
Maven And Java 9 Flags
One way to start migrating a project to Java 9 is to compile it with javac 9. There are different ways to do this with Maven and one of them (
.mavenrc file) leads to the entire Maven process running on Java 9. For reasons I'm not going into we need Maven to run on Java 9 anyway so we took that approach.
Contribute to mvn-java-9 development by creating an account on GitHub.
But: Some Maven plugins operate on internal APIs or depend on Java EE modules (which have to be added manually), so the JVM running them needs to be launched with some command line flags like
--add-opens (although maybe not much longer - see above) or
--add-modules. No problem if they can be forked into their own process but that is not always implemented. In those cases they run in the Maven process, meaning Maven must be launched with the appropriate flags.
This is possible by creating a file
.mvn/jvm.config in the project's folder (see documentation). Unfortunately the project can then no longer be built with Java 8 because Maven applies the flags it finds in that file when launching the JVM but version 8 does of course not know any of them and hence barfs. We have some ideas how to fix that once we want to set up a CI build but during experimentation, where you occasionally want to switch between 8 and 9, that really sucks.
Hunting down a differnet compatibility problem I started to switch constantly, though, and to not go bonkers I created the following script:
Depending which versions I want to run on, it creates the following configuration:
.mavenrcis commented out, starting the process with "system Java"
- the project’s
.mvnfolder contains no file called
jvm.config(if it existed it was renamed to
.mavenrcis not commented out, starting the process with the defined Java, which is 9
- the project’s
.mvnfolder may contain a file called
jvm.config(if it existed as
That saved a lot of time. Only caveat: If you have several projects and switch one to Java 8 (for example), another one might still be partially stuck on Java 9 because the
.mvn/jvm.config is not renamed across subprojects.
Bla Bla Bla
I was recently interviewed by the Talking Tech Podcast about Java 9 (in German). It was released last Monday and you should totally check it out! If you like it (or any of other Talking Tech Podcasts), give the guys a shout out. They are still pretty new and can use the publicity.
#5: Nicolai Parlog - codefx.org
Diesmal ist Nicolai Parlog bei uns zu Gast. Nicolai ist Autor des Buchs The Java 9 Module System und er spricht mit uns…
On Thursday I flew back to Frankfurt, took a car to Braunschweig, told the JUG Ostfalen that Java 9 is coming (slides), drove the car back to Frankfurt, hopped into a train home (Karlsruhe), where I arrived after 23 hours of travel — intense.
It has been some time since I drove long distance (well, “long”… three hours each way) and it was great fun to do it again! Listened to Rachel Maddow (Trump’s special prosecutor), Software Engineering Daily (digital ownership), Rammstein (Mutter), Metallica (Master of Puppets), and — the geek cherry on this nerd sundae — Wil Wheaton and his friends play the pen and paper RPG Titansgrave (I’m not actually too enthused about their style to play but it’s still fun to listen to).
Speeding through the night, 190 km/h, speakers blaring “Master! Master!”… I missed that.
Project Of The Week
This week’s project is ArchUnit, which I will let speak for itself:
ArchUnit is a free, simple and extensible library for checking the architecture of your Java code. That is, ArchUnit can check dependencies between packages and classes, layers and slices, check for cyclic dependencies and more. It does so by analyzing given Java bytecode, importing all classes into a Java code structure. ArchUnit’s main focus is to automatically test architecture and coding rules, using any plain Java unit testing framework.
It looks like this:
Isn’t that something?
This is the shot to end all shots: What The Fuck Just Happened Today? Every Californian afternoon Matt Kiser summarizes all the weird shit the Trump administration got caught up in in a succinct list, summarizing each event in a handful of lines, linking to primary sources. Priceless. Also: Fear inducing! On Twitter, too.