/*
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.util;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.net.URLConnection;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import sun.nio.cs.UTF_8;
import jdk.internal.loader.BootLoader;
import jdk.internal.loader.ClassLoaders;
import jdk.internal.access.JavaLangAccess;
import jdk.internal.access.SharedSecrets;
import jdk.internal.misc.VM;
import jdk.internal.module.ServicesCatalog;
import jdk.internal.module.ServicesCatalog.ServiceProvider;
import jdk.internal.reflect.CallerSensitive;
import jdk.internal.reflect.Reflection;
A facility to load implementations of a service.
A service is a well-known interface or class for which zero, one,
or many service providers exist. A service provider (or just
provider) is a class that implements or subclasses the well-known interface or class. A ServiceLoader
is an object that locates and loads service providers deployed in the run time environment at a time of an application's choosing. Application code refers only to the service, not to service providers, and is assumed to be capable of choosing between multiple service providers (based on the functionality they expose through the service), and handling the possibility that no service providers are located.
Obtaining a service loader
An application obtains a service loader for a given service by invoking one of the static load
methods of ServiceLoader
. If the application is a module, then its module declaration must have a uses
directive that specifies the service; this helps to locate providers and ensure
they will execute reliably. In addition, if the application module does not
contain the service, then its module declaration must have a requires
directive that specifies the module which exports the service. It is strongly
recommended that the application module does not require modules which
contain providers of the service.
A service loader can be used to locate and instantiate providers of the service by means of the iterator
method. ServiceLoader
also defines the stream
method to obtain a stream of providers that can be inspected and filtered without instantiating them.
As an example, suppose the service is com.example.CodecFactory
, an interface that defines methods for producing encoders and decoders:
package com.example;
public interface CodecFactory {
Encoder getEncoder(String encodingName);
Decoder getDecoder(String encodingName);
}
The following code obtains a service loader for the CodecFactory
service, then uses its iterator (created automatically by the enhanced-for loop) to yield instances of the service providers that are located:
ServiceLoader<CodecFactory> loader = ServiceLoader.load(CodecFactory.class);
for (CodecFactory factory : loader) {
Encoder enc = factory.getEncoder("PNG");
if (enc != null)
... use enc to encode a PNG file
break;
}
If this code resides in a module, then in order to refer to the com.example.CodecFactory
interface, the module declaration would require the module which exports the interface. The module declaration would also specify use of com.example.CodecFactory
:
requires com.example.codec.core;
uses com.example.CodecFactory;
Sometimes an application may wish to inspect a service provider before instantiating it, in order to determine if an instance of that service provider would be useful. For example, a service provider for
CodecFactory
that is capable of producing a "PNG" encoder may be annotated with @PNG
. The following code uses service loader's stream
method to yield instances of Provider<CodecFactory>
in contrast to how the iterator yields instances of CodecFactory
:
ServiceLoader<CodecFactory> loader = ServiceLoader.load(CodecFactory.class);
Set<CodecFactory> pngFactories = loader
.stream() // Note a below
.filter(p -> p.type().isAnnotationPresent(PNG.class)) // Note b
.map(Provider::get) // Note c
.collect(Collectors.toSet());
- A stream of
Provider<CodecFactory>
objects
-
p.type()
yields a Class<CodecFactory>
-
get()
yields an instance of CodecFactory
Designing services
A service is a single type, usually an interface or abstract class. A
concrete class can be used, but this is not recommended. The type may have
any accessibility. The methods of a service are highly domain-specific, so
this API specification cannot give concrete advice about their form or
function. However, there are two general guidelines:
A service should declare as many methods as needed to allow service
providers to communicate their domain-specific properties and other
quality-of-implementation factors. An application which obtains a service
loader for the service may then invoke these methods on each instance of
a service provider, in order to choose the best provider for the
application.
A service should express whether its service providers are intended to be direct implementations of the service or to be an indirection mechanism such as a "proxy" or a "factory". Service providers tend to be indirection mechanisms when domain-specific objects are relatively expensive to instantiate; in this case, the service should be designed so that service providers are abstractions which create the "real" implementation on demand. For example, the CodecFactory
service expresses through its name that its service providers are factories for codecs, rather than codecs themselves, because it may be expensive or complicated to produce certain codecs.
Developing service providers
A service provider is a single type, usually a concrete class. An
interface or abstract class is permitted because it may declare a static
provider method, discussed later. The type must be public and must not be
an inner class.
A service provider and its supporting code may be developed in a module,
which is then deployed on the application module path or in a modular
image. Alternatively, a service provider and its supporting code may be
packaged as a JAR file and deployed on the application class path. The
advantage of developing a service provider in a module is that the provider
can be fully encapsulated to hide all details of its implementation.
An application that obtains a service loader for a given service is indifferent to whether providers of the service are deployed in modules or packaged as JAR files. The application instantiates service providers via the service loader's iterator, or via Provider
objects in the service loader's stream, without knowledge of the service providers' locations.
Deploying service providers as modules
A service provider that is developed in a module must be specified in a
provides directive in the module declaration. The provides directive
specifies both the service and the service provider; this helps to locate the
provider when another module, with a uses directive for the service,
obtains a service loader for the service. It is strongly recommended that the
module does not export the package containing the service provider. There is
no support for a module specifying, in a provides directive, a service
provider in another module.
A service provider that is developed in a module has no control over when
it is instantiated, since that occurs at the behest of the application, but it
does have control over how it is instantiated:
- If the service provider declares a provider method, then the service
loader invokes that method to obtain an instance of the service provider. A
provider method is a public static method named "provider" with no formal
parameters and a return type that is assignable to the service's interface
or class.
In this case, the service provider itself need not be assignable to the
service's interface or class.
- If the service provider does not declare a provider method, then the
service provider is instantiated directly, via its provider constructor. A
provider constructor is a public constructor with no formal parameters.
In this case, the service provider must be assignable to the service's
interface or class
A service provider that is deployed as an automatic module on the application module path must have a provider constructor. There is no support for a provider method in this case.
As an example, suppose a module specifies the following directives:
provides com.example.CodecFactory with com.example.impl.StandardCodecs;
provides com.example.CodecFactory with com.example.impl.ExtendedCodecsFactory;
where
-
com.example.CodecFactory
is the two-method service from earlier.
-
com.example.impl.StandardCodecs
is a public class that implements CodecFactory
and has a public no-args constructor.
-
com.example.impl.ExtendedCodecsFactory
is a public class that does not implement CodecFactory, but it declares a public static no-args method named "provider" with a return type of CodecFactory
.
A service loader will instantiate StandardCodecs
via its constructor, and will instantiate ExtendedCodecsFactory
by invoking its provider
method. The requirement that the provider constructor or provider method is public helps to document the intent that the class (that is, the service provider) will be instantiated by an entity (that is, a service loader) which is outside the class's package.
Deploying service providers on the class path
A service provider that is packaged as a JAR file for the class path is
identified by placing a provider-configuration file in the resource directory META-INF/services
. The name of the provider-configuration file is the fully qualified binary name of the service. The provider-configuration file contains a list of fully qualified binary names of service providers, one per line. For example, suppose the service provider com.example.impl.StandardCodecs
is packaged in a JAR file for the class path. The JAR file will contain a provider-configuration file named:
META-INF/services/com.example.CodecFactory
that contains the line:
com.example.impl.StandardCodecs # Standard codecs
The provider-configuration file must be encoded in UTF-8. Space and tab characters surrounding each service provider's name, as well as blank lines, are ignored. The comment character is '#'
('\u0023'
NUMBER SIGN);
on each line all characters following the first comment character are ignored.
If a service provider class name is listed more than once in a
provider-configuration file then the duplicate is ignored. If a service
provider class is named in more than one configuration file then the duplicate
is ignored.
A service provider that is mentioned in a provider-configuration file may
be located in the same JAR file as the provider-configuration file or in a
different JAR file. The service provider must be visible from the class loader
that is initially queried to locate the provider-configuration file; this is
not necessarily the class loader which ultimately locates the
provider-configuration file.
Timing of provider discovery
Service providers are loaded and instantiated lazily, that is, on demand. A service loader maintains a cache of the providers that have been loaded so far. Each invocation of the iterator
method returns an Iterator
that first yields all of the elements cached from previous iteration, in instantiation order, and then lazily locates and instantiates any remaining providers, adding each one to the cache in turn. Similarly, each invocation of the stream method returns a Stream
that first processes all providers loaded by previous stream operations, in load order, and then lazily locates any remaining providers. Caches are cleared via the
reload
method.
Errors
When using the service loader's iterator
, the hasNext
and next
methods will fail with ServiceConfigurationError
if an error occurs locating, loading or instantiating a service provider. When processing the service loader's stream then ServiceConfigurationError
may be thrown by any method that causes a service provider to be located or loaded.
When loading or instantiating a service provider in a module,
ServiceConfigurationError
can be thrown for the following reasons:
- The service provider cannot be loaded.
- The service provider does not declare a provider method, and either
it is not assignable to the service's interface/class or does not have a
provider constructor.
- The service provider declares a public static no-args method named
"provider" with a return type that is not assignable to the service's
interface or class.
- The service provider class file has more than one public static no-args method named "
provider
".
- The service provider declares a provider method and it fails by returning
null
or throwing an exception.
- The service provider does not declare a provider method, and its
provider constructor fails by throwing an exception.
When reading a provider-configuration file, or loading or instantiating a provider class named in a provider-configuration file, then
ServiceConfigurationError
can be thrown for the following reasons:
- The format of the provider-configuration file violates the format specified above;
- An
IOException
occurs while reading the provider-configuration file;
- A service provider cannot be loaded;
- A service provider is not assignable to the service's interface or
class, or does not define a provider constructor, or cannot be
instantiated.
Security
Service loaders always execute in the security context of the caller
of the iterator or stream methods and may also be restricted by the security
context of the caller that created the service loader.
Trusted system code should typically invoke the methods in this class, and
the methods of the iterators which they return, from within a privileged
security context.
Concurrency
Instances of this class are not safe for use by multiple concurrent
threads.
Null handling
Unless otherwise specified, passing a null
argument to any method in this class will cause a NullPointerException
to be thrown.
Author: Mark Reinhold Type parameters: - <S> –
The type of the service to be loaded by this loader
Since: 1.6 @revised 9 @spec JPMS
/**
* A facility to load implementations of a service.
*
* <p> A <i>service</i> is a well-known interface or class for which zero, one,
* or many service providers exist. A <i>service provider</i> (or just
* <i>provider</i>) is a class that implements or subclasses the well-known
* interface or class. A {@code ServiceLoader} is an object that locates and
* loads service providers deployed in the run time environment at a time of an
* application's choosing. Application code refers only to the service, not to
* service providers, and is assumed to be capable of choosing between multiple
* service providers (based on the functionality they expose through the service),
* and handling the possibility that no service providers are located.
*
* <h2> Obtaining a service loader </h2>
*
* <p> An application obtains a service loader for a given service by invoking
* one of the static {@code load} methods of {@code ServiceLoader}. If the
* application is a module, then its module declaration must have a <i>uses</i>
* directive that specifies the service; this helps to locate providers and ensure
* they will execute reliably. In addition, if the application module does not
* contain the service, then its module declaration must have a <i>requires</i>
* directive that specifies the module which exports the service. It is strongly
* recommended that the application module does <b>not</b> require modules which
* contain providers of the service.
*
* <p> A service loader can be used to locate and instantiate providers of the
* service by means of the {@link #iterator() iterator} method. {@code ServiceLoader}
* also defines the {@link #stream() stream} method to obtain a stream of providers
* that can be inspected and filtered without instantiating them.
*
* <p> As an example, suppose the service is {@code com.example.CodecFactory}, an
* interface that defines methods for producing encoders and decoders:
*
* <pre>{@code
* package com.example;
* public interface CodecFactory {
* Encoder getEncoder(String encodingName);
* Decoder getDecoder(String encodingName);
* }
* }</pre>
*
* <p> The following code obtains a service loader for the {@code CodecFactory}
* service, then uses its iterator (created automatically by the enhanced-for
* loop) to yield instances of the service providers that are located:
*
* <pre>{@code
* ServiceLoader<CodecFactory> loader = ServiceLoader.load(CodecFactory.class);
* for (CodecFactory factory : loader) {
* Encoder enc = factory.getEncoder("PNG");
* if (enc != null)
* ... use enc to encode a PNG file
* break;
* }
* }</pre>
*
* <p> If this code resides in a module, then in order to refer to the
* {@code com.example.CodecFactory} interface, the module declaration would
* require the module which exports the interface. The module declaration would
* also specify use of {@code com.example.CodecFactory}:
* <pre>{@code
* requires com.example.codec.core;
* uses com.example.CodecFactory;
* }</pre>
*
* <p> Sometimes an application may wish to inspect a service provider before
* instantiating it, in order to determine if an instance of that service
* provider would be useful. For example, a service provider for {@code
* CodecFactory} that is capable of producing a "PNG" encoder may be annotated
* with {@code @PNG}. The following code uses service loader's {@code stream}
* method to yield instances of {@code Provider<CodecFactory>} in contrast to
* how the iterator yields instances of {@code CodecFactory}:
* <pre>{@code
* ServiceLoader<CodecFactory> loader = ServiceLoader.load(CodecFactory.class);
* Set<CodecFactory> pngFactories = loader
* .stream() // Note a below
* .filter(p -> p.type().isAnnotationPresent(PNG.class)) // Note b
* .map(Provider::get) // Note c
* .collect(Collectors.toSet());
* }</pre>
* <ol type="a">
* <li> A stream of {@code Provider<CodecFactory>} objects </li>
* <li> {@code p.type()} yields a {@code Class<CodecFactory>} </li>
* <li> {@code get()} yields an instance of {@code CodecFactory} </li>
* </ol>
*
* <h2> Designing services </h2>
*
* <p> A service is a single type, usually an interface or abstract class. A
* concrete class can be used, but this is not recommended. The type may have
* any accessibility. The methods of a service are highly domain-specific, so
* this API specification cannot give concrete advice about their form or
* function. However, there are two general guidelines:
* <ol>
* <li><p> A service should declare as many methods as needed to allow service
* providers to communicate their domain-specific properties and other
* quality-of-implementation factors. An application which obtains a service
* loader for the service may then invoke these methods on each instance of
* a service provider, in order to choose the best provider for the
* application. </p></li>
* <li><p> A service should express whether its service providers are intended
* to be direct implementations of the service or to be an indirection
* mechanism such as a "proxy" or a "factory". Service providers tend to be
* indirection mechanisms when domain-specific objects are relatively
* expensive to instantiate; in this case, the service should be designed
* so that service providers are abstractions which create the "real"
* implementation on demand. For example, the {@code CodecFactory} service
* expresses through its name that its service providers are factories
* for codecs, rather than codecs themselves, because it may be expensive
* or complicated to produce certain codecs. </p></li>
* </ol>
*
* <h2> <a id="developing-service-providers">Developing service providers</a> </h2>
*
* <p> A service provider is a single type, usually a concrete class. An
* interface or abstract class is permitted because it may declare a static
* provider method, discussed later. The type must be public and must not be
* an inner class.
*
* <p> A service provider and its supporting code may be developed in a module,
* which is then deployed on the application module path or in a modular
* image. Alternatively, a service provider and its supporting code may be
* packaged as a JAR file and deployed on the application class path. The
* advantage of developing a service provider in a module is that the provider
* can be fully encapsulated to hide all details of its implementation.
*
* <p> An application that obtains a service loader for a given service is
* indifferent to whether providers of the service are deployed in modules or
* packaged as JAR files. The application instantiates service providers via
* the service loader's iterator, or via {@link Provider Provider} objects in
* the service loader's stream, without knowledge of the service providers'
* locations.
*
* <h2> Deploying service providers as modules </h2>
*
* <p> A service provider that is developed in a module must be specified in a
* <i>provides</i> directive in the module declaration. The provides directive
* specifies both the service and the service provider; this helps to locate the
* provider when another module, with a <i>uses</i> directive for the service,
* obtains a service loader for the service. It is strongly recommended that the
* module does not export the package containing the service provider. There is
* no support for a module specifying, in a <i>provides</i> directive, a service
* provider in another module.
* <p> A service provider that is developed in a module has no control over when
* it is instantiated, since that occurs at the behest of the application, but it
* does have control over how it is instantiated:
*
* <ul>
*
* <li> If the service provider declares a provider method, then the service
* loader invokes that method to obtain an instance of the service provider. A
* provider method is a public static method named "provider" with no formal
* parameters and a return type that is assignable to the service's interface
* or class.
* <p> In this case, the service provider itself need not be assignable to the
* service's interface or class. </li>
*
* <li> If the service provider does not declare a provider method, then the
* service provider is instantiated directly, via its provider constructor. A
* provider constructor is a public constructor with no formal parameters.
* <p> In this case, the service provider must be assignable to the service's
* interface or class </li>
*
* </ul>
*
* <p> A service provider that is deployed as an
* {@linkplain java.lang.module.ModuleDescriptor#isAutomatic automatic module} on
* the application module path must have a provider constructor. There is no
* support for a provider method in this case.
*
* <p> As an example, suppose a module specifies the following directives:
* <pre>{@code
* provides com.example.CodecFactory with com.example.impl.StandardCodecs;
* provides com.example.CodecFactory with com.example.impl.ExtendedCodecsFactory;
* }</pre>
*
* <p> where
*
* <ul>
* <li> {@code com.example.CodecFactory} is the two-method service from
* earlier. </li>
*
* <li> {@code com.example.impl.StandardCodecs} is a public class that implements
* {@code CodecFactory} and has a public no-args constructor. </li>
*
* <li> {@code com.example.impl.ExtendedCodecsFactory} is a public class that
* does not implement CodecFactory, but it declares a public static no-args
* method named "provider" with a return type of {@code CodecFactory}. </li>
* </ul>
*
* <p> A service loader will instantiate {@code StandardCodecs} via its
* constructor, and will instantiate {@code ExtendedCodecsFactory} by invoking
* its {@code provider} method. The requirement that the provider constructor or
* provider method is public helps to document the intent that the class (that is,
* the service provider) will be instantiated by an entity (that is, a service
* loader) which is outside the class's package.
*
* <h2> Deploying service providers on the class path </h2>
*
* A service provider that is packaged as a JAR file for the class path is
* identified by placing a <i>provider-configuration file</i> in the resource
* directory {@code META-INF/services}. The name of the provider-configuration
* file is the fully qualified binary name of the service. The provider-configuration
* file contains a list of fully qualified binary names of service providers, one
* per line.
*
* <p> For example, suppose the service provider
* {@code com.example.impl.StandardCodecs} is packaged in a JAR file for the
* class path. The JAR file will contain a provider-configuration file named:
*
* <blockquote>{@code
* META-INF/services/com.example.CodecFactory
* }</blockquote>
*
* that contains the line:
*
* <blockquote>{@code
* com.example.impl.StandardCodecs # Standard codecs
* }</blockquote>
*
* <p><a id="format">The provider-configuration file must be encoded in UTF-8. </a>
* Space and tab characters surrounding each service provider's name, as well as
* blank lines, are ignored. The comment character is {@code '#'}
* ({@code '\u0023'} <span style="font-size:smaller;">NUMBER SIGN</span>);
* on each line all characters following the first comment character are ignored.
* If a service provider class name is listed more than once in a
* provider-configuration file then the duplicate is ignored. If a service
* provider class is named in more than one configuration file then the duplicate
* is ignored.
*
* <p> A service provider that is mentioned in a provider-configuration file may
* be located in the same JAR file as the provider-configuration file or in a
* different JAR file. The service provider must be visible from the class loader
* that is initially queried to locate the provider-configuration file; this is
* not necessarily the class loader which ultimately locates the
* provider-configuration file.
*
* <h2> Timing of provider discovery </h2>
*
* <p> Service providers are loaded and instantiated lazily, that is, on demand.
* A service loader maintains a cache of the providers that have been loaded so
* far. Each invocation of the {@code iterator} method returns an {@code Iterator}
* that first yields all of the elements cached from previous iteration, in
* instantiation order, and then lazily locates and instantiates any remaining
* providers, adding each one to the cache in turn. Similarly, each invocation
* of the stream method returns a {@code Stream} that first processes all
* providers loaded by previous stream operations, in load order, and then lazily
* locates any remaining providers. Caches are cleared via the {@link #reload
* reload} method.
*
* <h2> <a id="errors">Errors</a> </h2>
*
* <p> When using the service loader's {@code iterator}, the {@link
* Iterator#hasNext() hasNext} and {@link Iterator#next() next} methods will
* fail with {@link ServiceConfigurationError} if an error occurs locating,
* loading or instantiating a service provider. When processing the service
* loader's stream then {@code ServiceConfigurationError} may be thrown by any
* method that causes a service provider to be located or loaded.
*
* <p> When loading or instantiating a service provider in a module, {@code
* ServiceConfigurationError} can be thrown for the following reasons:
*
* <ul>
*
* <li> The service provider cannot be loaded. </li>
*
* <li> The service provider does not declare a provider method, and either
* it is not assignable to the service's interface/class or does not have a
* provider constructor. </li>
*
* <li> The service provider declares a public static no-args method named
* "provider" with a return type that is not assignable to the service's
* interface or class. </li>
*
* <li> The service provider class file has more than one public static
* no-args method named "{@code provider}". </li>
*
* <li> The service provider declares a provider method and it fails by
* returning {@code null} or throwing an exception. </li>
*
* <li> The service provider does not declare a provider method, and its
* provider constructor fails by throwing an exception. </li>
*
* </ul>
*
* <p> When reading a provider-configuration file, or loading or instantiating
* a provider class named in a provider-configuration file, then {@code
* ServiceConfigurationError} can be thrown for the following reasons:
*
* <ul>
*
* <li> The format of the provider-configuration file violates the <a
* href="ServiceLoader.html#format">format</a> specified above; </li>
*
* <li> An {@link IOException IOException} occurs while reading the
* provider-configuration file; </li>
*
* <li> A service provider cannot be loaded; </li>
*
* <li> A service provider is not assignable to the service's interface or
* class, or does not define a provider constructor, or cannot be
* instantiated. </li>
*
* </ul>
*
* <h2> Security </h2>
*
* <p> Service loaders always execute in the security context of the caller
* of the iterator or stream methods and may also be restricted by the security
* context of the caller that created the service loader.
* Trusted system code should typically invoke the methods in this class, and
* the methods of the iterators which they return, from within a privileged
* security context.
*
* <h2> Concurrency </h2>
*
* <p> Instances of this class are not safe for use by multiple concurrent
* threads.
*
* <h3> Null handling </h3>
*
* <p> Unless otherwise specified, passing a {@code null} argument to any
* method in this class will cause a {@link NullPointerException} to be thrown.
*
* @param <S>
* The type of the service to be loaded by this loader
*
* @author Mark Reinhold
* @since 1.6
* @revised 9
* @spec JPMS
*/
public final class ServiceLoader<S>
implements Iterable<S>
{
// The class or interface representing the service being loaded
private final Class<S> service;
// The class of the service type
private final String serviceName;
// The module layer used to locate providers; null when locating
// providers using a class loader
private final ModuleLayer layer;
// The class loader used to locate, load, and instantiate providers;
// null when locating provider using a module layer
private final ClassLoader loader;
// The access control context taken when the ServiceLoader is created
private final AccessControlContext acc;
// The lazy-lookup iterator for iterator operations
private Iterator<Provider<S>> lookupIterator1;
private final List<S> instantiatedProviders = new ArrayList<>();
// The lazy-lookup iterator for stream operations
private Iterator<Provider<S>> lookupIterator2;
private final List<Provider<S>> loadedProviders = new ArrayList<>();
private boolean loadedAllProviders; // true when all providers loaded
// Incremented when reload is called
private int reloadCount;
private static JavaLangAccess LANG_ACCESS;
static {
LANG_ACCESS = SharedSecrets.getJavaLangAccess();
}
Represents a service provider located by ServiceLoader
. When using a loader's stream()
method then the elements are of type Provider
. This allows processing to select or filter on the provider class without instantiating the provider.
Type parameters: - <S> – The service type
Since: 9 @spec JPMS
/**
* 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
* @spec JPMS
*/
public static interface Provider<S> extends Supplier<S> {
Returns the provider type. There is no guarantee that this type is accessible or that it has a public no-args constructor. The get()
method should be used to obtain the provider instance. When a module declares that the provider class is created by a provider factory then this method returns the return type of its public static "provider()
" method.
Returns: The provider type
/**
* Returns the provider type. There is no guarantee that this type is
* accessible or that it has a public no-args constructor. The {@link
* #get() get()} method should be used to obtain the provider instance.
*
* <p> When a module declares that the provider class is created by a
* provider factory then this method returns the return type of its
* public static "{@code provider()}" method.
*
* @return The provider type
*/
Class<? extends S> type();
Returns an instance of the provider.
Throws: - ServiceConfigurationError – If the service provider cannot be instantiated, or in the case of a provider factory, the public static "
provider()
" method returns null
or throws an error or exception. The ServiceConfigurationError
will carry an appropriate cause where possible.
Returns: An instance of the provider.
/**
* Returns an instance of the provider.
*
* @return An instance of the provider.
*
* @throws ServiceConfigurationError
* If the service provider cannot be instantiated, or in the
* case of a provider factory, the public static
* "{@code provider()}" method returns {@code null} or throws
* an error or exception. The {@code ServiceConfigurationError}
* will carry an appropriate cause where possible.
*/
@Override S get();
}
Initializes a new instance of this class for locating service providers
in a module layer.
Throws: - ServiceConfigurationError – If
svc
is not accessible to caller
or the caller module does not use the service type.
/**
* Initializes a new instance of this class for locating service providers
* in a module layer.
*
* @throws ServiceConfigurationError
* If {@code svc} is not accessible to {@code caller} or the caller
* module does not use the service type.
*/
private ServiceLoader(Class<?> caller, ModuleLayer layer, Class<S> svc) {
Objects.requireNonNull(caller);
Objects.requireNonNull(layer);
Objects.requireNonNull(svc);
checkCaller(caller, svc);
this.service = svc;
this.serviceName = svc.getName();
this.layer = layer;
this.loader = null;
this.acc = (System.getSecurityManager() != null)
? AccessController.getContext()
: null;
}
Initializes a new instance of this class for locating service providers
via a class loader.
Throws: - ServiceConfigurationError – If
svc
is not accessible to caller
or the caller module does not use the service type.
/**
* Initializes a new instance of this class for locating service providers
* via a class loader.
*
* @throws ServiceConfigurationError
* If {@code svc} is not accessible to {@code caller} or the caller
* module does not use the service type.
*/
private ServiceLoader(Class<?> caller, Class<S> svc, ClassLoader cl) {
Objects.requireNonNull(svc);
if (VM.isBooted()) {
checkCaller(caller, svc);
if (cl == null) {
cl = ClassLoader.getSystemClassLoader();
}
} else {
// if we get here then it means that ServiceLoader is being used
// before the VM initialization has completed. At this point then
// only code in the java.base should be executing.
Module callerModule = caller.getModule();
Module base = Object.class.getModule();
Module svcModule = svc.getModule();
if (callerModule != base || svcModule != base) {
fail(svc, "not accessible to " + callerModule + " during VM init");
}
// restricted to boot loader during startup
cl = null;
}
this.service = svc;
this.serviceName = svc.getName();
this.layer = null;
this.loader = cl;
this.acc = (System.getSecurityManager() != null)
? AccessController.getContext()
: null;
}
Initializes a new instance of this class for locating service providers
via a class loader.
Throws: - ServiceConfigurationError –
If the caller module does not use the service type.
API Note: For use by ResourceBundle
/**
* Initializes a new instance of this class for locating service providers
* via a class loader.
*
* @apiNote For use by ResourceBundle
*
* @throws ServiceConfigurationError
* If the caller module does not use the service type.
*/
private ServiceLoader(Module callerModule, Class<S> svc, ClassLoader cl) {
if (!callerModule.canUse(svc)) {
fail(svc, callerModule + " does not declare `uses`");
}
this.service = Objects.requireNonNull(svc);
this.serviceName = svc.getName();
this.layer = null;
this.loader = cl;
this.acc = (System.getSecurityManager() != null)
? AccessController.getContext()
: null;
}
Checks that the given service type is accessible to types in the given
module, and check that the module declares that it uses the service type.
/**
* Checks that the given service type is accessible to types in the given
* module, and check that the module declares that it uses the service type.
*/
private static void checkCaller(Class<?> caller, Class<?> svc) {
if (caller == null) {
fail(svc, "no caller to check if it declares `uses`");
}
// Check access to the service type
Module callerModule = caller.getModule();
int mods = svc.getModifiers();
if (!Reflection.verifyMemberAccess(caller, svc, null, mods)) {
fail(svc, "service type not accessible to " + callerModule);
}
// If the caller is in a named module then it should "uses" the
// service type
if (!callerModule.canUse(svc)) {
fail(svc, callerModule + " does not declare `uses`");
}
}
private static void fail(Class<?> service, String msg, Throwable cause)
throws ServiceConfigurationError
{
throw new ServiceConfigurationError(service.getName() + ": " + msg,
cause);
}
private static void fail(Class<?> service, String msg)
throws ServiceConfigurationError
{
throw new ServiceConfigurationError(service.getName() + ": " + msg);
}
private static void fail(Class<?> service, URL u, int line, String msg)
throws ServiceConfigurationError
{
fail(service, u + ":" + line + ": " + msg);
}
Returns true
if the provider is in an explicit module /**
* Returns {@code true} if the provider is in an explicit module
*/
private boolean inExplicitModule(Class<?> clazz) {
Module module = clazz.getModule();
return module.isNamed() && !module.getDescriptor().isAutomatic();
}
Returns the public static "provider" method if found.
Throws: - ServiceConfigurationError – if there is an error finding the
provider method or there is more than one public static
provider method
/**
* Returns the public static "provider" method if found.
*
* @throws ServiceConfigurationError if there is an error finding the
* provider method or there is more than one public static
* provider method
*/
private Method findStaticProviderMethod(Class<?> clazz) {
List<Method> methods = null;
try {
methods = LANG_ACCESS.getDeclaredPublicMethods(clazz, "provider");
} catch (Throwable x) {
fail(service, "Unable to get public provider() method", x);
}
if (methods.isEmpty()) {
// does not declare a public provider method
return null;
}
// locate the static methods, can be at most one
Method result = null;
for (Method method : methods) {
int mods = method.getModifiers();
assert Modifier.isPublic(mods);
if (Modifier.isStatic(mods)) {
if (result != null) {
fail(service, clazz + " declares more than one"
+ " public static provider() method");
}
result = method;
}
}
if (result != null) {
Method m = result;
PrivilegedAction<Void> pa = () -> {
m.setAccessible(true);
return null;
};
AccessController.doPrivileged(pa);
}
return result;
}
Returns the public no-arg constructor of a class.
Throws: - ServiceConfigurationError – if the class does not have
public no-arg constructor
/**
* Returns the public no-arg constructor of a class.
*
* @throws ServiceConfigurationError if the class does not have
* public no-arg constructor
*/
private Constructor<?> getConstructor(Class<?> clazz) {
PrivilegedExceptionAction<Constructor<?>> pa
= new PrivilegedExceptionAction<>() {
@Override
public Constructor<?> run() throws Exception {
Constructor<?> ctor = clazz.getConstructor();
if (inExplicitModule(clazz))
ctor.setAccessible(true);
return ctor;
}
};
Constructor<?> ctor = null;
try {
ctor = AccessController.doPrivileged(pa);
} catch (Throwable x) {
if (x instanceof PrivilegedActionException)
x = x.getCause();
String cn = clazz.getName();
fail(service, cn + " Unable to get public no-arg constructor", x);
}
return ctor;
}
A Provider implementation that supports invoking, with reduced
permissions, the static factory to obtain the provider or the
provider's no-arg constructor.
/**
* A Provider implementation that supports invoking, with reduced
* permissions, the static factory to obtain the provider or the
* provider's no-arg constructor.
*/
private static class ProviderImpl<S> implements Provider<S> {
final Class<S> service;
final Class<? extends S> type;
final Method factoryMethod; // factory method or null
final Constructor<? extends S> ctor; // public no-args constructor or null
final AccessControlContext acc;
ProviderImpl(Class<S> service,
Class<? extends S> type,
Method factoryMethod,
AccessControlContext acc) {
this.service = service;
this.type = type;
this.factoryMethod = factoryMethod;
this.ctor = null;
this.acc = acc;
}
ProviderImpl(Class<S> service,
Class<? extends S> type,
Constructor<? extends S> ctor,
AccessControlContext acc) {
this.service = service;
this.type = type;
this.factoryMethod = null;
this.ctor = ctor;
this.acc = acc;
}
@Override
public Class<? extends S> type() {
return type;
}
@Override
public S get() {
if (factoryMethod != null) {
return invokeFactoryMethod();
} else {
return newInstance();
}
}
Invokes the provider's "provider" method to instantiate a provider.
When running with a security manager then the method runs with
permissions that are restricted by the security context of whatever
created this loader.
/**
* Invokes the provider's "provider" method to instantiate a provider.
* When running with a security manager then the method runs with
* permissions that are restricted by the security context of whatever
* created this loader.
*/
private S invokeFactoryMethod() {
Object result = null;
Throwable exc = null;
if (acc == null) {
try {
result = factoryMethod.invoke(null);
} catch (Throwable x) {
exc = x;
}
} else {
PrivilegedExceptionAction<?> pa = new PrivilegedExceptionAction<>() {
@Override
public Object run() throws Exception {
return factoryMethod.invoke(null);
}
};
// invoke factory method with permissions restricted by acc
try {
result = AccessController.doPrivileged(pa, acc);
} catch (Throwable x) {
if (x instanceof PrivilegedActionException)
x = x.getCause();
exc = x;
}
}
if (exc != null) {
if (exc instanceof InvocationTargetException)
exc = exc.getCause();
fail(service, factoryMethod + " failed", exc);
}
if (result == null) {
fail(service, factoryMethod + " returned null");
}
@SuppressWarnings("unchecked")
S p = (S) result;
return p;
}
Invokes Constructor::newInstance to instantiate a provider. When running
with a security manager then the constructor runs with permissions that
are restricted by the security context of whatever created this loader.
/**
* Invokes Constructor::newInstance to instantiate a provider. When running
* with a security manager then the constructor runs with permissions that
* are restricted by the security context of whatever created this loader.
*/
private S newInstance() {
S p = null;
Throwable exc = null;
if (acc == null) {
try {
p = ctor.newInstance();
} catch (Throwable x) {
exc = x;
}
} else {
PrivilegedExceptionAction<S> pa = new PrivilegedExceptionAction<>() {
@Override
public S run() throws Exception {
return ctor.newInstance();
}
};
// invoke constructor with permissions restricted by acc
try {
p = AccessController.doPrivileged(pa, acc);
} catch (Throwable x) {
if (x instanceof PrivilegedActionException)
x = x.getCause();
exc = x;
}
}
if (exc != null) {
if (exc instanceof InvocationTargetException)
exc = exc.getCause();
String cn = ctor.getDeclaringClass().getName();
fail(service,
"Provider " + cn + " could not be instantiated", exc);
}
return p;
}
// For now, equals/hashCode uses the access control context to ensure
// that two Providers created with different contexts are not equal
// when running with a security manager.
@Override
public int hashCode() {
return Objects.hash(service, type, acc);
}
@Override
public boolean equals(Object ob) {
if (!(ob instanceof ProviderImpl))
return false;
@SuppressWarnings("unchecked")
ProviderImpl<?> that = (ProviderImpl<?>)ob;
return this.service == that.service
&& this.type == that.type
&& Objects.equals(this.acc, that.acc);
}
}
Loads a service provider in a module. Returns null
if the service provider's module doesn't read the module with the service type. Throws: - ServiceConfigurationError – if the class cannot be loaded or
isn't the expected sub-type (or doesn't define a provider
factory method that returns the expected type)
/**
* Loads a service provider in a module.
*
* Returns {@code null} if the service provider's module doesn't read
* the module with the service type.
*
* @throws ServiceConfigurationError if the class cannot be loaded or
* isn't the expected sub-type (or doesn't define a provider
* factory method that returns the expected type)
*/
private Provider<S> loadProvider(ServiceProvider provider) {
Module module = provider.module();
if (!module.canRead(service.getModule())) {
// module does not read the module with the service type
return null;
}
String cn = provider.providerName();
Class<?> clazz = null;
if (acc == null) {
try {
clazz = Class.forName(module, cn);
} catch (LinkageError e) {
fail(service, "Unable to load " + cn, e);
}
} else {
PrivilegedExceptionAction<Class<?>> pa = () -> Class.forName(module, cn);
try {
clazz = AccessController.doPrivileged(pa);
} catch (Throwable x) {
if (x instanceof PrivilegedActionException)
x = x.getCause();
fail(service, "Unable to load " + cn, x);
return null;
}
}
if (clazz == null) {
fail(service, "Provider " + cn + " not found");
}
int mods = clazz.getModifiers();
if (!Modifier.isPublic(mods)) {
fail(service, clazz + " is not public");
}
// if provider in explicit module then check for static factory method
if (inExplicitModule(clazz)) {
Method factoryMethod = findStaticProviderMethod(clazz);
if (factoryMethod != null) {
Class<?> returnType = factoryMethod.getReturnType();
if (!service.isAssignableFrom(returnType)) {
fail(service, factoryMethod + " return type not a subtype");
}
@SuppressWarnings("unchecked")
Class<? extends S> type = (Class<? extends S>) returnType;
return new ProviderImpl<S>(service, type, factoryMethod, acc);
}
}
// no factory method so must be a subtype
if (!service.isAssignableFrom(clazz)) {
fail(service, clazz.getName() + " not a subtype");
}
@SuppressWarnings("unchecked")
Class<? extends S> type = (Class<? extends S>) clazz;
@SuppressWarnings("unchecked")
Constructor<? extends S> ctor = (Constructor<? extends S> ) getConstructor(clazz);
return new ProviderImpl<S>(service, type, ctor, acc);
}
Implements lazy service provider lookup of service providers that
are provided by modules in a module layer (or parent layers)
/**
* Implements lazy service provider lookup of service providers that
* are provided by modules in a module layer (or parent layers)
*/
private final class LayerLookupIterator<T>
implements Iterator<Provider<T>>
{
Deque<ModuleLayer> stack = new ArrayDeque<>();
Set<ModuleLayer> visited = new HashSet<>();
Iterator<ServiceProvider> iterator;
Provider<T> nextProvider;
ServiceConfigurationError nextError;
LayerLookupIterator() {
visited.add(layer);
stack.push(layer);
}
private Iterator<ServiceProvider> providers(ModuleLayer layer) {
ServicesCatalog catalog = LANG_ACCESS.getServicesCatalog(layer);
return catalog.findServices(serviceName).iterator();
}
@Override
public boolean hasNext() {
while (nextProvider == null && nextError == null) {
// get next provider to load
while (iterator == null || !iterator.hasNext()) {
// next layer (DFS order)
if (stack.isEmpty())
return false;
ModuleLayer layer = stack.pop();
List<ModuleLayer> parents = layer.parents();
for (int i = parents.size() - 1; i >= 0; i--) {
ModuleLayer parent = parents.get(i);
if (visited.add(parent)) {
stack.push(parent);
}
}
iterator = providers(layer);
}
// attempt to load provider
ServiceProvider provider = iterator.next();
try {
@SuppressWarnings("unchecked")
Provider<T> next = (Provider<T>) loadProvider(provider);
nextProvider = next;
} catch (ServiceConfigurationError e) {
nextError = e;
}
}
return true;
}
@Override
public Provider<T> next() {
if (!hasNext())
throw new NoSuchElementException();
Provider<T> provider = nextProvider;
if (provider != null) {
nextProvider = null;
return provider;
} else {
ServiceConfigurationError e = nextError;
assert e != null;
nextError = null;
throw e;
}
}
}
Implements lazy service provider lookup of service providers that
are provided by modules defined to a class loader or to modules in
layers with a module defined to the class loader.
/**
* Implements lazy service provider lookup of service providers that
* are provided by modules defined to a class loader or to modules in
* layers with a module defined to the class loader.
*/
private final class ModuleServicesLookupIterator<T>
implements Iterator<Provider<T>>
{
ClassLoader currentLoader;
Iterator<ServiceProvider> iterator;
Provider<T> nextProvider;
ServiceConfigurationError nextError;
ModuleServicesLookupIterator() {
this.currentLoader = loader;
this.iterator = iteratorFor(loader);
}
Returns iterator to iterate over the implementations of
service
in the given layer. /**
* Returns iterator to iterate over the implementations of {@code
* service} in the given layer.
*/
private List<ServiceProvider> providers(ModuleLayer layer) {
ServicesCatalog catalog = LANG_ACCESS.getServicesCatalog(layer);
return catalog.findServices(serviceName);
}
Returns the class loader that a module is defined to
/**
* Returns the class loader that a module is defined to
*/
private ClassLoader loaderFor(Module module) {
SecurityManager sm = System.getSecurityManager();
if (sm == null) {
return module.getClassLoader();
} else {
PrivilegedAction<ClassLoader> pa = module::getClassLoader;
return AccessController.doPrivileged(pa);
}
}
Returns an iterator to iterate over the implementations of
service
in modules defined to the given class loader or in custom layers with a module defined to this class loader. /**
* Returns an iterator to iterate over the implementations of {@code
* service} in modules defined to the given class loader or in custom
* layers with a module defined to this class loader.
*/
private Iterator<ServiceProvider> iteratorFor(ClassLoader loader) {
// modules defined to the class loader
ServicesCatalog catalog;
if (loader == null) {
catalog = BootLoader.getServicesCatalog();
} else {
catalog = ServicesCatalog.getServicesCatalogOrNull(loader);
}
List<ServiceProvider> providers;
if (catalog == null) {
providers = List.of();
} else {
providers = catalog.findServices(serviceName);
}
// modules in layers that define modules to the class loader
ClassLoader platformClassLoader = ClassLoaders.platformClassLoader();
if (loader == null || loader == platformClassLoader) {
return providers.iterator();
} else {
List<ServiceProvider> allProviders = new ArrayList<>(providers);
Iterator<ModuleLayer> iterator = LANG_ACCESS.layers(loader).iterator();
while (iterator.hasNext()) {
ModuleLayer layer = iterator.next();
for (ServiceProvider sp : providers(layer)) {
ClassLoader l = loaderFor(sp.module());
if (l != null && l != platformClassLoader) {
allProviders.add(sp);
}
}
}
return allProviders.iterator();
}
}
@Override
public boolean hasNext() {
while (nextProvider == null && nextError == null) {
// get next provider to load
while (!iterator.hasNext()) {
if (currentLoader == null) {
return false;
} else {
currentLoader = currentLoader.getParent();
iterator = iteratorFor(currentLoader);
}
}
// attempt to load provider
ServiceProvider provider = iterator.next();
try {
@SuppressWarnings("unchecked")
Provider<T> next = (Provider<T>) loadProvider(provider);
nextProvider = next;
} catch (ServiceConfigurationError e) {
nextError = e;
}
}
return true;
}
@Override
public Provider<T> next() {
if (!hasNext())
throw new NoSuchElementException();
Provider<T> provider = nextProvider;
if (provider != null) {
nextProvider = null;
return provider;
} else {
ServiceConfigurationError e = nextError;
assert e != null;
nextError = null;
throw e;
}
}
}
Implements lazy service provider lookup where the service providers are
configured via service configuration files. Service providers in named
modules are silently ignored by this lookup iterator.
/**
* Implements lazy service provider lookup where the service providers are
* configured via service configuration files. Service providers in named
* modules are silently ignored by this lookup iterator.
*/
private final class LazyClassPathLookupIterator<T>
implements Iterator<Provider<T>>
{
static final String PREFIX = "META-INF/services/";
Set<String> providerNames = new HashSet<>(); // to avoid duplicates
Enumeration<URL> configs;
Iterator<String> pending;
Provider<T> nextProvider;
ServiceConfigurationError nextError;
LazyClassPathLookupIterator() { }
Parse a single line from the given configuration file, adding the
name on the line to set of names if not already seen.
/**
* Parse a single line from the given configuration file, adding the
* name on the line to set of names if not already seen.
*/
private int parseLine(URL u, BufferedReader r, int lc, Set<String> names)
throws IOException
{
String ln = r.readLine();
if (ln == null) {
return -1;
}
int ci = ln.indexOf('#');
if (ci >= 0) ln = ln.substring(0, ci);
ln = ln.trim();
int n = ln.length();
if (n != 0) {
if ((ln.indexOf(' ') >= 0) || (ln.indexOf('\t') >= 0))
fail(service, u, lc, "Illegal configuration-file syntax");
int cp = ln.codePointAt(0);
if (!Character.isJavaIdentifierStart(cp))
fail(service, u, lc, "Illegal provider-class name: " + ln);
int start = Character.charCount(cp);
for (int i = start; i < n; i += Character.charCount(cp)) {
cp = ln.codePointAt(i);
if (!Character.isJavaIdentifierPart(cp) && (cp != '.'))
fail(service, u, lc, "Illegal provider-class name: " + ln);
}
if (providerNames.add(ln)) {
names.add(ln);
}
}
return lc + 1;
}
Parse the content of the given URL as a provider-configuration file.
/**
* Parse the content of the given URL as a provider-configuration file.
*/
private Iterator<String> parse(URL u) {
Set<String> names = new LinkedHashSet<>(); // preserve insertion order
try {
URLConnection uc = u.openConnection();
uc.setUseCaches(false);
try (InputStream in = uc.getInputStream();
BufferedReader r
= new BufferedReader(new InputStreamReader(in, UTF_8.INSTANCE)))
{
int lc = 1;
while ((lc = parseLine(u, r, lc, names)) >= 0);
}
} catch (IOException x) {
fail(service, "Error accessing configuration file", x);
}
return names.iterator();
}
Loads and returns the next provider class.
/**
* Loads and returns the next provider class.
*/
private Class<?> nextProviderClass() {
if (configs == null) {
try {
String fullName = PREFIX + service.getName();
if (loader == null) {
configs = ClassLoader.getSystemResources(fullName);
} else if (loader == ClassLoaders.platformClassLoader()) {
// The platform classloader doesn't have a class path,
// but the boot loader might.
if (BootLoader.hasClassPath()) {
configs = BootLoader.findResources(fullName);
} else {
configs = Collections.emptyEnumeration();
}
} else {
configs = loader.getResources(fullName);
}
} catch (IOException x) {
fail(service, "Error locating configuration files", x);
}
}
while ((pending == null) || !pending.hasNext()) {
if (!configs.hasMoreElements()) {
return null;
}
pending = parse(configs.nextElement());
}
String cn = pending.next();
try {
return Class.forName(cn, false, loader);
} catch (ClassNotFoundException x) {
fail(service, "Provider " + cn + " not found");
return null;
}
}
@SuppressWarnings("unchecked")
private boolean hasNextService() {
while (nextProvider == null && nextError == null) {
try {
Class<?> clazz = nextProviderClass();
if (clazz == null)
return false;
if (clazz.getModule().isNamed()) {
// ignore class if in named module
continue;
}
if (service.isAssignableFrom(clazz)) {
Class<? extends S> type = (Class<? extends S>) clazz;
Constructor<? extends S> ctor
= (Constructor<? extends S>)getConstructor(clazz);
ProviderImpl<S> p = new ProviderImpl<S>(service, type, ctor, acc);
nextProvider = (ProviderImpl<T>) p;
} else {
fail(service, clazz.getName() + " not a subtype");
}
} catch (ServiceConfigurationError e) {
nextError = e;
}
}
return true;
}
private Provider<T> nextService() {
if (!hasNextService())
throw new NoSuchElementException();
Provider<T> provider = nextProvider;
if (provider != null) {
nextProvider = null;
return provider;
} else {
ServiceConfigurationError e = nextError;
assert e != null;
nextError = null;
throw e;
}
}
@Override
public boolean hasNext() {
if (acc == null) {
return hasNextService();
} else {
PrivilegedAction<Boolean> action = new PrivilegedAction<>() {
public Boolean run() { return hasNextService(); }
};
return AccessController.doPrivileged(action, acc);
}
}
@Override
public Provider<T> next() {
if (acc == null) {
return nextService();
} else {
PrivilegedAction<Provider<T>> action = new PrivilegedAction<>() {
public Provider<T> run() { return nextService(); }
};
return AccessController.doPrivileged(action, acc);
}
}
}
Returns a new lookup iterator.
/**
* Returns a new lookup iterator.
*/
private Iterator<Provider<S>> newLookupIterator() {
assert layer == null || loader == null;
if (layer != null) {
return new LayerLookupIterator<>();
} else {
Iterator<Provider<S>> first = new ModuleServicesLookupIterator<>();
Iterator<Provider<S>> second = new LazyClassPathLookupIterator<>();
return new Iterator<Provider<S>>() {
@Override
public boolean hasNext() {
return (first.hasNext() || second.hasNext());
}
@Override
public Provider<S> next() {
if (first.hasNext()) {
return first.next();
} else if (second.hasNext()) {
return second.next();
} else {
throw new NoSuchElementException();
}
}
};
}
}
Returns an iterator to lazily load and instantiate the available
providers of this loader's service.
To achieve laziness the actual work of locating and instantiating providers is done by the iterator itself. Its
hasNext
and next
methods can therefore throw a ServiceConfigurationError
for any of the reasons specified in the Errors section above. To write robust code it is only necessary to catch ServiceConfigurationError
when using the iterator. If an error is thrown then subsequent invocations of the iterator will make a best effort to locate and instantiate the next available provider, but in general such recovery cannot be guaranteed.
Caching: The iterator returned by this method first yields all of the elements of the provider cache, in the order that they were loaded. It then lazily loads and instantiates any remaining service providers, adding each one to the cache in turn. If this loader's provider caches are cleared by invoking the reload
method then existing iterators for this service loader should be discarded. The hasNext
and next
methods of the iterator throw ConcurrentModificationException
if used after the provider cache has been cleared.
The iterator returned by this method does not support removal. Invoking its remove
method will cause an UnsupportedOperationException
to be thrown.
API Note: Throwing an error in these cases may seem extreme. The rationale
for this behavior is that a malformed provider-configuration file, like a
malformed class file, indicates a serious problem with the way the Java
virtual machine is configured or is being used. As such it is preferable
to throw an error rather than try to recover or, even worse, fail silently. Returns: An iterator that lazily loads providers for this loader's
service @revised 9 @spec JPMS
/**
* Returns an iterator to lazily load and instantiate the available
* providers of this loader's service.
*
* <p> To achieve laziness the actual work of locating and instantiating
* providers is done by the iterator itself. Its {@link Iterator#hasNext
* hasNext} and {@link Iterator#next next} methods can therefore throw a
* {@link ServiceConfigurationError} for any of the reasons specified in
* the <a href="#errors">Errors</a> section above. To write robust code it
* is only necessary to catch {@code ServiceConfigurationError} when using
* the iterator. If an error is thrown then subsequent invocations of the
* iterator will make a best effort to locate and instantiate the next
* available provider, but in general such recovery cannot be guaranteed.
*
* <p> Caching: The iterator returned by this method first yields all of
* the elements of the provider cache, in the order that they were loaded.
* It then lazily loads and instantiates any remaining service providers,
* adding each one to the cache in turn. If this loader's provider caches are
* cleared by invoking the {@link #reload() reload} method then existing
* iterators for this service loader should be discarded.
* The {@code hasNext} and {@code next} methods of the iterator throw {@link
* java.util.ConcurrentModificationException ConcurrentModificationException}
* if used after the provider cache has been cleared.
*
* <p> The iterator returned by this method does not support removal.
* Invoking its {@link java.util.Iterator#remove() remove} method will
* cause an {@link UnsupportedOperationException} to be thrown.
*
* @apiNote Throwing an error in these cases may seem extreme. The rationale
* for this behavior is that a malformed provider-configuration file, like a
* malformed class file, indicates a serious problem with the way the Java
* virtual machine is configured or is being used. As such it is preferable
* to throw an error rather than try to recover or, even worse, fail silently.
*
* @return An iterator that lazily loads providers for this loader's
* service
*
* @revised 9
* @spec JPMS
*/
public Iterator<S> iterator() {
// create lookup iterator if needed
if (lookupIterator1 == null) {
lookupIterator1 = newLookupIterator();
}
return new Iterator<S>() {
// record reload count
final int expectedReloadCount = ServiceLoader.this.reloadCount;
// index into the cached providers list
int index;
Throws ConcurrentModificationException if the list of cached
providers has been cleared by reload.
/**
* Throws ConcurrentModificationException if the list of cached
* providers has been cleared by reload.
*/
private void checkReloadCount() {
if (ServiceLoader.this.reloadCount != expectedReloadCount)
throw new ConcurrentModificationException();
}
@Override
public boolean hasNext() {
checkReloadCount();
if (index < instantiatedProviders.size())
return true;
return lookupIterator1.hasNext();
}
@Override
public S next() {
checkReloadCount();
S next;
if (index < instantiatedProviders.size()) {
next = instantiatedProviders.get(index);
} else {
next = lookupIterator1.next().get();
instantiatedProviders.add(next);
}
index++;
return next;
}
};
}
Returns a stream to lazily load available providers of this loader's service. The stream elements are of type Provider
, the Provider
's get
method must be invoked to get or instantiate the provider. To achieve laziness the actual work of locating providers is done
when processing the stream. If a service provider cannot be loaded for any
of the reasons specified in the Errors section above then ServiceConfigurationError
is thrown by whatever method caused the service provider to be loaded.
Caching: 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 service providers. If this loader's provider caches are cleared by invoking the reload
method then existing streams for this service loader should be discarded. The returned stream's source spliterator
is fail-fast and will throw ConcurrentModificationException
if the provider cache has been cleared.
The following examples demonstrate usage. The first example creates a stream of CodecFactory
objects, the second example is the same except that it sorts the providers by provider class name (and so locate all providers).
Stream<CodecFactory> providers = ServiceLoader.load(CodecFactory.class)
.stream()
.map(Provider::get);
Stream<CodecFactory> providers = ServiceLoader.load(CodecFactory.class)
.stream()
.sorted(Comparator.comparing(p -> p.type().getName()))
.map(Provider::get);
Returns: A stream that lazily loads providers for this loader's service Since: 9 @spec JPMS
/**
* Returns a stream to lazily load 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> To achieve laziness the actual work of locating providers is done
* when processing the stream. If a service provider cannot be loaded for any
* of the reasons specified in the <a href="#errors">Errors</a> section
* above then {@link ServiceConfigurationError} is thrown by whatever method
* caused the service provider to be loaded. </p>
*
* <p> Caching: 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 service providers. 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. The returned
* stream's source {@link Spliterator spliterator} is <em>fail-fast</em> and
* will throw {@link ConcurrentModificationException} if the provider cache
* has been cleared. </p>
*
* <p> The following examples demonstrate usage. The first example creates
* a stream of {@code CodecFactory} objects, the second example is the same
* except that it sorts the providers by provider class name (and so locate
* all providers).
* <pre>{@code
* Stream<CodecFactory> providers = ServiceLoader.load(CodecFactory.class)
* .stream()
* .map(Provider::get);
*
* Stream<CodecFactory> providers = ServiceLoader.load(CodecFactory.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
* @spec JPMS
*/
public Stream<Provider<S>> stream() {
// use cached providers as the source when all providers loaded
if (loadedAllProviders) {
return loadedProviders.stream();
}
// create lookup iterator if needed
if (lookupIterator2 == null) {
lookupIterator2 = newLookupIterator();
}
// use lookup iterator and cached providers as source
Spliterator<Provider<S>> s = new ProviderSpliterator<>(lookupIterator2);
return StreamSupport.stream(s, false);
}
private class ProviderSpliterator<T> implements Spliterator<Provider<T>> {
final int expectedReloadCount = ServiceLoader.this.reloadCount;
final Iterator<Provider<T>> iterator;
int index;
ProviderSpliterator(Iterator<Provider<T>> iterator) {
this.iterator = iterator;
}
@Override
public Spliterator<Provider<T>> trySplit() {
return null;
}
@Override
@SuppressWarnings("unchecked")
public boolean tryAdvance(Consumer<? super Provider<T>> action) {
if (ServiceLoader.this.reloadCount != expectedReloadCount)
throw new ConcurrentModificationException();
Provider<T> next = null;
if (index < loadedProviders.size()) {
next = (Provider<T>) loadedProviders.get(index++);
} else if (iterator.hasNext()) {
next = iterator.next();
loadedProviders.add((Provider<S>)next);
index++;
} else {
loadedAllProviders = true;
}
if (next != null) {
action.accept(next);
return true;
} else {
return false;
}
}
@Override
public int characteristics() {
// not IMMUTABLE as structural interference possible
// not NOTNULL so that the characteristics are a subset of the
// characteristics when all Providers have been located.
return Spliterator.ORDERED;
}
@Override
public long estimateSize() {
return Long.MAX_VALUE;
}
}
Creates a new service loader for the given service type, class
loader, and caller.
Params: - service –
The interface or abstract class representing the service
- loader – The class loader to be used to load provider-configuration files and provider classes, or
null
if the system class loader (or, failing that, the bootstrap class loader) is to be used - callerModule –
The caller's module for which a new service loader is created
Type parameters: - <S> – the class of the service type
Returns: A new service loader
/**
* Creates a new service loader for the given service type, class
* loader, and caller.
*
* @param <S> the class of the service type
*
* @param service
* The interface or abstract class representing the service
*
* @param loader
* The class loader to be used to load provider-configuration files
* and provider classes, or {@code null} if the system class
* loader (or, failing that, the bootstrap class loader) is to be
* used
*
* @param callerModule
* The caller's module for which a new service loader is created
*
* @return A new service loader
*/
static <S> ServiceLoader<S> load(Class<S> service,
ClassLoader loader,
Module callerModule)
{
return new ServiceLoader<>(callerModule, service, loader);
}
Creates a new service loader for the given service. The service loader uses the given class loader as the starting point to locate service providers for the service. The service loader's
iterator
and stream
locate providers in both named and unnamed modules, as follows:
-
Step 1: Locate providers in named modules.
Service providers are located in all named modules of the class
loader or to any class loader reachable via parent delegation.
In addition, if the class loader is not the bootstrap or platform class loader, then service providers may be located in the named modules of other class loaders. Specifically, if the class loader, or any class loader reachable via parent delegation, has a module in a module
layer, then service providers in all modules in the module layer are located.
For example, suppose there is a module layer where each module is in its own class loader (see
defineModulesWithManyLoaders
). If this ServiceLoader.load
method is invoked to locate providers using any of the class loaders created for the module layer, then it will locate all of the providers in the module layer, irrespective of their defining class loader.
Ordering: The service loader will first locate any service providers
in modules defined to the class loader, then its parent class loader,
its parent parent, and so on to the bootstrap class loader. If a class
loader has modules in a module layer then all providers in that module
layer are located (irrespective of their class loader) before the
providers in the parent class loader are located. The ordering of
modules in same class loader, or the ordering of modules in a module
layer, is not defined.
If a module declares more than one provider then the providers are located in the order that its module descriptor lists the
providers. Providers added dynamically by instrumentation agents (see redefineModule
) are always located after providers declared by the module.
-
Step 2: Locate providers in unnamed modules.
Service providers in unnamed modules are located if their class names are listed in provider-configuration files located by the class loader's getResources
method.
The ordering is based on the order that the class loader's
getResources
method finds the service configuration files and within that, the order that the class names are listed in the file.
In a provider-configuration file, any mention of a service provider
that is deployed in a named module is ignored. This is to avoid
duplicates that would otherwise arise when a named module has both a
provides directive and a provider-configuration file that mention
the same service provider.
The provider class must be visible to the class loader.
Params: - service –
The interface or abstract class representing the service
- loader – The class loader to be used to load provider-configuration files and provider classes, or
null
if the system class loader (or, failing that, the bootstrap class loader) is to be used
Type parameters: - <S> – the class of the service type
Throws: - ServiceConfigurationError – if the service type is not accessible to the caller or the caller is in an explicit module and its module descriptor does not declare that it uses
service
API Note: If the class path of the class loader includes remote network
URLs then those URLs may be dereferenced in the process of searching for
provider-configuration files.
This activity is normal, although it may cause puzzling entries to be
created in web-server logs. If a web server is not configured correctly,
however, then this activity may cause the provider-loading algorithm to fail
spuriously.
A web server should return an HTTP 404 (Not Found) response when a requested resource does not exist. Sometimes, however, web servers are erroneously configured to return an HTTP 200 (OK) response along with a helpful HTML error page in such cases. This will cause a ServiceConfigurationError
to be thrown when this class attempts to parse the HTML page as a provider-configuration file. The best solution to this problem is to fix the misconfigured web server to return the correct response code (HTTP 404) along with the HTML error page.
Returns: A new service loader @revised 9 @spec JPMS
/**
* Creates a new service loader for the given service. The service loader
* uses the given class loader as the starting point to locate service
* providers for the service. The service loader's {@link #iterator()
* iterator} and {@link #stream() stream} locate providers in both named
* and unnamed modules, as follows:
*
* <ul>
* <li> <p> Step 1: Locate providers in named modules. </p>
*
* <p> Service providers are located in all named modules of the class
* loader or to any class loader reachable via parent delegation. </p>
*
* <p> In addition, if the class loader is not the bootstrap or {@linkplain
* ClassLoader#getPlatformClassLoader() platform class loader}, then service
* providers may be located in the named modules of other class loaders.
* Specifically, if the class loader, or any class loader reachable via
* parent delegation, has a module in a {@linkplain ModuleLayer module
* layer}, then service providers in all modules in the module layer are
* located. </p>
*
* <p> For example, suppose there is a module layer where each module is
* in its own class loader (see {@link ModuleLayer#defineModulesWithManyLoaders
* defineModulesWithManyLoaders}). If this {@code ServiceLoader.load} method
* is invoked to locate providers using any of the class loaders created for
* the module layer, then it will locate all of the providers in the module
* layer, irrespective of their defining class loader. </p>
*
* <p> Ordering: The service loader will first locate any service providers
* in modules defined to the class loader, then its parent class loader,
* its parent parent, and so on to the bootstrap class loader. If a class
* loader has modules in a module layer then all providers in that module
* layer are located (irrespective of their class loader) before the
* providers in the parent class loader are located. The ordering of
* modules in same class loader, or the ordering of modules in a module
* layer, is not defined. </p>
*
* <p> If a module declares more than one provider then the providers
* are located in the order that its module descriptor {@linkplain
* java.lang.module.ModuleDescriptor.Provides#providers() lists the
* providers}. Providers added dynamically by instrumentation agents (see
* {@link java.lang.instrument.Instrumentation#redefineModule redefineModule})
* are always located after providers declared by the module. </p> </li>
*
* <li> <p> Step 2: Locate providers in unnamed modules. </p>
*
* <p> Service providers in unnamed modules are located if their class names
* are listed in provider-configuration files located by the class loader's
* {@link ClassLoader#getResources(String) getResources} method. </p>
*
* <p> The ordering is based on the order that the class loader's {@code
* getResources} method finds the service configuration files and within
* that, the order that the class names are listed in the file. </p>
*
* <p> In a provider-configuration file, any mention of a service provider
* that is deployed in a named module is ignored. This is to avoid
* duplicates that would otherwise arise when a named module has both a
* <i>provides</i> directive and a provider-configuration file that mention
* the same service provider. </p>
*
* <p> The provider class must be visible to the class loader. </p> </li>
*
* </ul>
*
* @apiNote If the class path of the class loader includes remote network
* URLs then those URLs may be dereferenced in the process of searching for
* provider-configuration files.
*
* <p> This activity is normal, although it may cause puzzling entries to be
* created in web-server logs. If a web server is not configured correctly,
* however, then this activity may cause the provider-loading algorithm to fail
* spuriously.
*
* <p> A web server should return an HTTP 404 (Not Found) response when a
* requested resource does not exist. Sometimes, however, web servers are
* erroneously configured to return an HTTP 200 (OK) response along with a
* helpful HTML error page in such cases. This will cause a {@link
* ServiceConfigurationError} to be thrown when this class attempts to parse
* the HTML page as a provider-configuration file. The best solution to this
* problem is to fix the misconfigured web server to return the correct
* response code (HTTP 404) along with the HTML error page.
*
* @param <S> the class of the service type
*
* @param service
* The interface or abstract class representing the service
*
* @param loader
* The class loader to be used to load provider-configuration files
* and provider classes, or {@code null} if the system class
* loader (or, failing that, the bootstrap class loader) is to be
* used
*
* @return A new service loader
*
* @throws ServiceConfigurationError
* if the service type is not accessible to the caller or the
* caller is in an explicit module and its module descriptor does
* not declare that it uses {@code service}
*
* @revised 9
* @spec JPMS
*/
@CallerSensitive
public static <S> ServiceLoader<S> load(Class<S> service,
ClassLoader loader)
{
return new ServiceLoader<>(Reflection.getCallerClass(), service, loader);
}
Creates a new service loader for the given service type, using the current thread's
context class loader. An invocation of this convenience method of the form
ServiceLoader.load(service)
is equivalent to
ServiceLoader.load(service, Thread.currentThread().getContextClassLoader())
Params: - service –
The interface or abstract class representing the service
Type parameters: - <S> – the class of the service type
Throws: - ServiceConfigurationError – if the service type is not accessible to the caller or the caller is in an explicit module and its module descriptor does not declare that it uses
service
API Note: Service loader objects obtained with this method should not be
cached VM-wide. For example, different applications in the same VM may
have different thread context class loaders. A lookup by one application
may locate a service provider that is only visible via its thread
context class loader and so is not suitable to be located by the other
application. Memory leaks can also arise. A thread local may be suited
to some applications. Returns: A new service loader @revised 9 @spec JPMS
/**
* Creates a new service loader for the given service type, using the
* current thread's {@linkplain java.lang.Thread#getContextClassLoader
* context class loader}.
*
* <p> An invocation of this convenience method of the form
* <pre>{@code
* ServiceLoader.load(service)
* }</pre>
*
* is equivalent to
*
* <pre>{@code
* ServiceLoader.load(service, Thread.currentThread().getContextClassLoader())
* }</pre>
*
* @apiNote Service loader objects obtained with this method should not be
* cached VM-wide. For example, different applications in the same VM may
* have different thread context class loaders. A lookup by one application
* may locate a service provider that is only visible via its thread
* context class loader and so is not suitable to be located by the other
* application. Memory leaks can also arise. A thread local may be suited
* to some applications.
*
* @param <S> the class of the service type
*
* @param service
* The interface or abstract class representing the service
*
* @return A new service loader
*
* @throws ServiceConfigurationError
* if the service type is not accessible to the caller or the
* caller is in an explicit module and its module descriptor does
* not declare that it uses {@code service}
*
* @revised 9
* @spec JPMS
*/
@CallerSensitive
public static <S> ServiceLoader<S> load(Class<S> service) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
return new ServiceLoader<>(Reflection.getCallerClass(), service, cl);
}
Creates a new service loader for the given service type, using the platform class loader. This convenience method is equivalent to:
ServiceLoader.load(service, ClassLoader.getPlatformClassLoader())
This method is intended for use when only installed providers are
desired. The resulting service will only find and load providers that
have been installed into the current Java virtual machine; providers on
the application's module path or class path will be ignored.
Params: - service –
The interface or abstract class representing the service
Type parameters: - <S> – the class of the service type
Throws: - ServiceConfigurationError – if the service type is not accessible to the caller or the caller is in an explicit module and its module descriptor does not declare that it uses
service
Returns: A new service loader @revised 9 @spec JPMS
/**
* Creates a new service loader for the given service type, using the
* {@linkplain ClassLoader#getPlatformClassLoader() platform class loader}.
*
* <p> This convenience method is equivalent to: </p>
*
* <pre>{@code
* ServiceLoader.load(service, ClassLoader.getPlatformClassLoader())
* }</pre>
*
* <p> This method is intended for use when only installed providers are
* desired. The resulting service will only find and load providers that
* have been installed into the current Java virtual machine; providers on
* the application's module path or class path will be ignored.
*
* @param <S> the class of the service type
*
* @param service
* The interface or abstract class representing the service
*
* @return A new service loader
*
* @throws ServiceConfigurationError
* if the service type is not accessible to the caller or the
* caller is in an explicit module and its module descriptor does
* not declare that it uses {@code service}
*
* @revised 9
* @spec JPMS
*/
@CallerSensitive
public static <S> ServiceLoader<S> loadInstalled(Class<S> service) {
ClassLoader cl = ClassLoader.getPlatformClassLoader();
return new ServiceLoader<>(Reflection.getCallerClass(), service, cl);
}
Creates a new service loader for the given service type to load service providers from modules in the given module layer and its ancestors. It does not locate providers in unnamed modules. The ordering that the service loader's iterator
and stream
locate providers and yield elements is as follows:
Providers are located in a module layer before locating providers
in parent layers. Traversal of parent layers is depth-first with each
layer visited at most once. For example, suppose L0 is the boot layer, L1
and L2 are modules layers with L0 as their parent. Now suppose that L3 is
created with L1 and L2 as the parents (in that order). Using a service
loader to locate providers with L3 as the context will locate providers
in the following order: L3, L1, L0, L2.
If a module declares more than one provider then the providers are located in the order that its module descriptor
lists the providers. Providers added dynamically by instrumentation agents are always located after providers declared by the module.
The ordering of modules in a module layer is not defined.
Params: - layer –
The module layer
- service –
The interface or abstract class representing the service
Type parameters: - <S> – the class of the service type
Throws: - ServiceConfigurationError – if the service type is not accessible to the caller or the caller is in an explicit module and its module descriptor does not declare that it uses
service
API Note: Unlike the other load methods defined here, the service type is the second parameter. The reason for this is to avoid source compatibility issues for code that uses load(S, null)
. Returns: A new service loader Since: 9 @spec JPMS
/**
* Creates a new service loader for the given service type to load service
* providers from modules in the given module layer and its ancestors. It
* does not locate providers in unnamed modules. The ordering that the service
* loader's {@link #iterator() iterator} and {@link #stream() stream} locate
* providers and yield elements is as follows:
*
* <ul>
* <li><p> Providers are located in a module layer before locating providers
* in parent layers. Traversal of parent layers is depth-first with each
* layer visited at most once. For example, suppose L0 is the boot layer, L1
* and L2 are modules layers with L0 as their parent. Now suppose that L3 is
* created with L1 and L2 as the parents (in that order). Using a service
* loader to locate providers with L3 as the context will locate providers
* in the following order: L3, L1, L0, L2. </p></li>
*
* <li><p> If a module declares more than one provider then the providers
* are located in the order that its module descriptor
* {@linkplain java.lang.module.ModuleDescriptor.Provides#providers()
* lists the providers}. Providers added dynamically by instrumentation
* agents are always located after providers declared by the module. </p></li>
*
* <li><p> The ordering of modules in a module layer is not defined. </p></li>
* </ul>
*
* @apiNote Unlike the other load methods defined here, the service type
* is the second parameter. The reason for this is to avoid source
* compatibility issues for code that uses {@code load(S, null)}.
*
* @param <S> the class of the service type
*
* @param layer
* The module layer
*
* @param service
* The interface or abstract class representing the service
*
* @return A new service loader
*
* @throws ServiceConfigurationError
* if the service type is not accessible to the caller or the
* caller is in an explicit module and its module descriptor does
* not declare that it uses {@code service}
*
* @since 9
* @spec JPMS
*/
@CallerSensitive
public static <S> ServiceLoader<S> load(ModuleLayer layer, Class<S> service) {
return new ServiceLoader<>(Reflection.getCallerClass(), layer, service);
}
Load the first available service provider of this loader's service. This convenience method is equivalent to invoking the
iterator()
method and obtaining the first element. It therefore returns the first element from the provider cache if possible, it otherwise attempts to load and instantiate the first provider. The following example loads the first available service provider. If
no service providers are located then it uses a default implementation.
CodecFactory factory = ServiceLoader.load(CodecFactory.class)
.findFirst()
.orElse(DEFAULT_CODECSET_FACTORY);
Throws: - ServiceConfigurationError –
If a provider class cannot be loaded for any of the reasons
specified in the Errors section above.
Returns: The first service provider or empty Optional
if no service providers are located Since: 9 @spec JPMS
/**
* Load the first available service provider of this loader's service. This
* convenience method is equivalent to invoking the {@link #iterator()
* iterator()} method and obtaining the first element. It therefore
* returns the first element from the provider cache if possible, it
* otherwise attempts to load and instantiate the first provider.
*
* <p> The following example loads the first available service provider. If
* no service providers are located then it uses a default implementation.
* <pre>{@code
* CodecFactory factory = ServiceLoader.load(CodecFactory.class)
* .findFirst()
* .orElse(DEFAULT_CODECSET_FACTORY);
* }</pre>
* @return The first service provider or empty {@code Optional} if no
* service providers are located
*
* @throws ServiceConfigurationError
* If a provider class cannot be loaded for any of the reasons
* specified in the <a href="#errors">Errors</a> section above.
*
* @since 9
* @spec JPMS
*/
public Optional<S> findFirst() {
Iterator<S> iterator = iterator();
if (iterator.hasNext()) {
return Optional.of(iterator.next());
} else {
return Optional.empty();
}
}
Clear this loader's provider cache so that all providers will be
reloaded.
After invoking this method, subsequent invocations of the iterator
or stream
methods will lazily locate providers (and instantiate in the case of iterator
) from scratch, just as is done by a newly-created service loader.
This method is intended for use in situations in which new service
providers can be installed into a running Java virtual machine.
/**
* Clear this loader's provider cache so that all providers will be
* reloaded.
*
* <p> After invoking this method, subsequent invocations of the {@link
* #iterator() iterator} or {@link #stream() stream} methods will lazily
* locate providers (and instantiate in the case of {@code iterator})
* from scratch, just as is done by a newly-created service loader.
*
* <p> This method is intended for use in situations in which new service
* providers can be installed into a running Java virtual machine.
*/
public void reload() {
lookupIterator1 = null;
instantiatedProviders.clear();
lookupIterator2 = null;
loadedProviders.clear();
loadedAllProviders = false;
// increment count to allow CME be thrown
reloadCount++;
}
Returns a string describing this service.
Returns: A descriptive string
/**
* Returns a string describing this service.
*
* @return A descriptive string
*/
public String toString() {
return "java.util.ServiceLoader[" + service.getName() + "]";
}
}