Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8181204

(sl) Static "provider" method should only be invoked if defined directly by provider class

XMLWordPrintable

    • Icon: Enhancement Enhancement
    • Resolution: Fixed
    • Icon: P3 P3
    • 9-repo-jigsaw
    • 9
    • core-libs
    • 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();
          }

            alanb Alan Bateman
            ljungman Lukáš Jungmann
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: