Please use the Apache issue tracking system for new NetBeans issues ( !!
Bug 178735 - ProjectClasspathModifier.addRoots()/addLibraries() doesn't work for Netbeans project
ProjectClasspathModifier.addRoots()/addLibraries() doesn't work for Netbeans ...
Product: apisupport
Classification: Unclassified
Component: Project
All All
: P1 (vote)
: 6.x
Assigned To: Jesse Glick
Depends on: 179578
Blocks: 180455
  Show dependency treegraph
Reported: 2009-12-16 07:43 UTC by Milan Kuchtiak
Modified: 2010-02-11 03:55 UTC (History)
1 user (show)

See Also:


Note You need to log in before you can comment on or make changes to this bug.
Description Milan Kuchtiak 2009-12-16 07:43:53 UTC
You may theoretically change this to an enhancement but it would be nice if the Netbeans module could wrap the jar files specified in these methods. May be user can be asked for confirmation first.

Now the message appears:
Cannot add JAR XXX to this module as it is.
Make a library wrapper module for it and add that as a dependency.

This happens for example when you want to drag & drop some REST service resource, e.g. Facebook from Web Services node(Services tab) into Netbeans module java source.
Comment 1 rmichalsky 2009-12-16 09:10:50 UTC
Yes, it is an enhancement, ClassPathExtender in apisupport never implemented this. P1 enh. since it probably blocks serious WS RCP client development. 

I could implement it, there may be a "political" problem that CPE will be adding <class-path-extension> to the module instead of creating another lib wrapper module. CC'ing Jesse, as he usually opposed putting too much stuff to <c-p-e>.
Comment 2 Jesse Glick 2009-12-16 09:50:34 UTC
Indeed, I don't recommend simply adding <c-p-e> to the target module. It messes up update semantics (cannot independently update real code vs. 3rd-party libs), and it will not work well if two or more modules in the same suite use the lib, which does not seem at all unlikely for a serious WS-using app.

Creating a lib wrapper module for the JARs is a possibility, but better would be to declare a dep on a known module. This could work in several ways:

1. We could expand the hardcoded list in apisupport.project of j2se library name -> module CNB. Currently we do junit_4 and swing-layout. We could do others as an easy short-term fix.

2. We could somehow discover the owner of the lib at runtime using module introspection. Works only if the lib is in fact a Class-Path extension of that module, which is not true in some cases. For example, org.netbeans.modules.junit declares a descriptor whereas org.netbeans.libs.junit4 actually supplies those classes.

3. [probably best] The library descriptor could include an optional volume specifying a module CNB. This is analogous to what happens if you are using Maven (see those descriptors with <type>maven-pom</type>). There is a minor irritation that the libraries API uses URL rather than URI, so we cannot use an abstract token like "nbm://".

What is the concrete use case here, i.e. which library do you have in mind?
Comment 3 Milan Kuchtiak 2009-12-17 07:50:13 UTC
> What is the concrete use case here, i.e. which library do you have in mind?

e.g. JAXB library, or jar file created for Facebook REST service.
See :
Comment 4 Milan Kuchtiak 2010-01-04 06:32:08 UTC
To be more specific in describing use cases, we need:

Use case 1:
to add dependency on Netbeans library, like JAXB, JAX-WS
 - ProjectClasspathModifier.addLibraries()

Use case 2:
to add dependency on a specific jar file
 - ProjectClasspathModifier.addRoots()
Comment 5 Jesse Glick 2010-01-14 13:04:36 UTC
As of core-main #3b3d1c4272a5 you can add libraries (your use case #1) if the classpath volume(s) is of the form


(Currently the code just assumes without checking that module-bundling-library.jar in fact declares Class-Path: ext/whatever.jar; could be refined if needed.)

To make use of this, I also fixed the declarations of the jaxb, jaxws21, swdp, and restapi libraries to specify the CNB in the nbinst URL (which you should have been doing to begin with). junit4, jaxrpc16, swing-layout, and a number of other potentially useful libraries were already correct and seem to work.

(The former code added deps on both libs.junit4 and nbjunit when you created a unit test, i.e. "added junit4 library". The new code only adds a dep on libs.junit4, since that is what the library requests. Of course the user can add a test dep on nbjunit on their own if they plan to use those classes, and if we make a NbTestCase template then its wizard should try to add that dep too.)

Note that the module which declares the library is irrelevant here - only the owner of the JAR matters. For example, the jaxb lib packages together JARs from both libs.jaxb and xml.jaxb.api; both will be added to your module's CP if you add this lib. More to the point, swing-layout is declared by the form module, but it is o.jdesktop.layout which is added as the dependency. This corrects my concern in the originally proposed technique #2.

removeLibraries is not supported for now. I doubt it is called; if it is, it could be supported. There would however be the caveat that the result may be imprecise since there is not a 1-1 correspondence between library and module dep. For example, the jaxws21 lib seems to be a superset of jaxb (except for jaxb1-impl.jar), so if you "added jaxws21" and then "removed jaxb" you would be left with deps only on websvc.jaxws21 and websvc.jaxws21api, which does not correspond to any set of libraries.
Comment 6 Jesse Glick 2010-01-14 14:44:01 UTC
I would like to know more about use case #2 before I do any work on it. Probably ModuleClassPathExtender.addRoots can add <c-p-e>s using something like CustomizerLibraries.addJarButtonActionPerformed (Util.copyClassPathExtensionJar and ProjectXMLManager.replaceClassPathExtensions).

But (1) it is not really desirable to add <c-p-e>s to individual modules, for reasons already explained, and creating a library wrapper module with no human intervention is not a good idea; (2) a caller might try to add the same JAR again in the future, since the ClassPath.COMPILE for the module's source root is not going to include the same JAR as was originally passed in (rather, a copy).

Please supply a complete realistic use case, with steps I can follow to have ModuleClassPathExtender.addRoots actually be called today. "jar file created for Facebook REST service" doesn't tell me enough to evaluate what options are appropriate.
Comment 7 Quality Engineering 2010-01-14 23:40:05 UTC
Integrated into 'main-golden', will be available in build *201001150201* on (upload may still be in progress)
User: Jesse Glick <>
Log: #178735 (1/2): permit libraries to be "added" to NBM projects if there is a matching library wrapper module.
Comment 8 Milan Kuchtiak 2010-01-15 05:40:01 UTC
> I would like to know more about use case #2 before I do any work on it.

The use case:

- create J2SE Project, or web project (doesn't mater).
- open some java file in editor
- drag and drop some REST operation, e.g. photo_search from Flickr|Photo Service|REST (Runtime tab | Web Services)

What's happening there :

- the Flickr service is described by wadl file (FlickrWadl.xml), which also includes the XML schema file describing request/response data format.
- the SaasServices support compiles the XML schema and generates the jar file for those classes
- the jar file is added to project (under project_home/lib/ folder)

The code is included in :|
see addClientJars() (line 86) and addArchivesToProject() (line 119).

In Flickr case, the is extended with :
Comment 9 Milan Kuchtiak 2010-01-15 05:42:29 UTC
BTW: thanks for implementing the first part. I'll check it.
Comment 10 Jesse Glick 2010-01-15 17:08:04 UTC
(In reply to comment #8)
> addArchivesToProject() (line 119)

Several problems I see with this code:

1. classPath.contains(destJar) is nonsense; this would always be false. The classpath would only "contain" *.class files _inside_ JARs. Perhaps you meant Arrays.asList(classPath.getRoots()).contains(FileUtil.getArchiveRoot(destJar))?

2. getWebServiceClientLibraryDir, returning lib/webservice_clients (and BTW you forgot to use PATH_LIBRARIES rather than hardcoded "lib" consistently in getProjectLibraryDirectory) is not going to work well for an NBM project; addRoots would anyway have to copy the JAR to release/modules/ext for it to be usable.

3. new URL(destJar.getURL().toExternalForm() + "/") looks to be nonsense. "file:/myprj/lib/webservice_clients/stuff.jar/" is not a valid URL. "file:/myprj/lib/webservice_clients/stuff.jar" is a valid URL but is not a directory and cannot legally be used as a classpath root. I think what you meant was FileUtil.getArchiveRoot(destJar.getURL()).
Comment 11 Jesse Glick 2010-01-15 19:00:50 UTC
libs.jaxb has to be made public for it to be possible to add at least Facebook REST:

.../harness/build.xml:165: The module module1 is not a friend of .../ide12/modules/org-netbeans-libs-jaxb.jar
Comment 12 Jesse Glick 2010-01-15 19:28:42 UTC
Implemented addRoots to accept JAR files. They will be copied to release/modules/ext/ if not already there. Should return false if a similar JAR was already added. Packages in the JARs will not be added to the module's public package list - they are only for use from the src/ dir. Lightly tested with REST services and seems to work (the editor may show error badges until restart). core-main #fbbb35f27e40
Comment 13 Quality Engineering 2010-01-16 23:28:44 UTC
Integrated into 'main-golden', will be available in build *201001170201* on (upload may still be in progress)
User: Jesse Glick <>
Log: #178735: support addRoots to add JARs as <class-path-extension>s.
Comment 14 Milan Kuchtiak 2010-01-18 01:18:23 UTC
Sorry for the SAAS Services code. I agree with you.
I'll have to fix those issues.
And thanks for addRoots(). It's a useful improvement.

By use of this website, you agree to the NetBeans Policies and Terms of Use. © 2014, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo