This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

Bug 242859 - CoS execution should prepend target/classes/ to ${java.class.path}, but leave target/*.jar
Summary: CoS execution should prepend target/classes/ to ${java.class.path}, but leave...
Status: RESOLVED WONTFIX
Alias: None
Product: projects
Classification: Unclassified
Component: Maven (show other bugs)
Version: 8.0
Hardware: All All
: P3 normal (vote)
Assignee: Tomas Stupka
URL:
Keywords:
Depends on:
Blocks: 153635
  Show dependency tree
 
Reported: 2014-03-13 13:32 UTC by Jesse Glick
Modified: 2016-07-07 08:37 UTC (History)
1 user (show)

See Also:
Issue Type: ENHANCEMENT
Exception Reporter:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jesse Glick 2014-03-13 13:32:41 UTC
Say you have projects A and B with B dependent on A (say via a Maven snapshot dependency), and are running a test in B after making a change in a class in A which that test will exercise somehow, and have compile-on-save mode enabled (for both projects). Rather than setting the classpath for the test to

  a/target/a.jar:b/target/classes:b/target/test-classes

as ‘mvn test’ would from the CLI, the IDE will set it to

  a/target/classes:b/target/classes:b/target/test-classes

If the code is do nothing special with class loaders or modules or whatever, this will probably work, because AppClassLoader does not generally care whether a class gets loaded from a JAR or not. There will be a different CodeSource and a few other differences but simple programs will not care.

However larger systems using some kind of module structure will often care. In particular, they may be asking for ClassLoader.getResources('META-INF/MANIFEST.MF') or otherwise expecting classpath resources that are generated by a build process occurring after Java compilation. In such cases you have to hack the module system to find the original JAR (or similar classpath artifact):

https://github.com/jenkinsci/jenkins/commit/fb0ad71b719f4a49e21492273c3f3a03035b92fa


I think it would be better to prepend the classes directory, but leave the original entry:

  a/target/classes:a/target/a.jar:b/target/classes:b/target/test-classes

This means that so long as you have run a full build of A at least once (or since changing A’s metadata, typically much less common than Java source code changes), and so long as the module system is not strict about the CodeSource, tests in B will still work and pick up the last-saved version of classes from A. It would be enough to make CoS work for typical systems.

There is the downside that Class.forName('a.RecentlyDeletedClass') will return a class from a.jar, but this rarely matters in practice.


An alternative would be to keep the classpath as

  a/target/classes:b/target/classes:b/target/test-classes

yet scan a/target/a.jar for resources *not* present in a/src/main/resources/ and copy them into a/target/classes/. However this seems riskier since if the IDE fails to clean out a/target/classes/ before the next regular build (it is *supposed* to but this is not terribly reliable), the build step to create the a.jar could fail in weird ways.
Comment 1 Jesse Glick 2014-03-13 13:34:50 UTC
The proposed change would probably suffice to make CoS work for “unit” tests in NB module development, where the NB platform expects a META-INF/MANIFEST.MF entry to be available for every module.
Comment 2 Milos Kleint 2014-03-13 17:05:47 UTC
I suppose this should be reassigned to maven, as the classpath composition for maven based projects is nowadays done on maven level only (and is injected into a cmd line maven. Unless you've suppressed it and are still using the old ant based CoS execution.
Comment 3 Jesse Glick 2014-03-14 03:08:28 UTC
Yes I am using regular Maven CoS. Thought this was all handled generically.
Comment 4 Milos Kleint 2014-03-14 08:28:51 UTC
Unfortunately not easily to be done within the current CoS solution.

We inject an WorkspaceReader implementation via maven.ext.class.path property, so any 3.x maven will use our implementation in the core. So we effectively modify the internals of maven that way. The advantage here is that it works with most maven plugins that way without a need to modify the plugins in any way. exec-maven-plugin, maven-surefire-plugin etc..
The disadvantage is that the API for workspaceReader allows us just to replace 1 artifact for another one (jar in local repo for target/classes)
Comment 5 Milos Kleint 2014-03-14 08:32:12 UTC
are any other resources affected by this than MANIFEST.MF?
Comment 6 Jesse Glick 2014-03-14 15:20:24 UTC
(In reply to Milos Kleint from comment #4)
> We inject an WorkspaceReader implementation via maven.ext.class.path

I guess this explains why the command line printed in the Output Window is not actually what is happening. Which is a bit frustrating, by the way: if your test fails with a weird error due to a missing JAR manifest, and you then copy the “command line” printed by NetBeans and paste it into a shell, the test runs fine. It would be better I think to not suppress the CLI argument -Dmaven.ext.class.path=… since that can be vital to reproducing the failure from a shell. (You could remove this argument and see the behavior difference, pinpointing the issue as NetBeans-specific.)


> The disadvantage is that the API for workspaceReader allows us just to
> replace 1 artifact for another one (jar in local repo for target/classes)

Hmm. So my alternative suggestion (pulling missing bits out from the JAR and synchronizing them into target/classes/) could still work. (*)


(In reply to Milos Kleint from comment #5)
> are any other resources affected by this than MANIFEST.MF?

Cannot think of anything offhand. For example, in the case of NBM projects, a hand-edited layer.xml would already be synchronized by CoS, and META-INF/generated-layer.xml should be present in target/classes/ if the IDE’s internal compiler is working correctly.

Perhaps the specific policy of how to handle CoS should be an SPI so that a particular packaging type module can select a behavior known to work for that module system—whether extracting resources from a JAR previously created by an external build system, or generating temporary copies of such resources adequate for testing based on POM information, etc.


(*) I would still feel much more comfortable if the IDE created a separate target/cos/ or whatever, so there is no chance of accidentally contaminating the CLI Maven lifecycle with IDE-generated classes or resources. This would also significantly simplify the code (I think) since you would not need to create a .netbeans_automatic_build marker, or clean up generated classes prior to a full build, etc.
Comment 7 Martin Balin 2016-07-07 08:37:24 UTC
This old bug may not be relevant anymore. If you can still reproduce it in 8.2 development builds please reopen this issue.

Thanks for your cooperation,
NetBeans IDE 8.2 Release Boss