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

    Details

    • Type: Enhancement
    • Status: Resolved
    • Priority: P3
    • Resolution: Fixed
    • Affects Version/s: 9
    • Fix Version/s: 9-repo-jigsaw
    • Component/s: core-libs
    • Labels:
      None
    • Subcomponent:
    • CPU:
      generic
    • OS:
      generic

      Description

      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();
          }

        Attachments

          Activity

            People

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

              Dates

              Created:
              Updated:
              Resolved: