Friday, September 5, 2014

xerces, what a bliss


I firmly believe that you are not a seasoned Java developer until you have  faced an irritating class loading issue.

Recently found myself in xerces hell, trust me its not a good place to be in. Without going into too much details and various issues I faced (internet is filled with them). I will talk about what solved the issues for me:
Background: XercesImpl.jar and xml-apis.jar are both part of Apache xerces and XML4J xml parser library. One of the product I was working on, somehow was shipping with only XercesImpl.jar. Things worked fine until now. (looks like xml-apis.jar delivered classes were getting picked from the JDK. xerces parser jars are part of JDK since version 6 at-least, may be even earlier)

Problem: Suddenly there were errors thrown up related to “XMLGregorianCalendar2 class not found” , “Duration2 class not found”. Looks like these classes are present in the XML4J - xml-apis.jar. As this jar was not packed with the product, hence the error.

Why these error didn't come up previously: Looks like there was no Gregorian calendar related XML parsing happening in the product previously. Due to some change it started and hence the error.

Possible solution (not working): Add xml-apis.jar in the products/web-inf. But on doing so the xml-apis classes started conflicting with the already loaded apis from the JDK. You would see errors like org.apache.xerces.jaxp.datatype.DatatypeFactoryImpl cannot be cast to javax.xml.datatype.DatatypeFactory. Don't be too surprised, as both the classes are fully compatible but looks like the problem is classloader. Classes are loaded by different classloader and hence mismatch.

Even if the the application is having “parent last” classloader setting, you will see this error. Also I saw some pages where it said that adding xml-apis.jar to web-inf/lib is not suggested.

Correct solution (at-least which worked for me): Removed the xercesImpl.jar from the web-inf/lib. (classes will get served from the JDK)
In case you are using some ancient version of JDK with no XML parser, there is another safer solution > Keep xercesImpl.jar in web-inf/lib, and keep the xml-apis.jar in appserver/domain/lib directory.
This way the required API classes will not be loaded, even if they are, will not conflict with the JDK classes as these will be loaded in the same classloader as that of JDK.
The only problem I see with this solution is that, keeping the jar in domain lib will be extra manual step, outside of the regular app deployment.

In case you are aware of any better solution then do let me know.

(There is a setting in to Prefer application packages in Weblogic, that might also work, but I I have not tried. Anyways its a app server specific fix and playing too much with application class-loading sequence is not suggested)

No comments:

Post a Comment