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

Build path contains duplicate entry: 'module-info.java' for project 'Test' #173

Open
arjantijms opened this issue Apr 16, 2021 · 37 comments

Comments

@arjantijms
Copy link

In a Maven module that uses JPMS Maven defines the following:

  • a module descriptor located in src/main/java
  • a module descriptor in src/test/java

See https://maven.apache.org/surefire/maven-surefire-plugin/examples/jpms.html

However this does not work in M2E; an error is thrown "Build path contains duplicate entry: 'module-info.java' for project 'Test'", and the project "crashes" (meaning, nothing is recognised as Java files etc, and it's just a plain folder with files in the IDE).

@arjenzhou
Copy link

arjenzhou commented Nov 4, 2021

I have the same issue, is there any progress?

@mickaelistria
Copy link
Contributor

No known progress on this topic; but contributions are welcome.

@spannm
Copy link

spannm commented Nov 24, 2021

Having the same issue, and stopping to use Eclipse with JPMS projects. Wished I didn't have to.

@arjantijms
Copy link
Author

@HannesWell Can we do anything to lessen the pain at least? Perhaps a start would be to provide an option to ignore the second module-info and not totally crash and hang everything?

See also https://bugs.eclipse.org/bugs/show_bug.cgi?id=559601

@laeubi
Copy link
Member

laeubi commented Jan 10, 2022

@arjantijms you might want to provide a patch?

@arjantijms
Copy link
Author

you might want to provide a patch?

I could probably look into that, as I do indeed have some experience working on the Eclipse internals. That said, it's probably best to get some level of agreement from the maintainers before I come up with some kind of patch.

@HannesWell
Copy link
Contributor

HannesWell commented Jan 10, 2022

you might want to provide a patch?

I could probably look into that, as I do indeed have some experience working on the Eclipse internals. That said, it's probably best to get some level of agreement from the maintainers before I come up with some kind of patch.

@laeubi is also a maintainer of the project (as you can see by the member tag on the top right of his comments) :) Even for longer than I am.
And yes we always welcome quality contributions and encourage the community to get involved, so a patch would be welcome. :) Ideally with tests.

Regarding the issue:
I have to admit that I don't have to deal with JPMS very often and I'm not very experienced with it.
But I wonder if it would be possible and useful to use the module descriptor located in src/main/java for Java-Application launches and for the main-class/modulepath and the module descriptor located in src/test/java for (JUnit) Test launches and the test class/modulepath?

@laeubi
Copy link
Member

laeubi commented Jan 10, 2022

I have to admit that I don't have to deal with JPMS very often and I'm not very experienced with it.

As most of the other contributors as it seems :-)

That said, it's probably best to get some level of agreement from the maintainers before I come up with some kind of patch.

It seems you are the one knowing JPMS so if you suggest a solution that fits the JPMS workflow I don't see a reason for disagreement. Even if it is not completely solve the JPMS story it still can improve it, so just go a head, we are here to help if any issues/questions arise but very low at free time to work on issues that do not affect our workflows or some kind of funding (e.g. money, developer time, ...) is offered, at least a minimal project reproducing the issue would already help.

@arjantijms
Copy link
Author

My apologies to @laeubi, I only just noticed.

A project you could potentially use for testing this on Eclipse / M2E is https://github.com/piranhacloud/piranha

For example, see this Maven module:

This construct that is supported by real Maven makes it incredibly painful to nearly impossible for me to work on this project using Eclipse.

cc @mnriem

@arjantijms
Copy link
Author

It seems you are the one knowing JPMS so if you suggest a solution that fits the JPMS workflow I don't see a reason for disagreement.

Well, that's a bit of the issue here. It looks like to properly support this JDT buy-in is needed. Though JDT is chasing an absolutely rock-solid lasting solution, that may, or may not ever arrive. Of course no blame to them, but real Maven (Surefire/FailSafe particularly), already has made a choice here.

