Proposal: #ResourceEncapsulation & #ClassFilesAsResources (revised)

Mark Reinhold mark.reinhold at oracle.com
Mon Sep 12 15:10:01 UTC 2016


Issue summaries
---------------

  #ClassFilesAsResources --- If a type is visible and was loaded from a
  class file then it should be possible to read that file by invoking the
  `getResourceAsStream` method of the type's class loader, as it is in
  earlier releases. [1]

  #ResourceEncapsulation --- The `Module::getResourceAsStream` method can
  be used to read the resources of any named module, without restriction,
  which violates the resource-encapsulation requirement [2].  This method
  should be restricted somehow so that only "suitably-privileged" code
  (for some definition of that term) can access resources in a named
  module other than its own.  An alternative is to drop this
  requirement. [3]

Proposal
--------

Extend the notion of private exports, introduced nearby in the revised
proposal for #ReflectiveAccessToNonExportedTypes, to govern whether a
resource defined in a named module can be located by code in some other
module.

Resources are named by URL-like path strings.  The _effective package
name_ of an absolute resource name is computed by removing the initial
slash character, removing the final slash character (`'/'`) and any
subsequent characters, and then converting any remaining slash characters
to periods (`'.'`).  The effective package name of a resource named by
the string `"/foo/bar/baz"`, e.g., is 'foo.bar'.  The effective package
name of a relative resource name is computed by resolving the resource
name against a particular class, as if by the `Class::getResource`
method, and then computing the effective package name of the result.

For a resource defined in a named module we impose the following
restrictions upon code in other modules:

  - If a resource's name ends in `".class"` then it can be located by
    code in any module.

  - If a resource's effective package name is not a valid Java language
    package name (e.g., `"META-INF.foo.bar"`) [4] then the resource can
    be located by code in any module.

  - If the package is exported privately, without qualification, then the
    resource can be located by code in any module.

  - If the package is exported privately to a specific set of modules
    then the resource can be located by code in those modules.

  - If the package is not exported privately in any way then the resource
    cannot be located by code outside of the module itself.

We revise the various `getResource*` methods to impose the above
constraints:

  - The `Module::getResourceAsStream` method allows a resource to be
    located directly within a module, without first having to load a
    class from that module.  This method is caller-sensitive.

  - The `Class::getResource*` methods, when invoked upon a class defined
    in a named module, only locate resources from within that module.
    These methods are also caller-sensitive.

  - The `ClassLoader::getResource*` methods will locate resources in
    named modules subject to the above restrictions except that the
    effective package of the resource must be exported privately without
    qualification, since this method is not caller-sensitive.  Custom
    class loaders that locate resources in modules should implement these
    restrictions, but there is no way to force them to do so.  The order
    of the elements of an enumeration returned by the `getResources`
    method is unspecified, but for a given class loader `cl` the values
    of `cl.getResources(name).nextElement()` and `cl.getResource(name)`
    are always equal.

Every package in an unnamed, automatic, or weak module is exported
privately, so all of the resources in such modules can be located by
code in all other modules.

Notes
-----

  - The first proposal for these issues [5] suggested that we simply drop
    the agreed resource-encapsulation requirement [2].  As suggested both
    in the EG [6] and elsewhere [7][8], this revised proposal attempts to
    strike a balance between practical compatibility and modular
    encapsulation.

  - This proposal leverages private exports, i.e., the `exports private`
    directive, since the internal resources of a module are much like the
    non-public elements of the types defined in a module.  This avoids
    leaking resources inadvertently from packages that are exported
    normally, i.e., without the `private` modifier.  It also avoids the
    need to extend the syntax and semantics of module declarations with
    a completely new directive just for resources, which seems like
    overkill.


[1] http://openjdk.java.net/projects/jigsaw/spec/issues/#ClassFilesAsResources
[2] http://openjdk.java.net/projects/jigsaw/spec/reqs/#resource-encapsulation
[3] http://openjdk.java.net/projects/jigsaw/spec/issues/#ResourceEncapsulation
[4] http://docs.oracle.com/javase/specs/jls/se8/html/jls-6.html#jls-PackageName
[5] http://mail.openjdk.java.net/pipermail/jpms-spec-experts/2016-June/000309.html
[6] http://mail.openjdk.java.net/pipermail/jpms-spec-experts/2016-June/000322.html
[7] http://mail.openjdk.java.net/pipermail/jpms-spec-comments/2016-June/000050.html
[8] http://mail.openjdk.java.net/pipermail/jpms-spec-comments/2016-June/000051.html


More information about the jpms-spec-experts mailing list