I've got a module (vxml) which depends on xml-tree. xml-
tree contains a class called DoctypeCustomizer. vxml's
layer file contains:
The VoiceXMLMap.xml contains the names of classes, such as
com.foo.vxml.MyCustomizer. The DoctypeCustomizer class
(specified in vxml's layer file) reads in VoiceXMLMap.vxml
and instantiates com.foo.vxml.MyCustomizer.
This causes a ClassNotFoundDef error. It seems that even
though DoctypeCustomizer is referred to from the vxml
module's layer file, it only has access to the xml-tree
module's class loader. When I replace the reference in
vxml's layer file to a trivial subclass of
DoctypeCustomizer that lives in the vxml module, it works.
Jarda, please evaluate the bug.
I am not able to find the DoctypeCustomizer in
xml/tree-edit/src/org/netbeans/modules/xml/tree/nodes so I am moving
this to XML guys to decide what is wrong.
It is not dirrectly XML module code, Rich enhances XML module in his side.
I think Rich has problems with tree of ClassLoaders. But I do not know
in which side problem could be. Rich do you have correct modules
I'm confused about what the "right" dependencies are. My
impression was that any classes referred to in a module's
layer should be accessible from that module. My vxml
module depends on xml.tree. vxml-layer.xml refers to a
service with instanceClass=DoctypeCustomizer.
DoctypeCustomizer is in xml.tree. However, in this case
it is being loaded by the vxml module. Therefore, it is
able to load the file VoiceXMLMap.xml, which resides in
the vxml module. VoiceXMLMap.xml contains the name of a
class in the vxml module. That is the class which does
not get loaded.
So, we have a class in xml.tree (DoctypeCustomizer) which
is being loaded during the vxml layer initialization, but
cannot access classes in the vxml module.
When I add a new class to the vxml module, which is a
trivial subclass of DoctypeCustomizer, and refer to that
subclass in vxml-layer.xml instead of referring to
DoctypeCustomizer, it works. This seems to me to be an
unnecessary limitation of the services mechanism.
I've posted my patched xml.tree code to
It is not complete as yet, which is why I've not yet
submitted it the standard way.
At Jesse's suggestion, I tried explicitly using
TopManager.systemClassPath in my Class.forName call, and
it worked. This seems odd to me, as the "current"
classloader I would think should be the same as what gets
returned by TopManager.systemClassPath.
Perhaps it is a bug, or perhaps I'm misunderstanding the
subtleties of module classloaders. I'll leave it to you
whether this issue can be closed. The workaround is
sufficient for my needs.
If I understand it right what you are asking was implemented into 3.4
as issue 20663. Marking this as duplicate. Not available in 3.3.1 -
*** This issue has been marked as a duplicate of 20663 ***
Well, #20663 simply makes it more convenient for people using non-NB
external libraries such as JAXP: you can use
Thread.currentThread().getContextClassLoader() instead of the
NB-specific TopManager.getDefault().systemClassLoader(). So this is
not exactly a duplicate I suppose.
The basic problem is the same with or without #20663:
Class.forName(String) looks in the *caller's* classloader, which will
only load classes from the classpath, the caller's module, and modules
the caller's module depends on. Other modules, including those
depending on the caller's module, will *not* be accessible here. You
must pass in the ClassLoader explicitly if you want them to be. This
is not a bug, it is just how classloaders work. The calling code,
which I guess would be in the XML Tree module (?) is responsible for
passing a suitable classloader to whatever call is used to load
classes. Purely an XML module issue.
Resolved for 3.4.x or earlier, no new info since then -> closing.