So we seem to be stuck between M2E on the one hand that should support Maven projects, and Maven having invented one specific way to deal with this very complex issue. On the other hand there's JDT chasing this perfect solution, that a) may not ever arrive, and b) if if ever arrives may or may not be compatible with how Maven does it.

@laeubi
Copy link
Member

laeubi commented Jan 10, 2022

If there are currently JDT limitations it might be good to link the corresponding issues here. I found that JDT actually offers a lot of (hidden) stuff regarding JPMS so there might already be a solution for it in the meanwhile.

Beside that, you might want to describe what is the issue with module-info.java and how maven has solved this. For example a low-hanging-fruit would be to simply exclude the module-info.java from the classpath if it does not add any functional thing to the test-classes. Beside that if the test source folder is correctly marked a such it should even be possible to compile that file given that there are dedicated output folder.

@arjantijms
Copy link
Author

If there are currently JDT limitations it might be good to link the corresponding issues here.

These are two important ones:

Beside that, you might want to describe what is the issue with module-info.java and how maven has solved this.

The issue with module-info.java is that it describes the modular requirements of a module, which is mostly the imports (modules it needs) and the exports (packages it exports), but there are some other things to having to do with reflection (opens) and service loaders.

Eclipse insists on only a single module-info.java, but Maven wants multiple. This is because there is no concept of test imports/exports in the Java module system, while there is in Maven. So this difference had to be bridged somehow.

how maven has solved this.

See https://maven.apache.org/surefire/maven-surefire-plugin/examples/jpms.html

@laeubi
Copy link
Member

laeubi commented Jan 10, 2022

A project you could potentially use for testing this on Eclipse / M2E

Thanks for the hint, is there a more focused example? I tried to import that project but it seems to have a lots of perquisites (Java 17, maven version and lost of other dependencies).

Maybe can you try out the following: Right click on the offending module-info.java in test and choose Buildpath > Exclude, does this work as a workaround?

@arjantijms
Copy link
Author

I tried to import that project but it seems to have a lots of perquisites (Java 17, maven version and lost of other dependencies).

The dependencies should all be automatically resolved by Maven. At least when I do the following on a new system, it builds without having to do anything manually:

git clone https://github.com/piranhacloud/piranha.git
mvn clean install

You indeed need to have the current version of Java installed. It doesn't bundle the JDK such as Eclipse does, but installing Java should be easy (I use https://sdkman.io which makes it even easier, and also allows you to switch to previous versions if needed for testing). But Piranha just uses the current version, so there's no need to manually switch to an old version of Java.

I can create a single Maven module example too of course, which would show the same issue.

Right click on the offending module-info.java in test and choose Buildpath > Exclude, does this work as a workaround?

It kinda does work, but it's a pain to do when switching between Eclipse installations and between machines and locations etc. Just a 'simply' recursively deleting all the tests folders from the project is what my current workaround is, but it's a different kind of pain, as it will always conflict when someone updates the project.

Perhaps the only somewhat workable workaround is to automatically exclude all module-info.java files in /test folders by M2E (both via the initial import and via update maven). Maybe with an option to switch that behaviour off, but with a warning that it will likely hang or crash Eclipse.

@laeubi
Copy link
Member

laeubi commented Jan 10, 2022

I can create a single Maven module example too of course, which would show the same issue.

That would be great as we potentially use that as a unit-test.

Perhaps the only somewhat workable workaround is to automatically exclude all module-info.java files in /test folders by M2E

Thats what I try to find out, if that helps, it might lower the pain a bit, but reading through the tickets in JDT it seems the modules-info.java might still be necessary...

@stephan-herrmann
Copy link

Let me drop some ideas what strings m2e could pull to make the desired project structure digestable for JDT:

Using JPMS options like adding exports or reads etc.:

  • the m2e project configurator (import or otherwise) may add JPMS options to the src/test/java source folder (via its classpath entry)
  • the maven classpath container might add options to any resolved classpath entry

When using the mechanism of org.eclipse.jdt.core.IClasspathEntry.getExtraAttributes() with keys from org.eclipse.jdt.core.IClasspathAttribute JDT should immediately respect those for compiling as well as for launching.

