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-observers
mailing list