My preference of these three options is option 2. However, I would prefer to see the method name be defined by the module definition as previously suggested [1]:
module { provides java.sql.Driver with com.mysql.jdbc.Driver::instance; } This would allow ::staticMethod or ::staticConstant, and avoid hard-coding "provider" as a special method name. (For my motivating use case, the Chronology classes of ThreeTen-Extra [2] it would be distracting to have a method named provider(). While a separate class in a non-exported package would be possible to hold the provider() method, as a solution that seems like overkill relative to the syntax above.) Stephen [1] http://mail.openjdk.java.net/pipermail/jpms-spec-observers/2016-July/000535.html [2] https://github.com/ThreeTen/threeten-extra/tree/master/src/main/java/org/threeten/extra/chrono On 12 September 2016 at 16:13, Mark Reinhold <mark.reinh...@oracle.com> 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.) > > [1] > http://openjdk.java.net/projects/jigsaw/spec/issues/#ServiceLoaderEnhancements > > -- > > /** > * Represents a service provider located by {@code ServiceLoader}. > * > * <p> When using a loader's {@link ServiceLoader#stream() stream()} > method > * then the elements are of type {@code Provider}. This allows processing > * to select or filter on the provider class without instantiating the > * provider. </p> > * > * @param <S> The service type > * @since 9 > */ > public static interface Provider<S> extends Supplier<S> { > > /** > * Returns the provider class. There is no guarantee that this type is > * accessible and so attempting to instantiate it, by means of its > * {@link Class#newInstance() newInstance()} method for example, will > * fail when it is not accessible. The {@link #get() get()} method > * should instead be used to obtain the provider. > * > * @return The provider class > */ > Class<S> type(); > > /** > * Returns an instance of the provider. > * > * @return An instance of the provider. > * > * @throws ServiceConfigurationError > * If the service provider cannot be instantiated. The error > * cause will carry an appropriate cause. > */ > @Override S get(); > > } > > /** > * Returns a stream that lazily loads the available providers of this > * loader's service. The stream elements are of type {@link Provider > * Provider}, the {@code Provider}'s {@link Provider#get() get} method > * must be invoked to get or instantiate the provider. > * > * <p> When processing the stream then providers that were previously > * loaded by stream operations are processed first, in load order. It then > * lazily loads any remaining providers. If a provider class cannot be > * loaded, can't be assigned to the service type, or some other error is > * thrown when locating the provider then it is wrapped with a {@code > * ServiceConfigurationError} and thrown by whatever method caused the > * provider to be loaded. </p> > * > * <p> If this loader's provider caches are cleared by invoking the {@link > * #reload() reload} method then existing streams for this service > * loader should be discarded. </p> > * > * <p> The following examples demonstrate usage. The first example > * creates a stream of providers, the second example is the same except > * that it sorts the providers by provider class name (and so locate all > * providers). > * <pre>{@code > * Stream<CodecSet> providers = ServiceLoader.load(CodecSet.class) > * .stream() > * .map(Provider::get); > * > * Stream<CodecSet> providers = ServiceLoader.load(CodecSet.class) > * .stream() > * .sorted(Comparator.comparing(p -> p.type().getName())) > * .map(Provider::get); > * }</pre> > * > * @return A stream that lazily loads providers for this loader's service > * > * @since 9 > */ > public Stream<Provider<S>> stream() { ... }