Proposal: #ResourceEncapsulation and #ClassFilesAsResources
mark.reinhold at oracle.com
Tue Jun 28 21:20:15 UTC 2016
#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. 
#ResourceEncapsulation --- The `Module::getResourceAsStream` method can
be used to read the resources of any named module, without restriction,
which violates the resource-encapsulation requirement . 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
Drop the agreed resource-encapsulation requirement, which reads:
Resource encapsulation --- The run-time system must ensure that the
static resource files within a module are directly accessible only by
code within that module. The existing resource-access APIs should
continue to work as they do today when used to access a module's own
resource files. 
Make the following changes to the various `getResource*` methods:
- The `ClassLoader::getResource*` methods will first delegate to the
loader's parent, if any, and will then search for resources in the
named modules defined to the loader, and will then search in the
loader's unnamed module, typically defined by a class path. In the
case of the `getResources` method the order of the resources in the
returned enumeration will be unspecified, except that the values of
`cl.getResources(name).nextElement()` and `cl.getResource(name)`
will be equal.
- The `Class::getResource*` methods will only search for resources in
the module that defines the class. In the case of a class in an
unnamed module this will typically result in searching the class
path of the corresponding class loader.
The `java.lang.reflect.Module::getResourceAsStream` method will remain,
so that it's possible to look up a resource in a module without having a
reference to a class defined in that module. It will always be the case
that, for a given a class `c`, `c.getResourceAsStream(name)` will be
equivalent to `c.getModule().getResourceAsStream(name)`.
The encapsulation of resources was intended to be part of the overall
encapsulation story, on the view that a module's resources are just
internal implementation details that need not, and should not, be
available to code in other modules. Allowing external code to depend
upon a module's internal resources is just as problematic as allowing
such code to depend upon internal APIs.
The reality of existing code today, however, is rather different, with
two common use cases:
- Resources are often used intentionally to convey information to
external code, e.g., as a way to publish configuration files such as
`persistence.xml`. This sort of thing should, ideally, be done via
services , but that is not the current practice and it will
take years to migrate to it.
- Various popular tools and byte-code manipulation frameworks expect to
be able to load class files as resources, i.e., to access the class
file that defines a class `p.q.C` by invoking `getResource("p.q.C")`
on that class's loader.
With the API as it stands today these use cases can still be supported,
but the code that looks up the resource must be converted to use the
`Module::getResourceAsStream` method. This is a barrier to migration,
since it means that fewer existing frameworks will work out-of-the-box
as automatic modules.
We should not drop agreed requirements lightly, but now that we have
some practical experience with an implementation of this one I think
it's clear that the pain outweighs the gain.
More information about the jpms-spec-experts