JDK-8333131 : Source launcher should work with service loader SPI
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 22,23
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2024-05-29
  • Updated: 2024-07-16
  • Resolved: 2024-05-31
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 23
23 b26Fixed
Related Reports
Relates :  
Description
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
```
Comments
Changeset: 681137ca Author: Christian Stein <cstein@openjdk.org> Date: 2024-05-31 15:02:55 +0000 URL: https://git.openjdk.org/jdk/commit/681137cad2b1de8a0af1dfea949439bcaf5e7500
31-05-2024

A pull request was submitted for review. URL: https://git.openjdk.org/jdk/pull/19443 Date: 2024-05-29 06:29:54 +0000
29-05-2024