For compilation, JDT handles the main/test separation by invoking the builder twice. Search for references to org.eclipse.jdt.internal.core.CompilationGroup. This is controlled by a classpath attribute with key IClasspathAttribute.TEST.

When compiling tests, JDT considers contents of src/main/java as observable within the same module, too. If src/test/java contains module-info.java that wants to requires the module in src/main/java, then that's probably the main challenge.

If IClasspathEntry#getExclusionPatterns() can be used to exclude either of the module-info.java from compilation, this could be configured during project import, too. Or, JDT could be told to exclude src/main/java/module-info.java when compiling tests, etc.

Or could the builder for tests be told, to read the main classes from target/classes rather than src/main/java? Then we would be talking about interpreting target/classes as a module that can be required during test build, indeed.

Disclaimer: the smarts to compile test sources separately have been implemented by Till Brychcy, who no longer contributes to JDT. I have observed some of his doings but not every detail.

Additionally, for launching tests JDT automagically adds some JPMS options which can be inspected in the launch configuration dialog (button Show Command Line).

I could even imagine that m2e tells JDT to ignore src/test/java/module-info.java but behind the scenes translates its contents into JPMS options (again statically in .classpath or during resolution of the classpath container).

Or would it make sense to import src/test as a separate Eclipse project? Depending on how well nested projects work in reality, this could possibly go a long way.

I'm not recommending any specific strategy, but I'm open to:

  • explain the above concepts in more detail if needed
  • make minor additions to JDT API to fill any gaps

@laeubi
Copy link
Member

laeubi commented Jan 11, 2022

@stephan-herrmann thanks for all the insights an analysis. I have already take some look at the IClasspathAttribute.TEST and added support for it in Tycho and m2e already should mark source/output folders appropriate. So I think we are not that far away here, from the technical part.

The more problematic from my point of view is the following:

  1. We would require some sample projects that covers typical use cases and combination of module-info.java, these should be as small as possible
  2. Currently no m2e contributor (including me) seems to have a strong use-case for JPMS to handle this with priority.

Anyways if m2e+JPMS is crucial for any ones business my company offers commercial support for Open Source projects (including m2e), or one could sponsor me directly so I can afford additional time-slots for m2e/jdt development, let me know if this is interesting for anyone.

Of course direct contributions in that area are always welcome as mentioned above.

@arjantijms
Copy link
Author

let me know if this is interesting for anyone.

Even though I'm the one having opened this issue, I'm actually in the same trade. Should there indeed be a business who's interested in this I could dedicate time for this as well. @laeubi maybe, if such business would be there, maybe we could work together on getting this done.

My biggest problem is not that I could not provide patches for this, but indeed, the time-slots I have available. I doubt though we'll find a company willing to sponsor here in this issue.

Meanwhile, it would be good still to have discussions about the approaches we can take, and I'm surely eager to investigate what Maven exactly does technically to do what they do.

@stephan-herrmann
Copy link

Btw., did you see my presentation at EclipseCon Europe 2019? It has a whole section on tests vs. JPMS: https://www.youtube.com/watch?v=UUQoQtKgaWc&t=1256s :-)
Even though the example shows a layout with separate projects, some of the concepts might be usable here, too.

@laeubi
Copy link
Member

laeubi commented Jan 12, 2022

@arjantijms sure, I'll let you know if there is any opportunity.
@stephan-herrmann thanks for the link I'll currently watching your presentation to get some more ideas what m2e can do.

@TomerFi
Copy link

TomerFi commented Jan 17, 2022

Hello everyone.

I'm not a contributor here, or in any of the related repositories.

But I do work a lot with JPMS, so I figured I'll pitch in on how I handle the module-info descriptor,
I can also help out with creating some sample repositories perhaps, as requested by @laeubi.

For my projects, I do not use module-info descriptors for the test sources at all,
I use the JPMS command-line options instead, as mentioned by @stephan-herrmann.

