Exporting things (Was: Re: Module-system requirements)
mark.reinhold at oracle.com
mark.reinhold at oracle.com
Mon Feb 16 01:24:05 UTC 2015
2015/2/11 11:27 -0800, david.lloyd at redhat.com:
> I notice that under Exports, it is defined that only packages (i.e.
> classes within those packages) are considered to be exportable, and not
> resources. I'm not certain how I feel about that... in our
> implementation we flattened the concepts of packages and directories.
> This was mainly to solve a few specific difficulties of supporting plain
> JARs as module content; a JAR has a mix of classes and resources, and it
> is hard to deterministically tell the difference, especially when you
> can do such (commonly done) things as:
> classLoader.getResource("org/foo/bar/SomeClass.class").
>
> ...
>
> However this approach is not without its difficulties: ...
>
> ... To sum up though, I'd be glad to see (from my perspective) this
> behavior go away in favor of the simpler model of restricting exports to
> packages (and isolating classes and resources),
I tend to agree.
Exposing all of a module's resources, as JAR files do today, is wrong
from the perspective of encapsulation. Extending the "exports"
requirement to allow control over which resources are exported leads to
both conceptual and implementation complexity (e.g., what would it mean
to export both a class, as a type, as well as the corresponding .class
file, or the latter and not the former?) It seems sanest to treat
resources as strictly internal to modules.
This suggests an additional requirement:
- _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.
> but only if we can be
> reasonably sure that the use cases solved thereby are somehow sorted
> out, which include:
>
> • Supporting this case (or determining that it is not relevant): A
> module privately uses services provided by one or more specific peer
> module(s) (via ServiceLoader), the arrangement of which is determined
> statically by distribution.
One way to accomplish this is to make the service interface accessible
only by the relevant modules, via qualified exports. Then only those
modules can provide or use implementations of the service.
Another possibility is to add a requirement that the binding of providers
to service interfaces can be controlled manually during the configuration
process. Is that more along the lines of what you mean when you say
"determined statically by the distribution"?
> • Having (generally) the same visibility to .class files as to the
> classes themselves, from a given resource-loading entry point (Class or
> ClassLoader), i.e. if I have visibility to
> classLoader.loadClass("SomeClass"), I also have visibility to
> classLoader.getResource("SomeClass.class"), and vice-versa (any security
> restrictions aside).
Can you describe some use cases that require this property?
What if a module is compiled to native code ahead-of-time, and hence
doesn't necessarily contain a .class file for every class?
> • A consistent ruling on the right behavior of general resources which
> are co-packaged with classes that use them (typically loaded via e.g.
> getClass().getResourceAsStream("MyResource.properties") or similar).
If we take the view that resources are module-internal then the answer
is that code within a module can access that module's resources but code
outside of the module cannot (with the usual exception for reflection,
which would require a security check).
> • A consistent ruling on whether it makes sense generally to be able to
> export resources to dependents.
If we take the view that resources are module-internal then the answer is
no, this does not make sense. A module can export packages of classes
and interfaces, and can publish service providers; it cannot also export
files in a string-based hierarchical namespace.
> A minor, somewhat related point that this raises...
>
> The term "dependences" (rarely-used pl. of "dependence") is used quite a
> lot in the document (whether intentional or otherwise), but I think that
> the term "dependencies" (pl. of "dependency") is probably a better term,
> and is definitely a more ubiquitous one. The inverse of "dependency" is
> "dependent", which forms a concise term pair that we use quite a lot
> internally (i.e. if A is a dependency of B, B is a dependent of A).
You're not the first to ask me about this ...
"Dependence" and "dependency" name distinct concepts. A dependence is a
relationship, potentially unfulfilled; a dependency is a thing which can
fulfill a relationship of dependence. When thinking, speaking, or
writing about modules I find it useful to keep this distinction clear.
A module, standing alone, can have dependences upon some other,
yet-to-be-identified modules. All that is known is that they have
specific names, or that they provide specific services. The module's
definition, in other words, merely describes relationships and
constraints upon how those relationships can be fulfilled; it does not
identify the specific modules that will fulfill those relationships.
The processes of resolution and service binding identify the actual
modules, i.e., the dependencies, that will satisfy a module's
dependences.
I agree that "dependent" is also a useful term. In ASCII-art form the
three concepts are related thus:
Dependence
Dependent --------------> Dependency
- Mark
More information about the jpms-spec-observers
mailing list