Module Views

mark.reinhold at oracle.com mark.reinhold at oracle.com
Wed Dec 7 13:17:02 PST 2011


A build of the current Jigsaw prototype divides the JDK into 63 separate
modules.  Roughly a third of these modules are strictly for internal use
within the JDK, are useless on their own, and are not intended to be
referenced directly by application code.  We'd like to keep the total
number of modules comprising the JDK as small as is reasonable, so we've
been exploring ways to fold shared internal content into other modules.
The best technique we've come up with so far is that of _module views_.
Herewith a brief introduction.

Motivation
----------

About a third of the modules in the current prototype build exist only
because they define types used internally across multiple non-internal
modules.  These modules are named using the prefix "`sun`" rather than
"`jdk`", and they're defined with `permits` clauses so that only specific
JDK modules can reference them.

A typical example is the `sun.tls` module, which contains internal
implementation classes for the `javax.net.ssl` package and related APIs
defined in the `jdk.tls` module.  This module exists separately from
`jdk.tls` because the internal classes defined within it are used by
several other modules, as documented in the `permits` clause of its
declaration:

    module sun.tls @ 8-ea {
        permits jdk.crypto, jdk.sunpkcs11, jdk.tls, sun.compat,
                sun.jndi, sun.kerberos, sun.management, sun.rmi;
        exports sun.security.internal.interfaces.*;
        exports sun.security.internal.spec.*;
        exports sun.security.pkcs.*;
        exports sun.security.ssl.*;
        exports sun.security.util.*;
        exports sun.security.x509.*;
    }

(A summary of the current module-declaration syntax is available
[here][1].)

The `jdk.tls` module, which is intended for public consumption, is
defined simply as:

    module jdk.tls @ 8-ea {
        requires sun.tls @ 8-ea;
        exports com.sun.net.ssl.*;
        exports java.net.*;
        exports javax.net.*;
        exports javax.net.ssl.*;
        exports javax.security.cert.*;
    }

