Proposal: #ServiceLoaderEnhancements
David M. Lloyd
david.lloyd at redhat.com
Mon Sep 12 16:32:17 UTC 2016
On 09/12/2016 10:13 AM, Mark Reinhold wrote:
> Issue summary
> -------------
>
> #ServiceLoaderEnhancements --- The module system encourages the use of
> services for loose coupling, but the `ServiceLoader` class is not very
> flexible. Consider enhancing it so that (1) neither a provider class
> nor its no-args constructor need be declared `public`, (2) a provider
> can be a singleton, or perhaps a collection of singletons, and (3) the
> classes of the available providers can be inspected and selected prior
> to instantiation. [13]
>
> Proposal
> --------
>
> (1) No change: Continue to require service-provider classes, and their
> no-args constructors, to be public.
>
> Providers on the class path, and their no-args constructors, must
> always be public. Allowing a class-path provider or its no-args
> constructor to be non-public introduces a security risk, since an
> adversary could place a `META-INF/services` entry elsewhere on the
> class path in order to force that otherwise-inaccessible
> constructor to be invoked.
>
> For providers in named modules, allowing non-public provider
> classes and non-public no-args constructors isn't really necessary
> and is, in some ways, counterproductive. In a named module a
> provider class, and its constructor, can be encapsulated by placing
> the provider in an unexported package. Having to declare the
> provider class and its no-args constructor `public` is a useful
> declaration of intent, since they will be accessed by the service
> loader itself, and hence useful documentation.
>
> (2) Revise the `ServiceLoader` class so that if a candidate provider
> class in a named module has a no-args public static method named
> `provider` then that method is invoked and its result is taken as
> the provider object. An exception is thrown if the method does
> not have an appropriate return type. A static `provider` method
> can either return a singleton or act as a factory method. If the
> candidate provider class does not have such a method then its
> public no-args constructor, if any, is invoked, per (1) above.
>
> (An alternative is to use an annotation, say `@Provider`, to
> identify provider-containing fields or provider-returning methods.
> The cost of loading the annotation-reading code into the JVM is,
> however, nontrivial, and since services are used widely within the
> JDK itself we'd prefer not to impose that overhead on all
> applications.)
>
> (3) Decouple the loading of provider classes from the instantiation of
> such classes: Introduce a new `ServiceLoader.Provider` interface
> that pairs a provider class with a method to instantiate that
> provider, and add a `stream()` method that returns a stream of
> objects implementing that interface. A client can then filter
> providers by inspecting the elements of the stream, examining each
> provider class and perhaps the annotations thereon, and then
> instantiating the class if appropriate. (Draft Javadoc source
> attached below.)
I think proposal 2 makes the most sense from our perspective: it's a
simple, low-infrastructure, effective solution. I also tend to agree on
the security points mentioned.
--
- DML
More information about the jpms-spec-experts
mailing list