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.
Startup warnings are being generated from jsp-parser.jar
The text of the warning is the following: [org.netbeans.core.modules #4] WARNING: Class-Path value ../../ant/lib/ant.jar from E:\software\ide\nb_prj_20031029\modules\eager\jsp-parser.jar is illegal according to the Java Extension Mechanism: must be relative and not move up directories This warning was introduced by the integration of the new Tomcat JSP parser library, which has a runtime dependency on Ant. Additionally, Ant binaries were moved to a separate directory $IDE_HOME/ant, which also contributed to this warning. I must say I have no idea how this warning could be fixed, without introducing other architecture problems, such as duplication of jar files. I suggest that the displaying of this warning is simply suppressed towards the end of the release cycle.
Jarda, I am assuming that the startup warnings that will still be present in the build (like this one) after the creation of the NetBeans 3.6 branch, will be simply suppressed in this branch in the openide/core code. Correct?
Per private discussions with Jarda Tulach, warnings will be suppressed after we create the 3.6 branch. Changing target milestone to 3.6.
IMHO the problem in this case should be fixed, rather than suppressing the startup warning. 0. I know jasper-compiler.jar currently hardcodes use of Ant task classes to run internal javac. It is quite gratuitous, however; it would probably require less code and be more readable to just launch javac directly. If it is straightforward to use a patched jasper-compiler.jar that just does that, I would recommend that. Otherwise, assuming this is not an option... 1. Remove the Class-Path entry, as well as those of any JARs like jasper-compiler.jar directly or indirectly depending on ant.jar. You may keep them in modules/ext if you like. 2. Use InstalledFileLocator at runtime to locate these JARs as well as ant.jar in the NB installation, and create a URLClassLoader based on them. Invoke whatever entry points you need from this class loader. 3. Currently web/jspparser takes no steps to ensure that ant.jar actually exists in the distribution, meaning it would break with NoClassDefFoundError's if it weren't, which is not good. You should either: a. Declare a module dependency on the Ant module to make sure it is there. However this also requires it to be enabled. b. Or, using the class loader mentioned in #2, fail gracefully if ant.jar cannot be found. c. Or, use ModuleInstall.validate() to check that ant.jar is present before permitting web/jspparser to be enabled. For promo-D we will likely have a comprehensive system of managing dependencies from modules on common installed system libraries like ant.jar, but in the meantime something should be done.
I haven't explored option 0 yet (technically this is trivial, but licensing might be an issue). I tried the other option (classloading changes), and what I found is that I had to write quite a lot of reflection code, this mechanism is hard to debug, and it still does not work. This basically means that all jasper code has to be called using reflection, correct? From the point of view of the JSP parser module, the resulting code is definitely uglier than the original code - if we can make it work at all. So I'd like to precisely know the reasons why this is preferable to using the Class-Path tag to load ant.jar. Is that because the Class-Path mechanism will not work under the new installation structure proposal, when ant.jar may end up in a different cluster than japparser.jar? Are there any other compelling reasons? Thanks.
Yes, using the simplest version of #1/#2 any entry points to the Jasper parser need to be called via reflection. You can also avoid all but one use of reflection using a callback interface defined in the module and implemented in the loader used for Jasper and Ant; the Ant module (e.g.) currently does this to interact with an ant.jar which may be located anywhere (user-switchable installation) without resorting to lots of reflection code. You just create the loader, load the impl class, newInstance, cast to the interface, and everything else is typechecked. Whether you choose to go with #1/#2, or just suppress the warning for B and think about what to do with consolidations for D, you still need to pay attention to #3 for B.
*** Issue 39658 has been marked as a duplicate of this issue. ***
I am trying Jesse's suggestion with the interface, and I can't get it to work. I use the following code (in class JspParserImpl): URL urls[] = ... // URLs of the external libraries including Ant // needed by the jspparser module URLClassLoader urlCL = new URLClassLoader(urls, JspParserImpl.class.getClassLoader()); This classloader is able to load my implementation class, but not the library classes. Is it supposed to work this way? I saw that the Ant module uses a rather more complicated approach - it has its own classloader class. What's the purpose of that class and what does it do? Isn't a plain URLClassLoader sufficient? Thanks.
JspParserImpl cannot be in the module, it must be in a separate JAR, e.g. in modules/ext. (Or you need a special URLClassLoader which refuses to load it from the module JAR, but that is messier.) Otherwise it will not be able to access the library classes because it is in the module class loader (think about how class linking works: requesting loader != defining loader). The Ant module uses some special class loaders to achieve multiple inheritance, which you do not need. However you may need to subclass URLClassLoader in order to return e.g. AllPermissions from getPermissions(CodeSource).
Jesse, thanks for useful advice. You are saying that class XYZ has to be in a separate jar file. By this, do you mean a) the class which constructs the classloader and loads the impl class, or b) the class that provides the implementation and that is loaded by reflection? Does this also mean that this class can not depend on other IDE code, e.g. OpenAPIs or my module classes? This would be a significant constraint, which would make the whole architecture substantially more complex than it is now. BTW, I also tried a dependency check that you suggested earlier: > c. Or, use ModuleInstall.validate() to check that ant.jar is present > before permitting web/jspparser to be enabled. This did not have any effect, though, as the loading of the modules fails before this code gets executed, if the required classpath item can not be found. BTW, do you know any details about the Promo D architecture that you mentioned before? Thanks. > For promo-D we will likely have a comprehensive system of managing > dependencies from modules on common installed system libraries like > ant.jar, but in the meantime something should be done.
(b) I suppose. If JspParserImpl provides the impl of some interface JspParser and is loaded by reflection, then it cannot live in the module JAR, because then it would be loaded by the module class loader (simply because it can be and that is a lower loader), and it would thus not be able to refer to the libraries. Just put this class (and whatever else needs to refer to the libraries) in a separate JAR - the impl JAR - which can then depend on the module (and anything the module depends on incl. Open APIs), and the libraries. It is really pretty simple. You have some interfaces in the module defining what you want to be able to do, and module code calls them; a separate source root (compiled against module classes and libraries) provides impls; some static setup code makes a URLCL with the impl JAR plus the libraries, with the parent loader being the module loader. If you set it up right, there should only be about ten lines of code dealing with class loaders and reflection at all. In the Ant module, see AntBridge, BridgeInterface, and BridgeImpl as an example. I don't know exactly what the promo-D architecture for this will look like. Maybe Yarda does. It may look different on different platforms.
Fixed the subissue that JSP parser effectively depends on ant.jar, but this dependency is not enforced. Used mechanism a. - declared a dependency on the Ant module.
Ok, this issue is now fixed following Jesse's suggestion. However, the fix was not as straightforward as outlined. The area of JSP parser integration is very intensive on classloading and sensitive to the correct behavior of classloaders. Notably, the class loader that loads user classes that are a part of the web application, has to adhere to the servlet specification in many respects. Similarly, the context classloader for the parser thread is constrained by the specification. A problem arises when the user applications contains some of the classes that are used by the classloader itself - at one point I had two different classloaders which loaded these, which was causing problems. The final solution is that some JSP parser jar files continue to be in the JSP parser module's classloader. Jesse, BTW., what's the behavior of Thread.getContextClassLoader() in the IDE? I didn't see this described at http://www.netbeans.org/download/dev/javadoc/OpenAPIs/org/openide/modules/doc-files/api.html Thanks.
http://www.netbeans.org/download/dev/javadoc/OpenAPIs/org/openide/doc-files/classpath.html#syscl
v