I build with maven, you can add all the required options to maven surefire's argLine,
but I prefer using this junit-platform-maven-plugin instead.
Disclaimer: I'm not the owner but I have contributed a little bit there.

This plugin's creator had a great idea, it takes an src/test/java/module-info.test file,
which is basically a text file containing all the required JPMS options and overloads them to the command line.
It's very clean and easy to read, unlike using surefire's argLine, and the most important thing,
it doesn't cause any heat with M2E and JDT.

An example from a public project of mine that uses this technique,
src/main/java/module-info.java
src/test/java/module-info.test

As for this issue resolution, maybe providing a way to specify JPMS options,
should be considered as an alternative to accepting two module-info.java.

@stephan-herrmann
Copy link

@TomerFi Yes, using the CLI syntax is a viable workaround, as this is part of the standard.

In JDT I have always pursued the goal to hide this syntax behind a nicer UI, because that syntax is fragile (I can never remember which separator symbols are used where and with what semantics), and we don't have an editor that can help you with it (nor would I want to implement one :) ).

With this I'm only arguing why having a standard for partial module-info.java and a semantic operation of merging two or more of them would be nice. That standard would need to come from Oracle, who don't seem to have ambitions in that direction.

If module-info.test is being adopted by many, then it would be interesting if we can (re)use the Module Dependencies tab of the Build Path dialog for maintaining this file :) - this might be much easier than creating a full blown JDT-quality editor.

For the time being, we could discuss how the contents of module-info.test is fed into compilation and launching. For that matter, m2e could try to convert the contents of that file into classpath attributes, which JDT already understands. Still we'd need a way to enable these options / attributes only when compiling / running tests. Feel free to file an RFE against JDT, to provide API that accepts test-only module options. When doing so please put me on Cc:

@arutsch
Copy link

arutsch commented Apr 16, 2022

Hello,
I see that the last comment was posted months ago. I wanted to say that I have the same problem in VS Code.
It would be nice if someone has a solution for this.

Thanks.

@arjantijms
Copy link
Author

@arutsch maybe we can get someone from Microsoft involved here?

@arutsch
Copy link

arutsch commented Apr 16, 2022

I have a clue now:
Note: I have the same module-info.java problem, but with Javafx in VS Code.
2022-04-16 (3)

If you don't select "javafx-controls-14.0.2.1-win.jar" and "javafx-graphics-14.0.2.1-win.jar", the error is gone. But without these the jar file won't work too.

@mickaelistria
Copy link
Contributor

maybe we can get someone from Microsoft involved here?

Anyone is welcome to contribute, this is an open-source project and vendor independency and meritocracy are guaranteed by conforming to the Eclipse Development Project.

In the meantime, @arutsch can you please give a try to importing this project in Eclipse IDE using latest m2e snapshots? I don't know if VSCode is using a recent enough version of Java. Maybe it's better if you report this issue tohttps://github.com/redhat-developer/vscode-java first and its contributors would run the 1st round of analysis to verify if work is needed on m2e side.

@arutsch
Copy link

arutsch commented Apr 18, 2022

@mickaelistria You're right. I found the Problem in "C:\Users\User\.m2\repository\org\openjfx". Each of these jar files have their own module-info.class file: javafx-graphics-14.0.2.1-win.jar, javafx-base-14.0.2.1-win.jar and javafx-controls-14.0.2.1-win.jar, but these are only the files I use to create a .jar file so javafx-fxml-14.0.2.1-win.jar has also his own module-info.class file. The Problem now: How to use them all at the same time in one .jar program? Because if you simply remove these .class files the error is gone but the program won't work too. And what makes it worse: the module-info.class files are barely readable.

@arutsch
Copy link

arutsch commented Apr 18, 2022

@mickaelistria You're again right. With Eclipse it works much better because you have the option to just paste the java Runtime packages into the jar program. But I have a problem again:
"Exception in thread "main" java.lang.UnsupportedClassVersionError: com/example/Rock has been compiled by a more recent version of the Java Runtime (class file version 55.0), this version of the Java Runtime only recognizes class file versions up to 52.0"

