Proposal: Move the `Module` and `Layer` classes from `java.lang.reflect` to `java.lang`

mark.reinhold at oracle.com mark.reinhold at oracle.com
Mon Mar 27 15:10:42 UTC 2017


(I'm proposing this API change via a new issue in order to make sure
 that everyone is aware of it.  Please let me know ASAP if you have any
 concerns; I'd like to merge it into an update of the Public Review
 draft.)

Issue summary
-------------

  #MoveModuleAndLayerClasses -- Move the `Module` and `Layer` classes,
  and a related exception class, from the `java.lang.reflect` package up
  into the `java.lang` package.  This will improve conceptual clarity, be
  consistent with the past, and leave room for the future.  [1]

Proposal
--------

Move and rename these classes as follows:

    java.lang.reflect.Module  ->  java.lang.Module
    java.lang.reflect.Layer   ->  java.lang.ModuleLayer
    java.lang.reflect.LayerInstantiationException
                              ->  java.lang.ModuleLayerInstantiationException

The `Layer` class is renamed to `ModuleLayer` so that it's easy for
readers to skip over that class by name rather than have to read its
Javadoc in order to learn that it's not what they're looking for.
The related exception is renamed to match.  (The `Module` class is
not renamed, about which more below.)

Motivation
----------

Experience shows that the best high-level shape for a non-trivial API is
often not apparent until it's nearly finished.  Looking at the totality
of classes and interfaces in the draft specification [2] and considering
the history and potential future of the platform leads to several reasons
for this proposed change.

  - For explanatory purposes there is a very useful and pleasant
    high-level conceptual analogy:

        class : class loader :: module : module layer

    That is, classes are instantiated via class loaders, and modules are
    instantiated via layers.  The types corresponding to these concepts
    should all be in the same package.

  - Existing constructs with keyword declarations in the language already
    have corresponding types in the `java.lang` package: `Class` for
    `class` and `interface`, `Package` for `package`, and `Enum` for
    `enum`.  Placing `Module` in the same package is consistent with
    these past choices.

  - The concepts of modules and layers will be with us for a very long
    time, and are just as fundamental as those of classes and class
    loaders.  The core reflection API in `java.lang.reflect` will be
    with us for a very long time too but it's not as fundamental, and it
    stands a good chance of being de-emphasized over time as alternatives
    are developed (e.g., Maurizio Cimadamore's mirror proposal [3]).

  - Long after `Class` was introduced we extended the language with the
    concept of class literals (e.g., `Object.class`).  Peering into the
    future, at some point we may want to extend the language to allow
    modules to be mentioned outside of module declarations, and in ways
    that relate language-level expressions to run-time `Module` objects.
    It would be unfortunate if such constructs had to be specified in the
    JLS to refer to a `Module` type in a legacy, de-emphasized
    `java.lang.reflect` package.

Impact
------

This is a cosmetic change.  No functionality will be added or removed.

This change is not, however, source-compatible relative to Java SE 8.  It
adds new types to the `java.lang` package, which is implicitly imported
on demand (i.e., `import java.lang.*`).  If code in an existing source
file imports some other package on demand, and that package declares a
`Module` type, and the existing code refers to that type, then the file
will not compile without change.  This could affect, among others, users
of the popular Guice framework, which declares its own `Module` type [4].

The impact of moving these three types from `java.lang.reflect` up into
`java.lang` is ameliorated by two factors:

  - A very common best practice is to use precise, type-specific `import`
    statements (e.g., `import com.google.inject.Module`) rather than
    import-on-demand wildcards (e.g., `import com.google.inject.*`).
    Code that follows this practice, which is well-supported by all the
    major IDEs, will compile without error [5].

  - If you declare a `Module` type in your own package then other code
    in your package that refers to that type will not be affected by the
    existence of `java.lang.Module`.  That's because an unqualified type
    name in source code resolves to a type in the same package in
    preference to a type in an import-on-demand package.

It may sometimes be necessary to add or adjust `import` statements in
order to compile existing source code for Java SE 9 but, unlike some
other kinds of changes required for migration, these kinds of changes
will compile on earlier releases.

Source compatibility from release to release is, in general, highly
desirable.  Unlike binary or behavioral compatibility, however, it has
never been a total commitment of the Java Platform.  Over the years we
have from time to time broken it in order to move forward, and this is
one of those times.


[1] http://openjdk.java.net/projects/jigsaw/spec/issues/#MoveModuleAndLayerClasses
[2] http://cr.openjdk.java.net/~mr/jigsaw/spec/api/java.base-summary.html
[3] http://cr.openjdk.java.net/~mcimadamore/reflection-manifesto.html
[4] https://google.github.io/guice/api-docs/latest/javadoc/com/google/inject/Module.html
[5] http://docs.oracle.com/javase/specs/jls/se8/html/jls-6.html#jls-6.4.1


More information about the jpms-spec-experts mailing list