| Summary: | Classes from workspace projects referenced by a classifier are unavailable in test classpath | ||||||
|---|---|---|---|---|---|---|---|
| Product: | z_Archived | Reporter: | Fred Bricon <fbricon> | ||||
| Component: | m2e | Assignee: | Project Inbox <m2e.core-inbox> | ||||
| Status: | CLOSED FIXED | QA Contact: | |||||
| Severity: | normal | ||||||
| Priority: | P3 | CC: | brice+eclipse, cforce, eclipse, eladtabak, igor, rhuddusa, staciewaleyko | ||||
| Version: | unspecified | ||||||
| Target Milestone: | --- | ||||||
| Hardware: | PC | ||||||
| OS: | Windows 7 | ||||||
| Whiteboard: | |||||||
| Attachments: |
|
||||||
|
Description
Fred Bricon
Created attachment 209251 [details]
Test case to reproduce the issue
attached projects test pass when running "mvn clean test" via command line from the root project.
When running module2 test via Junit in Eclipse, test fails with a ClassNotFoundException.
Maven model does not have any metadata that describes contents of classified artifacts. For classifier=tests we can reasonably assume the contents comes from dependency project target/test-classes folder. For other classifiers, there is simply no way to tell with any certainty. Igor, I totally agree about the "tests" classifier case and the way it's currently handled. All I'm saying is the current arbitrary rule that says unknown classifier = test classifier doesn't work out. It would be equally arbitrary to add target/classes to the classpath for such unknown classifiers. But with the added advantage of making the describe use case work. m2e is expected to ignore dependencies with unknown classifiers, using dependency target/test-classes folder indeed does not make sense. I'm in the same case as the OP. I have a project that generates several artifacts with different classifiers (basically those classifiers maps to a kind of resource file types in the artifacts, for instance I have one classifier "json"). Some other projects depends on those projects "json" classified projects. Maven command-line is able to properly run the Junit tests that uses those json resources that are into this json classified artifact. But running the exact same Junit test in eclipse definitely fails if the dependent project is open, because this json classifier is considered as a test classifier. That would make much more sense to consider all unknown classifier as main classifier than test classifiers. It'll eventually even match what the maven command-line is doing (which IMHO is a good goal). I definitely can produce a github pull request or patch if needed. (In reply to comment #5) > > That would make much more sense to consider all unknown classifier as main > classifier than test classifiers. It'll eventually even match what the maven > command-line is doing (which IMHO is a good goal). > How adding random/unexpected classes to classpath makes sense? How will this "eventually" match command-line classpath? (In reply to comment #6) > (In reply to comment #5) > > > > That would make much more sense to consider all unknown classifier as main > > classifier than test classifiers. It'll eventually even match what the maven > > command-line is doing (which IMHO is a good goal). > > > > How adding random/unexpected classes to classpath makes sense? It's absolutely not random nor unexpected. If your project depends on an artifact with a given classifier then that's because you usually intend to do something useful with it, otherwise you'd not even add a dependency. > How will this "eventually" match command-line classpath? Because that's how the command-line behave. It just adds all classified artifacts to the classpath as in this logs: mvn -X test ... [INFO] [surefire:test {execution: default-test}] ... [DEBUG] test classpath classpath: [DEBUG] /home/brice/cvs/project/project-core/target/test-classes [DEBUG] /home/brice/cvs/project/project-core/target/classes ... [DEBUG] /home/brice/.m2/repository/com/test/project/project-maps/1.0.0-SNAPSHOT/project-maps-1.0.0-SNAPSHOT-json.jar ... [DEBUG] provider classpath classpath: [DEBUG] /home/brice/cvs/project/project-core/target/test-classes [DEBUG] /home/brice/cvs/project/project-core/target/classes ... [DEBUG] /home/brice/.m2/repository/com/test/project/project-maps/1.0.0-SNAPSHOT/project-maps-1.0.0-SNAPSHOT-json.jar ... As you can see above, maven added to the surefire classpath the "json" classified artifacts of "project-maps". The exact same test when run in eclipse and the "project-maps" is *not* open, so it resort to fetching the artifacts from the maven local repository (classpath extracted through the Properties item of the VM running the test): /home/brice/cvs/project/project-core/target/test-classes /home/brice/cvs/project/project-core/target/classes ... /home/brice/.m2/repository/com/test/project/project-maps/1.0.0-SNAPSHOT/project-maps-1.0.0-SNAPSHOT-json.jar ... Now, I just open the project-maps project in Eclipse, and run the exact same test. The classpath now becomes: /home/brice/cvs/project/project-core/target/test-classes /home/brice/cvs/project/project-core/target/classes ... /home/brice/cvs/project-maps/target/test-classes ... As you can see it references test-classes now. Maybe I'm overlooking artifact classifiers and my use of them is incorrect. I just think the m2e behavior is inconsistent with what maven does. (In reply to comment #7) > > > That would make much more sense to consider all unknown classifier as main > > > classifier than test classifiers. It'll eventually even match what the maven > > > command-line is doing (which IMHO is a good goal). > > > > > > > How adding random/unexpected classes to classpath makes sense? > > It's absolutely not random nor unexpected. > If your project depends on an artifact with a given classifier then that's > because you usually intend to do something useful with it, otherwise you'd not > even add a dependency. > It is impossible to properly represent dependency on classified attached artifacts within eclipse workspace. It can either be dependency on entire project or no dependency at all. So when dependency with classifier=foo is requested, adding main, test and all other classes/resources produced by dependency project is very much unexpected and certainly does not match what happens on command line. Brice, there's no denying we have a mismatch between Maven and Eclipse builds with regards to classpath management here. Let's see what we're facing here : - unknown classifiers treated as test classifiers => bad, it should never do that - unknown classifiers are ignored => eclipse builds will fail 100% of the time, Maven CLI build will succeed 100% - if all classes are added when an unknown classifier is met => Eclipse builds will probably work 99% of the time, but you might break Maven builds. For example, with the ejb-client classifier : only a subset of EJB classes are exposed via that classifier. If a web project has a dependency on that particular classifier, Eclipse would leak other classes not normally available for CLI builds, breaking Maven CLI builds. From my understanding, Igor' stance here is we should never break the Maven build (but I could possibly miss other stuff). My opinion here is that, until we can come up with a proper solution for classifier management, treating unknown classifier as main classifier is an acceptable risk : users would still be able to fix the code after a CLI build failure. Not doing so would simply prevent users from using Workspace resolution in Eclipse, which I find much more hindering. Igor, I suspect that, Brice having a French name, he may have misused "eventually" when he meant "possibly" (typical mistake from French speaking natives) (In reply to comment #9) > ... > My opinion here is that, until we can come up with a proper solution for > classifier management, treating unknown classifier as main classifier is an > acceptable risk : users would still be able to fix the code after a CLI build > failure. Not doing so would simply prevent users from using Workspace > resolution in Eclipse, which I find much more hindering. I don't know how other people are working, but in my team, we run a CI server that uses the maven CLI, and every dev use eclipse. Preventing the dev to run their tests in Eclipse is very detrimental to our way of working. We'd definitely prefer to break the maven build by mistake (and be able to fix it, since our CI would alert us) than prevent our day-to-day eclipse workflow. Now, I understand Igor's concern and fully respect this. If that can't be made, then we'll find a work-around. > Igor, I suspect that, Brice having a French name, he may have misused > "eventually" when he meant "possibly" (typical mistake from French speaking > natives) You nailed it, sorry about that :) In m2e it shall behave the same way as it does from cmd line. If Maven "cmd line " behaviour is not like it should be, please request to change it there, but not let m2e handle things different . Maven is the reference not m2e! Please don't give up single sourcing! . It's great if a developer builds behave and does the same way like called from cmd line, eg in build server jenkins. Bot of course it shouldn't be needed to maintain the same build (local and global) twice. There shall be NO difference, excep´t profile and usr/pwd strings. We packaed extra a jar with all classes via assemply plugin in war project, because we habe another test-project we need to dependent on this jar with added it via classifier "classes". That is unknown and test in eclipse failed because of missing classes in cp. We will test no just to use well known classifier "jar" which shall add it to cp and test in eclipse shall work. For any case you want to have files packed intp cp (properties, xml files .. ) just use "jar" als classifier ... why not? In other casses it doesn't make sense to default copy any files of any classsifier into cp. So m2e plugin mvn xm cfg need s to have a config section where someone can configure a mapping - where to copy these files into structure. All I have to say here -- we welcome quality patches. I pushed a new API/extension point for Launch configuration classpath resolvers, based on classifiers : http://git.eclipse.org/c/m2e/m2e-core.git/commit/?id=c30ebdb14e18906e4ef1be233946669f3459155d (tests : https://github.com/sonatype/m2e-core-tests/commit/9935488f954cff935a75672cff6395fb8ba9d785) 3rd party plugins can implement the IClassifierClasspathProvider interface, or rather extend AbstractClassifierClasspathProvider and provide appropriate test or runtime classpath for a given classifier. By default, unknown classifiers fall back a NO-OP IClassifierClasspathProvider implementation, to match existing m2e behaviour. It would be very easy, should Igor agree to it, to make it add main classes to test/runtime classpath. test368230_FancyClassifier and test368230_unknownClassifier fail for me on the current master. is this expected? org.eclipse.core.runtime.CoreException: Launch configuration T06-runtime references non-existing project runtimeclasspath-testscope06. at org.eclipse.jdt.launching.JavaRuntime.abort(JavaRuntime.java:1395) at org.eclipse.jdt.launching.JavaRuntime.getJavaProject(JavaRuntime.java:1270) at org.eclipse.m2e.jdt.internal.launch.MavenRuntimeClasspathProvider.computeUnresolvedClasspath(MavenRuntimeClasspathProvider.java:90) at org.eclipse.m2e.tests.ClasspathProviderTest.test368230_FancyClassifier(ClasspathProviderTest.java:452) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at junit.framework.TestCase.runTest(TestCase.java:168) at junit.framework.TestCase.runBare(TestCase.java:134) at junit.framework.TestResult$1.protect(TestResult.java:110) at junit.framework.TestResult.runProtected(TestResult.java:128) at junit.framework.TestResult.run(TestResult.java:113) at junit.framework.TestCase.run(TestCase.java:124) at junit.framework.TestSuite.runTest(TestSuite.java:243) at junit.framework.TestSuite.run(TestSuite.java:238) at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:83) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) at org.eclipse.pde.internal.junit.runtime.RemotePluginTestRunner.main(RemotePluginTestRunner.java:62) at org.eclipse.pde.internal.junit.runtime.PlatformUITestHarness$1.run(PlatformUITestHarness.java:47) at org.eclipse.swt.widgets.RunnableLock.run(RunnableLock.java:35) at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Synchronizer.java:135) at org.eclipse.swt.widgets.Display.runAsyncMessages(Display.java:3965) at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3642) at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine$9.run(PartRenderingEngine.java:1049) at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:332) at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.run(PartRenderingEngine.java:939) at org.eclipse.e4.ui.internal.workbench.E4Workbench.createAndRunUI(E4Workbench.java:79) at org.eclipse.ui.internal.Workbench$5.run(Workbench.java:587) at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:332) at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:542) at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:149) at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:124) at org.eclipse.pde.internal.junit.runtime.NonUIThreadTestApplication.runApp(NonUIThreadTestApplication.java:54) at org.eclipse.pde.internal.junit.runtime.UITestApplication.runApp(UITestApplication.java:41) at org.eclipse.pde.internal.junit.runtime.NonUIThreadTestApplication.start(NonUIThreadTestApplication.java:48) at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:196) at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:110) at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:79) at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:353) at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:180) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:629) at org.eclipse.equinox.launcher.Main.basicRun(Main.java:584) at org.eclipse.equinox.launcher.Main.run(Main.java:1443) at org.eclipse.equinox.launcher.Main.main(Main.java:1419) I didn't noticed the test project setting files were ignored when I committed/pushed the tests. Sorry about that. Please try again now. I am using Eclipse Luna with the following version of m2e: 1.5.2.20150413-2215 I am still seeing the behavior described in the original bug. Is that a regression? In response to the previous comment I also saw the same behavior as the original bug with Eclipse Luna and m2e versions 1.1.1.20150109 and 1.6.2.20150902 (In reply to Stacie Waleyko from comment #17) > In response to the previous comment I also saw the same behavior as the > original bug with Eclipse Luna and m2e versions 1.1.1.20150109 and > 1.6.2.20150902 Sorry that should be 1.5.1.20150109 |