Here is a setup that causes this problem (though there might be a simpler one):
Create a parent project parent with settings.gradle:
rootProject.name = "parent"
include "api", "provider", "consumer"
Then put these 3 subprojects inside it: test.zip (660.6 KB)
provider and api are modular, consumer is not.
Both provider and consumer depend on api, and provider also exports api. consumer depends on provider in its tests only.
Without the war plugin of consumer, the project compiles fine in Eclipse. However, the war plugin creates a Web App Libraries container with api in it, casing an error: The package com.api is accessible from more than one module: <unnamed>, api
because api is available in 2 places (is what I understand).
Sorry for the late reply. I first had to understand the bigger picture:
The Web App Libraries classpath container from Eclipse WTP puts all entries on the classpath never on the modulepath. The container entries are created in FlexibleProjectContainer without the module attribute.
The Project and External Dependencies classpath container from Buildship is appended - when missing - after any other classpath containers. So normally the container from WTP is ordered before the container from Buildship (see Java Build Path > Order and Export in the project properties).
api is not modular in the WTP container.
api and provider are modular in the Buildship container.
api is initially resolved by the WTP container and so its packages are associated with the unnamed module.
provider is resolved by the Buildship container and so its packages are associated with the named module model.
While reading the module descriptor for model (in project provider) the requires clause for module apihas to be resolved. This time the module is found on the modulepath and now the packages from api are accessible through the unnamed module and api at the same time. (Name lookup in JDT seems here to be globally and not scoped to a single project.)
Because javac behaves differently, an option in JDT has been introduced to ignore this specific error (PR #424). Unfortunately, there is no option in the UI for this. But it can be manually added to consumer/.settings/org.eclipse.jdt.core.prefs:
After Project > Clean… the error disappears for me. I do not know, if this works in every scenario.
Another possible workaround could be to change the order of the classpath containers. When api is found on the container from Buildship before the container from WTP, it should be put on the modulepath and its packages do not end in the unnamed module.
Thank you for the detailed response. I just quickly tested by changing the order of exports in Eclipse to
and I can confirm that the issue is resolved. Of course, this is temporary and I will need to try the more permanent solution.
I would like to understand, however, why there is the additional Web App Libraries container to begin with. It seems like an implementation detail of WTP that the user shouldn’t concern themselves with.
When you have a project which is not managed by Gradle or Maven you can even remove these project and library dependencies from the Java Build Path and they can still be resolved through the Web App Libraries container.
There may be other ways to implement the deployment functionality of Eclipse WTP. So, yes - this container can be seen as an implementation detail.
Are you really using Eclipse WTP functionality (e.g. deployment assembly, server tools) or is it more an unwanted side effect of using the War plugin from Gradle? Or would it be sufficient to deploy and start the application externally?
Have you also tried the suggested solution to set the org.eclipse.jdt.core.compiler.ignoreUnnamedModuleForSplitPackage property?
We should investigate, if the Maven Integration for Eclipse WTP handles this situation better. When this is the case, Eclipse Buildship could possibly also improved. It would also be interesting what happens without a build system like Gradle or Maven - or when using the Gradle standalone project generator.
Most likely the classpath container from WTP has to preserve the module attribute when creating the classpath entries.
Are you really using Eclipse WTP functionality (e.g. deployment assembly, server tools) or is it more an unwanted side effect of using the War plugin from Gradle? Or would it be sufficient to deploy and start the application externally?
I’m using WTP server tools. I have this simplified setup in the Servers view
Have you also tried the suggested solution to set the org.eclipse.jdt.core.compiler.ignoreUnnamedModuleForSplitPackage property?
I didn’t because the solution you provided with changing the classpath order in the gradle build script worked and it’s more transparent than a hidden configuration file. Should I prefer the compiler option for some reason?
We should investigate, if the Maven Integration for Eclipse WTP handles this situation better. When this is the case, Eclipse Buildship could possibly also improved. It would also be interesting what happens without a build system like Gradle or Maven - or when using the Gradle standalone project generator.
Is there a submitted issue to track this somewhere so it won’t get lost? I can create one, but is it in the buildship repo or in some wtp-reated repo?