The `jdk.tls` module does not `requires public` the `sun.tls` module,
therefore the internal types defined in `sun.tls` are not available to
the outside world.  (For illustrative purposes the module declarations
shown here differ somewhat from those produced by the current prototype
build, which doesn't yet support explicit export declarations.)

Now in general we'd like to keep the total number of modules comprising
the JDK as small as is reasonable.  We're aiming to define a configurable
platform built from a set of coarse-grained modules that's easy for
developers to learn, straightforward for distro maintainers to package,
and simple for end users and system administrators to install and
upgrade.  Delivering a system in which a third of the modules are
strictly for internal use would not achieve that goal.

Module views
------------

The essential idea of module views is to separate the definition of the
content of a module from the definition of the external view of that
content.  We can then extend the syntax and semantics of module
declarations to allow a module to define more than one view.

The _content_ of a module is the set of types defined within it together
with those imported from other modules via `requires` clauses.  The
_view_ of a module is the set of types that it exports, via `exports`
clauses, and the set of modules to which those types are available, as
determined by any `permits` clauses.

Consider the following module declaration:

    module foo @ 1 {
        requires bar;
        exports foo.*;
    }

This defines a module named "`foo`", version 1.  It contains types
defined locally, e.g., on the module path under the `foo` module
directory, as well as all public types exported from the module `bar`.
It defines a single view which exports all public types in the `foo`
package to any other module.

A series of `exports` and `permits` clauses at the top syntactic level of
a module declaration defines the module's _default view_.  Further views
of a module's content can be defined using the new `view` construct,
which specifies a view name together with a bracketed list of exports and
permits declarations.

Suppose, e.g., that our `foo` module defines some private types which
need to be made available only to a third module, `baz`.  We can do that
by defining a `foo.internal` view:

    module foo @ 1 {
        requires bar;
        exports foo.*;
        view foo.internal {
            permits baz;
            exports foo.private.*;
        }
    }

The `foo` module now defines two views.  The default view, available by
referencing the module name `foo`, is the same as before---it's as if the
declaration also said `view foo { exports foo.*; }`.  The new view, named
`foo.internal`, is available only to the `baz` module.  It exports all
public types in the `foo.private` package.  It also exports all public
types in the `foo` package because the non-default views of a module
inherit the exports clauses of that module's default view.

A view can also declare an entry point different from that of its
containing module's default view, so a single module can now define
multiple related commands.  For example, the declaration

    module commands {
        view cat {
            class org.foo.commands.Cat;
        }
        view find {
            class org.foo.commands.Find;
        }
        view ls {
            class org.foo.commands.List;
        }
    }

defines three entry points, `cat`, `find`, and `ls`.

A few other details:

  - A non-default view never has `requires` clauses.

  - A non-default view cannot declare its version; it inherits the
    version, if any, of its containing module.

  - The `permits` clauses, if any, in a module's default view are not
    inherited by other views in that module.

  - In addition to declaring exports and entry points, a non-default
    view may also declare [services][2] and aliases.

Application
-----------

Returning to the original motivating example, module views allow us to
merge the `sun.tls` and `jdk.tls` modules into one:

    module jdk.tls @ 8-ea {

        requires local jdk.boot @ 8-ea;

        // Default view (available to all)
        exports com.sun.net.ssl.*;
        exports java.net.*;
        exports javax.net.*;
        exports javax.net.ssl.*;
        exports javax.security.cert.*;

        // Internal view (available only to permitted modules)
        view jdk.tls.internal {
            permits jdk.crypto, jdk.sunpkcs11, sun.compat,
                    sun.jndi, sun.kerberos, sun.management, sun.rmi;
            exports sun.security.internal.interfaces.*;
            exports sun.security.internal.spec.*;
            exports sun.security.pkcs.*;
            exports sun.security.ssl.*;
            exports sun.security.util.*;
            exports sun.security.x509.*;
        }

    }

Views also allow us to merge together modules that exist primarily to
define entry points.  The various compiler-like development tools
`javah`, `javac`, `javap`, and `javadoc`, e.g., share a lot of code but
currently each is defined in its own module since each requires its own
entry point.  Using views we can define them all in a single module:

    module jdk.devtools @ 8-ea {

        requires jdk.base @ 8-ea;
        requires jdk.compiler @ 8-ea;
        requires jdk.jaxp @ 8-ea;
        requires jdk.logging @ 8-ea;

        // exports external packages
        exports com.sun.javadoc.*;
        exports com.sun.source.tree.*;
        exports com.sun.source.util.*;
        exports com.sun.tools.doclets.*;

        view jdk.javah {
            class com.sun.tools.javah.Main;
        }

        view jdk.javac {
            class com.sun.tools.javac.Main;
        }

        view jdk.javadoc {
            class com.sun.tools.javadoc.Main;
        }

        view jdk.javap {
            class com.sun.tools.javap.Main;
        }

        view jdk.devtools.internal {
            ...
        }

    }

Applying these two kinds of transformations to the current prototype
build reduces the overall module count from 63 to 45.

Open issues
-----------

  - How do views map to native packaging systems such as RPM or Debian?
    Treating a module view as a virtual package would probably work but
    might not scale well.  Another possibility is to structure the names
    of non-default views so that they always include the names of their
    containing modules, but that turns views into second-class entities.

History and status
------------------

Module views are not a new idea.  The concept proposed here is very
similar to that of _structures_ in the module systems of [Scheme 48][3]
and [Standard ML][4].

Jon and Mandy are working to extend the Jigsaw prototype to support
views, and Alex is drafting new language and class-file specification
text.  All of this material will be published shortly.

- Mark


[1]: http://openjdk.java.net/projects/jigsaw/doc/topics/grammar.html
[2]: http://openjdk.java.net/projects/jigsaw/doc/topics/services.html
[3]: http://s48.org/1.8/manual/manual-Z-H-5.html
[4]: http://en.wikipedia.org/wiki/Standard_ML#Module_system



More information about the jigsaw-dev mailing list