Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Javac plugins cannot be found #215

Closed
Trigary opened this issue Jan 5, 2021 · 5 comments
Closed

Javac plugins cannot be found #215

Trigary opened this issue Jan 5, 2021 · 5 comments
Assignees
Labels
P3 type=defect Bug, not working as expected wontfix

Comments

@Trigary
Copy link

Trigary commented Jan 5, 2021

I am trying to use this library to unit test a javac plugin.

The plugin works fine when compilation is done through javac directly:

javac src/test/resources/HelloWorld.java -Xplugin:SamplePlugin -cp 'target/classes/'

But the following unit test fails:

/**
 * Fails, while it shouldn't. The error message:
 * error: plug-in not found: SamplePlugin
 * No files were generated.
 *   at sample@1.0/sample.SampleTest.withPlugin(SampleTest.java:48)
 */
@Test
public void withPlugin() {
	Compilation compilation = Compiler.javac()
			.withOptions("-Xplugin:SamplePlugin")
			.withClasspath(List.of(new File("target/classes")))
			.compile(JavaFileObjects.forResource("HelloWorld.java"));
	CompilationSubject.assertThat(compilation).succeeded();
}

The classpath itself is correct, as demonstrated by these unit tests:

/**
 * The compilation fails due to {@code sample.SampleClass} not being available.
 */
@Test
public void withoutClasspath() {
	Compilation compilation = Compiler.javac()
			.compile(JavaFileObjects.forResource("HelloWorld.java"));
	CompilationSubject.assertThat(compilation).failed();
}

/**
 * Compilation succeeds.
 */
@Test
public void withoutPlugin() {
	Compilation compilation = Compiler.javac()
			.withClasspath(List.of(new File("target/classes")))
			.compile(JavaFileObjects.forResource("HelloWorld.java"));
	CompilationSubject.assertThat(compilation).succeeded();
}

I have uploaded this minimalistic sample Maven project to help the confirmation and the reproduction of this issue: Sample.zip

@netdpb netdpb added P3 type=defect Bug, not working as expected labels Jan 8, 2021
@netdpb netdpb self-assigned this Jan 8, 2021
@elkkhan
Copy link

elkkhan commented Jan 7, 2024

I was running into a similar issue - your sample project helped me debug this and find the root cause.

Your plugin is being discovered by the ServiceLoader but it's being ignored.

The reason for this is that your plugin resides in the sample module but your module-info.java file does not export the plugin.
The ServiceLoader first tries to search for service providers in named modules - it doesn't find one in your case.
Then, it tries to search for service providers declared via config files, like you have done in your META-INF/services directory. Your plugin is found as a service provider at this step, but it's ignored because it's part of a named module.
From ServiceLoader javadoc:

In a provider-configuration file, any mention of a service provider that is deployed in a named module is ignored. This is to avoid duplicates that would otherwise arise when a named module has both a provides directive and a provider-configuration file that mention the same service provider.

You might want to add the following line to your module-info.java file and optionally remove the config in META-INF/services:

provides com.sun.source.util.Plugin with sample.SamplePlugin;

BTW,
At first I got a false positive from the test case in the project - you're asserting whether the compilation is success, but that does not ensure that the plugin was registered and invoked. I changed the plugin code to throw a custom exception on init() to make the test more reliable by changing the compilation success assert to assertThrows(CustomException.class, () -> compile()).

@netdpb
Copy link
Member

netdpb commented Jan 8, 2024

Thanks, @elkkhan!

@Trigary, what if you use withAnnotationProcessorPath() to point to your plugin code instead of withClasspath()? (SampleClass has to be in the actual classpath.)

@Trigary
Copy link
Author

Trigary commented Jan 8, 2024

@netdpb When I originally opened the issue, the withAnnotationProcessorPath() method did not yet exist. I updated to the latest version of the library (0.21.0) and ran the following test, unfortunately, it also fails, just like the one in the original issue description.

@Test
public void withPlugin() {
	Compilation compilation = Compiler.javac()
			.withOptions("-Xplugin:SamplePlugin")
			.withAnnotationProcessorPath(List.of(new File("target/classes")))
			.withClasspath(List.of(new File("target/classes")))
			.compile(JavaFileObjects.forResource("HelloWorld.java"));
	CompilationSubject.assertThat(compilation).succeeded();
}

Thank you @elkkhan for the explanation and the suggested modifications, your fix indeed works.

I don't know whether this issue should be closed or not. On the one hand, adding the provides line to module-info.java, as suggested by @elkkhan, should probably be done no matter whether we want to use javac directly or through this library. On the other hand, when using javac directly without the provides line, the compilation succeeds, and I believe this library should optimally mirror how javac works.

With that being said, I think this issue should be closed. Users can be expected to configure their modules correctly (to include the necessary provides statements).

@elkkhan
Copy link

elkkhan commented Jan 9, 2024

@Trigary I believe compilation through cmd-line javac works because you're not compiling the plugin class as part of a module. I would say that if you try to include module-info.java in the list of args to javac, you will see the same issue.

@netdpb
Copy link
Member

netdpb commented Jan 9, 2024

It looks to me like this isn't an issue with Compile Testing per se, but a constraint on how JPMS works, so I'll close this issue. Please reopen if I've misunderstood.

@netdpb netdpb closed this as not planned Won't fix, can't repro, duplicate, stale Jan 9, 2024
@netdpb netdpb added the wontfix label Jan 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
P3 type=defect Bug, not working as expected wontfix
Projects
None yet
Development

No branches or pull requests

3 participants