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
```
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
```
- relates to
-
JDK-8336470 Source launcher should work with service loader SPI in unnamed module
- In Progress