Proposal: #ReflectiveAccessToNonExportedTypes: `exports dynamic`

Paul Benedict pbenedict at
Thu Jun 30 22:33:13 UTC 2016

As I have opined in an email a few days back [1], listing out who can
reflect over you is counterintuitive. The proposed "dynamic" feature only
works when you believe your analysis is sound, and you can absolutely
identify who may reflect over you. If after you publish to the world, and
find out that you're wrong, you're completely hosed forever. There's no way
to go back into the published library to fix the mistake -- you'd have to
publish a new version with an updated module descriptor.... (which, by the
way, ties in to David Llyod's frequent objection that the descriptor should
be something that is easily editable... and by that, it probably needs to
be OUTSIDE the module so as not to affect the SHA1 checksums of published
artifacts.... but I digress.)

To my main point, it's not really reasonable to know who may want to
reflect your internals. If you're publishing yourself as a common library
serving as middleware, how can you guess at that? You just can't. I fully
believe that the compiler and JRE should respect the inability to use
non-exported types under normal circumstances, but reflection is not a
normal circumstance. To enforce this restriction on reflection is very much
unpalatable because it puts developers in a guessing game. The proposed
"dynamic" is asking programmers to divine how their application will be
consumed in the future. It's just not possible.

Alex, in your counter example, pretend "myapp" has been published to the
Maven repository in 2017 and ten years has passed. In 2017, it's great that
"myapp" can use "opengamma.strata", but it becomes absolutely useless to
"opengamma.strata2" in 2027 despite the fact "myapp" should be perfectly
usable. See the problem?

Let's take this example closer to the real world:

(1.x) org.apache.struts
(2.x) org.apache.struts2
(3.x) ???

(1.x) org.apache.log4j
(2.x) org.apache.logging.log4j
(3.x) ???

JBoss Community/AS:
(<7) org.jboss
(8-11) org.wildfly
(12+) ??? * not implying a change but not presuming either



On Thu, Jun 30, 2016 at 4:58 PM, Alex Buckley <alex.buckley at>

> On 6/30/2016 2:29 PM, Stephen Colebourne wrote:
>> To take one example from OpenGamma Strata:
> (Line 50: I think "are" should be "as".)
> (Line 181: I notice that while "constants" and "lookup" providers are
> specified in the class-level javadoc, "instance" providers are not.
> Admittedly, reflection is used not only for the [unspecified] special field
> of an "instance" provider class but also for the [specified] no-args ctor
> of a "lookup" provider class.)
> ExtendedEnum is a mechanism to provide enum-like behaviour, where the
>> set of constants is fixed at startup, but controlled dynamically based
>> on what configuration files are present. One of the options it
>> provides is for the configuration file to specify a Class name, which
>> is then reflected on to find suitable enum-like constants.
>> When designing this feature, at no stage did I think that the code
>> would not work because some of the constants are in a different
>> module. (Application users can add their own configuration files and
>> constants, ie, in a separate module).
>> This proposal essentially requires application users to specifically
>> expose these types to reflection where they might otherwise lock them
>> down in a non-exported package. While in this case, I could document
>> that users of extended enums must make sure their code can be accessed
>> if in a different module, it would at the very least be a faff, and a
>> source of questions.
> Counterpoint: the user's is a great place to document the
> special relationship between one of their packages and one of their
> dependencies.
> module myapp {
>   requires opengamma.strata;
>   // Classes to drive Strata's ExtendedEnum instances
>   exports dynamic to opengamma.strata;
> }
> Alex

More information about the jpms-spec-observers mailing list