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

Source launcher should work with service loader SPI

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: P3 P3
    • 23
    • 22, 23
    • tools
    • None
    • 22
    • b26

      Service implementations read from provides directives in a module-info.java file fail to work when a Java program is launched in source mode.

      The following three-files setup:
      - m/module-info.java
      ```java
      module m {
      uses java.util.spi.ToolProvider;
      provides java.util.spi.ToolProvider with p.Tool;
      }
      ```

      - m/p/Main.java
      ```java
      package p;

      import java.util.ServiceLoader;
      import java.util.spi.ToolProvider;

      class Main {
      public static void main(String... args) throws Exception {
      System.out.println(Main.class + " in " + Main.class.getModule());

      System.out.println("1");
      System.out.println(Main.class.getResource("/p/Main.java"));
      System.out.println(Main.class.getResource("/p/Main.class"));

      System.out.println("2");
      System.out.println(Main.class.getResource("/p/Tool.java"));
      System.out.println(Main.class.getResource("/p/Tool.class"));

      System.out.println("3");
      System.out.println(ToolProvider.findFirst("p.Tool")); // empty due to SCL being used

      System.out.println("4");
              listToolProvidersIn(Main.class.getModule().getLayer());

      System.out.println("5");
              Class.forName("p.Tool"); // trigger compilation of "p/Tool.java"
      System.out.println(Main.class.getResource("/p/Tool.class"));

      System.out.println("6");
              listToolProvidersIn(Main.class.getModule().getLayer());
      }

      static void listToolProvidersIn(ModuleLayer layer) {
              try {
               ServiceLoader.load(layer, ToolProvider.class).stream()
                   .filter(service -> service.type().getModule().getLayer() == layer)
                   .map(ServiceLoader.Provider::get)
                   .forEach(System.out::println);
              } catch (java.util.ServiceConfigurationError error) {
               error.printStackTrace(System.err);
              }
      }
      }
      ```

      - m/p/Tool.java
      ```java
      package p;

      import java.io.PrintWriter;
      import java.util.spi.ToolProvider;

      public record Tool(String name) implements ToolProvider {
        public static void main(String... args) {
          System.exit(new Tool().run(System.out, System.err, args));
        }

        public Tool() {
          this(Tool.class.getName());
        }

        @Override
        public int run(PrintWriter out, PrintWriter err, String... args) {
          out.println(name + "/out");
          err.println(name + "/err");
          return 0;
        }
      }
      ```

      yields for running `java m/p/Main.java`:

      ```
      class p.Main in module m
      1
      file:/[...]/m/p/Main.java
      sourcelauncher-memoryclassloader1789718525:p/Main.class
      2
      file:/[...]/m/p/Tool.java
      null
      3
      Optional.empty
      4
      java.util.ServiceConfigurationError: java.util.spi.ToolProvider: Provider p.Tool not found
              at java.base/java.util.ServiceLoader.fail(ServiceLoader.java:589)
              at java.base/java.util.ServiceLoader.loadProvider(ServiceLoader.java:871)
              at java.base/java.util.ServiceLoader$LayerLookupIterator.hasNext(ServiceLoader.java:954)
              at java.base/java.util.ServiceLoader$ProviderSpliterator.tryAdvance(ServiceLoader.java:1485)
              at java.base/java.util.Spliterator.forEachRemaining(Spliterator.java:332)
              at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:556)
              at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:546)
              at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151)
              at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174)
              at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:265)
              at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:611)
              at m/p.Main.listToolProvidersIn(Main.java:37)
              at m/p.Main.main(Main.java:22)
              at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
              at java.base/java.lang.reflect.Method.invoke(Method.java:580)
              at jdk.compiler/com.sun.tools.javac.launcher.SourceLauncher.execute(SourceLauncher.java:264)
              at jdk.compiler/com.sun.tools.javac.launcher.SourceLauncher.run(SourceLauncher.java:153)
              at jdk.compiler/com.sun.tools.javac.launcher.SourceLauncher.main(SourceLauncher.java:78)
      5
      sourcelauncher-memoryclassloader1789718525:p/Tool.class
      6
      Tool[name=p.Tool]
      ```

      Note that running `java m/p/Tool.java` directly yieds as expected:
      ```
      p.Tool/out
      p.Tool/err
      ```

            cstein Christian Stein
            cstein Christian Stein
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: