Issue #ServiceLoaderEnhancement

mark.reinhold at oracle.com mark.reinhold at oracle.com
Wed Jul 13 18:06:13 UTC 2016


2016/7/1 2:27:39 -0700, Stephen Colebourne <scolebourne at joda.org>:
> The ServiceLoader API is to be pushed as a key class by the module
> system. This issue is proposing enhancements to the API. Others may
> want to add their own proposals.
> 
> Currently, ServiceLoader requires service implementations to have a
> public no-args constructor on a public class. This is very
> restrictive, especially in a Java 8 world of immutable classes and
> factory methods (with constructors actively avoided).
> 
> JSR-310 has a service for loading Chronology implementations. In
> ThreeTen-Extra, I have a number of additional implementations [1].
> Unfortunately, all the implementations are forced to have a public
> no-args constructor, as ServiceLoader cannot make use of the singleton
> INSTANCE constant. As can be seen, I have to mark the public no-args
> constructor as deprecated [2]. This state of affairs is frankly
> ridiculous, and is one of the reasons putting me off using
> ServiceLoader non-JDK code.
> 
> I propose that the spec of ServiceLoader is extended to make it more useful.
> 
> Firstly, I propose that all reflection by ServiceLoader should use
> setAccessible(true) to allow providers to be non-public.

We could do this for service providers defined in modules, but not for
those specified via the META-INF/services convention.  The problem with
the latter is that if ServiceLoader could instantiate an arbitrary
non-public class then an adversary could spoof it into doing that simply
by placing an appropriate META-INF/services configuration file on the
class path.  That's not possible for providers in modules, since the
declaration of the provider and the provider itself are always tightly
associated with each other, in the same artifact, so we can relax the
restriction in that case.

> Secondly, I propose that if no public no-args constructor is found on
> the provider class, ServiceLoader should locate a public static
> constant named "INSTANCE" and use that instead.

That's reasonable, though we don't have much precedence for name-based
conventions in the SE platform itself.

> This proposal could be extended further. Instead of searching for
> "INSTANCE",  it could look for all public static constants of the
> provider type, allowing one provider class to result in many provider
> instances.

I suspect that might be one heuristic too much.  I could see searching
for INSTANCE, and maybe also INSTANCES where the latter refers to an
array or a collection of appropriate type, but just taking anything based
solely upon type matches could lead to difficult-to-diagnose failures.

An alternative is to take an explicitly-declarative approach, defining
something like a @Provides annotation to identify the constructors,
factories, or fields that construct or contain actual provider objects.
I'll give this some thought.

> Thirdly, it should be possible to access the set of provider classes
> without instantiating them. This would allow applications to use the
> module-info design for services without using ServiceLoader, eg to
> reflect on the provider classes, perhaps to search for annotations.

As an historical note, the original idea way back in Java 1.3 was for
complex providers to be represented by small, lightweight proxy objects
rather than full providers, or types.  To quote the specification (of
the sun.misc.Service class, before it became java.util.ServiceLoader):

 *           ...  This <i>provider class</i> will typically not be the entire
 * provider itself but rather a proxy that contains enough information to
 * decide whether the provider is able to satisfy a particular request together
 * with code that can create the actual provider on demand.  The details of
 * provider classes tend to be highly service-specific; no single class or
 * interface could possibly unify them, so no such class has been defined.

Most of the services defined and used in the JDK itself follow this
advice, but I accept that many others out in the world do not, so at
this point people reasonably want to be able to filter providers based
on types and annotations thereon.  This should be straightforward; I'll
work up a proposal.

> I hope this proposal is given serious consideration, as at present the
> design of ServiceLoader is simply too restrictive to be appropriate to
> be hard coded into the module specification.

These are all good suggestions; thanks for raising them here.  I've added
them to the issue list:

  http://openjdk.java.net/projects/jigsaw/spec/issues/#ServiceLoaderEnhancements

- Mark


More information about the jpms-spec-observers mailing list