A way to opt out of access restrictions on non-exported members.

Remi Forax forax at univ-mlv.fr
Sun Nov 15 18:14:17 UTC 2015

There are several ways to opt-out if you control the command line,
- put all your modules in the classpath or remove all the module-info from the modules in the module-path,
- create a jlink plugin that will crawle all modules (or the ones you want) and change the module-info,
- at runtime to create a new layer that will bypass the application classloader and change the module configuration on-the-fly.
And there are more exotic ways if you are able to change the bytecodes.

Anyway, one goal of jigsaw is to harden the Java plateform, so you can weaken the plateform if you want but it should not be neither the default mode nor it should not be too easy (reflection i'm looking at you) to do that.

Now, in the details,
- you can still access to members of exported classes by reflection, you may have to add a read edge between the corresponding modules for that, but it's possible.
- you can access to members of a non exported classes by using their interfaces if these interfaces are exported (the same way you can access members of a non public class in pre-jigsaw world).


----- Mail original -----
> De: "Reinier Zwitserloot" <reinier at zwitserloot.com>
> À: "jigsaw-dev" <jigsaw-dev at openjdk.java.net>
> Envoyé: Dimanche 15 Novembre 2015 12:03:20
> Objet: A way to opt out of access restrictions on non-exported members.
> TL;DR: There are rather a lot of libraries out there that access private
> members via reflection. I posit that almost all such libraries break
> without an easy way to fix the problem, if there is no way to use
> reflection to access non-exported members.
> setAccessible(true) doesn't let you opt out of module access rules. There
> are ways to effectively 'read' everything (and if not, there's addRead),
> but that still doesn't help if you need to reflectively access a member
> that isn't exported. According to the questions at the end of the J1
> session 'Advanced Modular Development (CON6821)', by Mark Reinhold, Alex
> Buckley, and Alex Bateman, there is no way to in-process get around the
> JVM-enforced access restriction.
> Now, under normal circumstances you shouldn't be accessing such classes /
> methods / fields / constructors in the first place, but that exact same
> line of reasoning can be used to defend not including setAccessible,
> getDeclaredMethod(s), getDeclaredField(s), and all the other ways the
> reflection API can be used to access (in JDK1-JDK8, at least) protected,
> package private, and private elements. Those things were never designed to
> be accessed either, and yet, accessing private members of existing stuff
> occurs in lots of libraries, usually for:
> * Dependency injection (guice and company)
> * Debugging tools (not all of these use JVMTI; sometimes you just have a
> utility method that dumps some information to a log that includes private
> members just because that seems like it'll help debug an exotic condition
> that you can't quite put your finger on).
> * Code automation tools (apache has a few utilities that return a useful
> hashCode, which work by inspecting your instance's fields).
> * Serialization libraries. I'm pretty sure a number of core JDK devs have
> gone on record not liking the built in serialization mechanism
> (java.io.Serializable and co), but third party solutions access private
> members all the time to do their job.
> * Workarounds. This one is a perhaps controversial, but as the saying goes,
> java is a 'blue collar' programming language. Sometimes you use access to
> private members to work around a bug or to get access to functionality that
> optimally speaking should be done differently or should be accomodated with
> an update to the library to make that part designed for public access.
> What are such libraries to do? They could provide the user with ways to use
> command line switches to hack in the required exports, but this is the kind
> of hassle that is going to reflect badly on JDK9 and slow adoption rates. I
> propose some mechanism to get around the restriction is added, with all due
> warnings in the documentation that this should be considered a hacky
> workaround. (interestingly, such commentary is not part of the javadoc on
> .setAccessible!)
> Alternatively, there are 3 ways this can go:
> * The authors of these libraries, or the help forums associated with such
> libraries, start espousing the principle that you should just export
> everything from your modules, or 'things might break'. This doesn't sound
> like a desirable outcome for the jigsaw project. It certainly doesn't sound
> desirable to me.
> * The authors of these libraries, or the help forums associated with this
> libraries, start espousing the principle that upgrading to JDK9 is an
> arduous slog, and that it is better to just stick with JDK8 for the
> foreseeable future. Certainly, not a desirable outcome.
> * The heavens part, ponies and rainbows for all, and everyone takes the
> time to update their serialized data structures or whatnot to make sense in
> a 'these are exported, these are not' world. I'm not sure this is even
> possible; it would make sense to have a public interface, and then 2
> (non-exported!) classes that are implementations of this. How would a
> no-hassle serialization library ever get this done without a way to dodge
> the rules? A module can export _TO_ a serialization library, but this
> breaks encapsulation: Now the author of framework A needs to know that the
> user of said framework so happens to have a desire to serialize the stuff
> from framework A using serialization library X. In practice you'd have to
> export everything to all the serialization frameworks out there, and now no
> new framework can ever be created because all these libraries failed to
> export their internals to them. In any case this boils down to 'just export
> every package to this subset of tools',  and that's the best case scenario,
> which doesn't sound desirable either.
> I guess option 4 is: "Surely it won't be that bad", but that's a bit of a
> gamble to make, given that the stakes are serious lack of adoption of JDK9,
> or widespread misconfiguration of exports clauses.
> NB1: Note also that JDK9 has taken its time (and rightly so) to fix its
> ball-o-twine dependency mess. However, once JDK9 is unleashed upon the
> masses, a 'quick fix' to make libraries at least workable with JDK9
> probably require such hacks. If it's not possible to do it, then libraries
> won't be JDK9 ready for years. Perhaps other projects aren't as messy as
> JDK pre-9 was, but let's not make that assumption.
> NB2: The module system already has a larger impact on adoption (compared to
> 6, 7, or 8) simply because of the unavoidable differences inherent in what
> jigsaw is doing (I bet a bunch of command line scripts are going to end up
> breaking, for example, or at least will be obsolete). Adding more barriers
> to adoption is something that should, in my opinion, by taken particularly
> seriously for this release.
>  --Reinier Zwitserloot

More information about the jigsaw-dev mailing list