Hi Paul,
It would be very strange code indeed that acted on the
ServiceConfigurationError in a way that you describe. After all, the
java.lang.Error hierarchy of throwables is reserved for things that
should be "acted upon" only by fixing the code, isn't it?
This is also explicitly noted in the javadoc of the ServiceLoader:
"Design Note: Throwing an error in these cases may seem extreme. The
rationale for this behaviour 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."
FWIW, I stumbled on the bug by chance in an application using Jetty
servlet engine as an embedded component. The service that was to be
loaded was a component of the Spring web application framework which
passed the "Web Context" CL to the ServiceLoader to load a component
and that "Web Context" CL returned by embedded Jetty was null (probably
because of miss-configuration of Jetty).
If ServiceLoader used System CL to load the class instead, the
miss-configuration of Jetty would go unnoticed.
But that's not the situation that you are concerned about. You are
concerned that a (badly written app) might end up loading "different"
service implementation even though that might be the one that should be
loaded (by the book).
Regards, Peter
On 10/01/2012 04:33 PM, Paul Sandoz wrote:
Hi Peter,
Thanks for reporting this.
It would be helpful to know the original intent of the author, but i suspect
this is a bug (even though null is commonly used to refer to the bootstrap CL).
FWIW i cannot find any explicit cases in the JDK that relies on this behaviour
to explicitly limit the loading of service provider classes to those in rt.jar,
which would be kind of a pointless use of SL :-)
I am inclined to think that fixing this is mostly harmless, since passing a
null CL renders SL useless for anything but service provider classes in rt.jar,
and there are so very few of those provider classes i.e. this issue is likely
to have been mostly worked around by explicitly passing in a non-null CL, such
as ClassLoader.getSystemClassLoader().
However, I say mostly harmless because fixing this will change behaviour to no
longer produce an error that would otherwise be acted on. This may be the case
for libraries that use SL and the user passed a CL to the library and the
library on error uses, for example. the thread context CL. Who knows, CL code
can be very strange.
Paul.
On Sep 14, 2012, at 10:20 AM, Peter Levart <[email protected]> wrote:
I reported this as Bug ID: 7198496
Regards, Peter
On 09/13/2012 05:13 PM, Peter Levart wrote:
Hi,
The javadoc for java.util.ServiceLoader.load(Class service, ClassLoader loader)
method says about it's parameters:
* @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 <tt>null</tt> if the system class
* loader (or, failing that, the bootstrap class loader) is to be
* used
So one might think that calling:
ServiceLoader.load(service, null);
is equivalent to:
ServiceLoader.load(service, ClassLoader.getSystemClassLoader());
But it is not. Either this is a bug in ServiceLoader or javadoc has to be
changed.
If null is specified as ClassLoader then ServiceLoader locates
META-INF/services/interface.name resources using system ClassLoader (using
ClassLoader.getSystemResources), but loads implementation classes using
bootstrap ClassLoader (using Class.forName(className, true, null)).
If this is not the expected behaviour then the fix is simple (in the private
constructor of ServiceLoader[217]):
- loader = cl;
+ loader = cl == null ? ClassLoader.getSystemClassLoader() : cl;
Regards, Peter