-
Enhancement
-
Resolution: Fixed
-
P3
-
9
-
None
-
generic
-
generic
griffin-lj:java.base lukas$ java -version
java version "9-ea"
Java(TM) SE Runtime Environment (build 9-ea+170)
Java HotSpot(TM) 64-Bit Server VM (build 9-ea+170, mixed mode)
Let Service API be:
package bug;
import java.util.Iterator;
import java.util.ServiceLoader;
public abstract class A {
public abstract String impl();
public static A provider() {
ServiceLoader<A> loader = ServiceLoader.load(A.class);
Iterator<A> it = loader.iterator();
if (it.hasNext()) {
return it.next();
}
return null;
}
}
let the provider implementation be:
package bug;
public class B extends A {
public String impl() {
return "hello";
}
}
let module definition be:
module bug {
exports bug;
uses bug.A;
provides bug.A with bug.B;
}
let the user code be:
package bug;
public class Main {
public static void main(String[] args) {
System.out.println(A.provider().impl());
}
}
Expected:
"hello" is printed on System.out
Actual:
Exception in thread "main" java.util.ServiceConfigurationError: bug.A: public static bug.A bug.A.provider() failed
at java.base/java.util.ServiceLoader.fail(ServiceLoader.java:534)
at java.base/java.util.ServiceLoader.access$200(ServiceLoader.java:343)
at java.base/java.util.ServiceLoader$ProviderImpl.invokeFactoryMethod(ServiceLoader.java:757)
at java.base/java.util.ServiceLoader$ProviderImpl.get(ServiceLoader.java:653)
at java.base/java.util.ServiceLoader$2.next(ServiceLoader.java:1279)
at bug/bug.A.provider(A.java:19)
at bug/bug.Main.main(Main.java:18)
Caused by: java.util.ServiceConfigurationError: bug.A: public static bug.A bug.A.provider() failed
at java.base/java.util.ServiceLoader.fail(ServiceLoader.java:534)
at java.base/java.util.ServiceLoader.access$200(ServiceLoader.java:343)
at java.base/java.util.ServiceLoader$ProviderImpl.invokeFactoryMethod(ServiceLoader.java:757)
at java.base/java.util.ServiceLoader$ProviderImpl.get(ServiceLoader.java:653)
at java.base/java.util.ServiceLoader$2.next(ServiceLoader.java:1279)
at bug/bug.A.provider(A.java:19)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:563)
at java.base/java.util.ServiceLoader$ProviderImpl.invokeFactoryMethod(ServiceLoader.java:736)
... 4 more
...
Caused by: java.lang.StackOverflowError
at java.base/java.util.concurrent.ConcurrentHashMap.transfer(ConcurrentHashMap.java:2433)
at java.base/java.util.concurrent.ConcurrentHashMap.addCount(ConcurrentHashMap.java:2362)
at java.base/java.util.concurrent.ConcurrentHashMap.putVal(ConcurrentHashMap.java:1085)
at java.base/java.util.concurrent.ConcurrentHashMap.putIfAbsent(ConcurrentHashMap.java:1555)
at java.base/java.lang.ClassLoader.getClassLoadingLock(ClassLoader.java:632)
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:563)
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:551)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:185)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:486)
at jdk.internal.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:563)
at java.base/java.util.ServiceLoader$ProviderImpl.invokeFactoryMethod(ServiceLoader.java:736)
at java.base/java.util.ServiceLoader$ProviderImpl.get(ServiceLoader.java:653)
at java.base/java.util.ServiceLoader$2.next(ServiceLoader.java:1279)
at bug/bug.A.provider(A.java:19)
at jdk.internal.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
...
Problem:
ServiceLoader seems to be looking for nearest available 'provider' method in the inheritance tree while, IMO, it should be looking for 'provider' method in the service implementation only
Workaround:
"override" provider method in service implementation class:
public static A provider() {
return new B();
}
java version "9-ea"
Java(TM) SE Runtime Environment (build 9-ea+170)
Java HotSpot(TM) 64-Bit Server VM (build 9-ea+170, mixed mode)
Let Service API be:
package bug;
import java.util.Iterator;
import java.util.ServiceLoader;
public abstract class A {
public abstract String impl();
public static A provider() {
ServiceLoader<A> loader = ServiceLoader.load(A.class);
Iterator<A> it = loader.iterator();
if (it.hasNext()) {
return it.next();
}
return null;
}
}
let the provider implementation be:
package bug;
public class B extends A {
public String impl() {
return "hello";
}
}
let module definition be:
module bug {
exports bug;
uses bug.A;
provides bug.A with bug.B;
}
let the user code be:
package bug;
public class Main {
public static void main(String[] args) {
System.out.println(A.provider().impl());
}
}
Expected:
"hello" is printed on System.out
Actual:
Exception in thread "main" java.util.ServiceConfigurationError: bug.A: public static bug.A bug.A.provider() failed
at java.base/java.util.ServiceLoader.fail(ServiceLoader.java:534)
at java.base/java.util.ServiceLoader.access$200(ServiceLoader.java:343)
at java.base/java.util.ServiceLoader$ProviderImpl.invokeFactoryMethod(ServiceLoader.java:757)
at java.base/java.util.ServiceLoader$ProviderImpl.get(ServiceLoader.java:653)
at java.base/java.util.ServiceLoader$2.next(ServiceLoader.java:1279)
at bug/bug.A.provider(A.java:19)
at bug/bug.Main.main(Main.java:18)
Caused by: java.util.ServiceConfigurationError: bug.A: public static bug.A bug.A.provider() failed
at java.base/java.util.ServiceLoader.fail(ServiceLoader.java:534)
at java.base/java.util.ServiceLoader.access$200(ServiceLoader.java:343)
at java.base/java.util.ServiceLoader$ProviderImpl.invokeFactoryMethod(ServiceLoader.java:757)
at java.base/java.util.ServiceLoader$ProviderImpl.get(ServiceLoader.java:653)
at java.base/java.util.ServiceLoader$2.next(ServiceLoader.java:1279)
at bug/bug.A.provider(A.java:19)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:563)
at java.base/java.util.ServiceLoader$ProviderImpl.invokeFactoryMethod(ServiceLoader.java:736)
... 4 more
...
Caused by: java.lang.StackOverflowError
at java.base/java.util.concurrent.ConcurrentHashMap.transfer(ConcurrentHashMap.java:2433)
at java.base/java.util.concurrent.ConcurrentHashMap.addCount(ConcurrentHashMap.java:2362)
at java.base/java.util.concurrent.ConcurrentHashMap.putVal(ConcurrentHashMap.java:1085)
at java.base/java.util.concurrent.ConcurrentHashMap.putIfAbsent(ConcurrentHashMap.java:1555)
at java.base/java.lang.ClassLoader.getClassLoadingLock(ClassLoader.java:632)
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:563)
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:551)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:185)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:486)
at jdk.internal.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:563)
at java.base/java.util.ServiceLoader$ProviderImpl.invokeFactoryMethod(ServiceLoader.java:736)
at java.base/java.util.ServiceLoader$ProviderImpl.get(ServiceLoader.java:653)
at java.base/java.util.ServiceLoader$2.next(ServiceLoader.java:1279)
at bug/bug.A.provider(A.java:19)
at jdk.internal.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
...
Problem:
ServiceLoader seems to be looking for nearest available 'provider' method in the inheritance tree while, IMO, it should be looking for 'provider' method in the service implementation only
Workaround:
"override" provider method in service implementation class:
public static A provider() {
return new B();
}