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