Proposal: #ResourceEncapsulation and #ClassFilesAsResources
mark.reinhold at oracle.com
mark.reinhold at oracle.com
Fri Jul 1 00:36:20 UTC 2016
2016/6/29 6:21:39 -0700, david.lloyd at redhat.com:
> On 06/28/2016 04:20 PM, Mark Reinhold wrote:
>> ...
>>
>> 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.
>
> I am really not a fan of unspecified resource order, especially when you
> can easily derive a stable order from the graph topology.
>
> Resources however should always load from the child-most loader first.
The `getResource*` methods in java.lang.ClassLoader have delegated to
the parent first since JDK 1.2, so for compatibility they'll have to
keep doing that. Custom loaders can, of course, continue to do whatever
they want.
> This isn't a problem in Jigsaw for classes because packages cannot be
> duplicated between modules (in a visible manner), but it becomes a
> problem with resources, especially if/when run-time cycles are
> permitted: you can run into an awkward situation where two mutually
> dependent modules each may see the other's resource "first" before their
> own, which is almost always undesirable.
This suggests that deriving a resource order from the graph topology
is maybe not as easy as you think. Is resource order, within a single
class loader, really so important that we should go to the trouble of
analyzing module relationships within that loader? If a container
application really needs fine-grained control over resource order then
it could always create a separate class loader for every module.
>> - 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.
>
> Does this also apply to automatic modules?
Yes, of course.
>> 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)`.
>
> I believe that in the former case, the "name" was historically relative
> to the location of the class. Is that behavior changing?
Good catch -- that's an error in my description.
>> Rationale
>> ---------
>>
>> 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 [4][5], but that is not the current practice and it will
>> take years to migrate to it.
>
> In many cases services are too limiting. It is useful for users to have
> a more powerful, general facility available that can use the same basic
> mechanism as services, but for arbitrary resources. For example, one
> case that came up quite recently (on Jigsaw-dev I think) was that it is
> useful to acquire not the service instance, but the class name, so that
> it could be constructed in various ways. Services as they are now
> require another front-end class to encapsulate this kind of variation.
> Also it is not uncommon for a situation to arise where many classes must
> be produced for variant services which all have the same basic behavior
> but differ only in details, which is awkward as well as it can result in
> large quantities of similar classes.
>
> It would be nice if service loading and resource loading continued to
> follow a similar set of rules. When Jigsaw switched ServiceLoader from
> a convenience API over resources to a separate concept, it lost the
> concept of using resources *as* an API component or participant, which
> is a powerful feature. This change will restore that to some degree,
> but it is still strange that loading a META-INF/services/com.foo.Service
> file will have different search semantics than using ServiceLoader.
> Basically we are taking this capability from users unless they do it the
> way that Jigsaw wants you to: via ServiceLoader, and no other way; it
> almost seems like Jigsaw is attempting to take on the characteristics of
> a container (not a very powerful one though because it only supports
> linking via services (a pretty thin concept when you think about it),
> not by (for example) annotations or anything else).
>
> Anyway I hope you can extract some kind of cogency from all that.
Um, no, not really.
At any rate this proposal is about resource loading, not services.
If you have a specific issue to raise or proposal to make about
services then please do so in a separate thread.
- Mark
More information about the jpms-spec-experts
mailing list