FYI: ClassLoading and Castor Issue (Resolved)

This posting is to help others skip the laborious process of trying to figure out why Castor (a popular Java/XML binding framework) will not work in WebMethods 6.5 sp2. It used to work in prior versions. It also sheds some light on classloading in WebMethods for those interested.

The Situation:
Given that we have a Java class named Sample that was deployed as a jar file in the packages/X/jars directory, a castor mapping file for Sample deployed in the packages/X/classes directory and the castor jar file deployed in the packages/X/jars directory here is what we observed. The WM Java Service in package X was able to create both the Castor Unmarshaller class and the Sample java class. However Castor got an error ClassNotFoundException when we tried to unmarshall an XML document to Java. The only difference was Castor was trying to create the Sample class instead of the Java Service. Weird.

The Solution:
First it is important to note that WebMethods uses the “standard” delegation model for Java class loading which is not the model used in JEE.

According to the JavaDocs for ClassLoader the algorithm used to search for classes is to delegate the search to the parent class loader before attempting to find the class itself. In the JEE model used in most application servers the algorithm used to search for classes is attempt the class itself before delegating the search to the parent classloader.

Second there is a castor jar file in the packages/wmPRT/jars/static directory. This jars/static directory apparently loads the jar in the parent Java classloader instead of the package classloader. This is what prevented Castor from being able to find our custom class Sample. WM apparently uses the system class loader for classes in jars/static so our service in package X was using the wmPRT version of Castor instead of the jar we deployed with our code. In addition the classloader that loads Castor
is what Castor must use by default when it creates classes. The problem is Castor was trying to do this with a class loader that had no visibility into our package classpath. IMHO this jars/static directory seems really dangerous since it is too easy to load jars above the package level and cause problems in other packages. The IS/common/jars seems better suited for this.

Third (thankfully) castor allows you to specify a classloader to use when you perform an unmarshall operation. However a bug/feature in Castor requires that you set it on the Mapping object instead of the Unmarshaller.

Looks something like this in your WM Java Service:

Unmarshaller um = new Unmarshaller();
Mapping map = new Mapping(new Sample().getClass().getClassloader());
map.loadMapping(mappingFile);
um.setMapping(map);
Sample mySample = um.unmarshall(new StringReader(xmlSample));

HTH
Mike