@arutsch
Copy link

arutsch commented Apr 19, 2022

My Problem is finally SOLVED:)

@mickaelistria
Copy link
Contributor

@arutsch Great! Can you please summarize the steps that allowed you to resolve it?

@arjantijms
Copy link
Author

@mickaelistria You closed the issue, but I tried it in Eclipse, and it's not solved yet, is it?

@zebity
Copy link

zebity commented Jan 14, 2023

Hi m2e team & @arjantijms ,

I am getting similar issue when trying to import and build/run Jakarta metro-jax-ws tools project in Eclipse.

This has a "module-info.java" files as per the JPMS project that first identified problem.

Error:

Description	Resource	Path	Location	Type
The project was not built due to "Build path contains duplicate entry: 'module-info.java' for project 'wscompile'". Fix the problem, then try refreshing this project and building it since it may be inconsistent	wscompile		Unknown	Java Problem

I only needed to run the WsImport tool in debugger (so did not try to build / run the entire metro reference implementation), so did an "Eclipse / Import / Existing Maven Project" pointing at "metro-jax-ws/tree/master/jaxws-ri/tools/wscompile/pom.xml" within cloned git repository.

Then tried to run "metro-jax-ws/blob/master/jaxws-ri/tools/wscompile/src/main/java/com/sun/tools/ws/WsImport.java" via the debugger (so I could trace a potential bug / user error I am seeing with this), when I got the above error.

So I am strictly an Eclipse user and not contributor and raise this case, as in reading this trail it asked for other project which have similar issues.

Happy to provide additional information, so anyone looking at this, as issue still appears to be open.

thank you.

zebity/John

@laeubi
Copy link
Member

laeubi commented Jan 14, 2023

Yes the issue is still open and something the usual committer/contributors do not encounter and thus handled with very low priority, but it is on the agenda so thanks for your example!

Beside that, sponsoring is a good way to get specific issues fixed, so if this is crucial to your business and you likes to speed up the development of m2e in general a sponsoring would allow me to assign more time-slots to bug fixing or contact me for an individual contract for example fixing a specific issue.

I'll also bring this up to the Eclipse IDE WG so they can decide if this is something that might be worth sponsor through the workinggroup.

@stephan-herrmann
Copy link

On revisiting this thread, I had another look at this:

how maven has solved this.

See https://maven.apache.org/surefire/maven-surefire-plugin/examples/jpms.html

From a quick look this seems to rely on two separate regular JPMS modules, where test depends on main.

The same applies to, e.g., https://github.com/eclipse-ee4j/metro-jax-ws/tree/master/jaxws-ri/tools/wscompile

To be explicit: this would not support white box testing where "test" accesses non-exported packages from "main". "test" would not have any privileges compared to other modules. Would people be happy with this restriction?

For this direction I'd expect that sufficient options have been listed, how this can be handled just in m2e, with no changes in JDT.

As https://bugs.eclipse.org/bugs/show_bug.cgi?id=559601 has been linked earlier, that issue has a more ambitious goal: to support white box testing. I believe this is what module-info.test mentioned above is about. If that is desired, the likely solution will involve some kind of merging of two module descriptors. For this to happen a specification of that merging operation would be the first thing we need.

I think these two topics should be well separated.

@dmatej
Copy link

dmatej commented Aug 3, 2023

Current error message:

The module-info is already defined in the project

I would say that this feature starts to be acute as people are moving to Java17 and 21 and try to use JavaFX and JLine which make the JPMS mandatory.
I managed to make Maven happy and tests do pass in Maven, but not in Eclipse IDE, that even cannot compile the project.

@HannesWell
Copy link
Contributor

As mentioned above, a contribution with a fix and a test is more than welcome.

@hohwille
Copy link

hohwille commented Oct 4, 2023

I have created an according issue in JDT core on gitub: eclipse-jdt/eclipse.jdt.core#1465

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests