Saturday, January 14, 2012

Xerces Parsing and the Dreaded FWK005 Exception

One of the Java/Groovy applications I'm currently works with multiple threads. In each thread, an XML service response is marshalled into an object using a method similar to:

    private def messageObjectFrom(String responseXml) {
def jaxbElement = (JAXBElement) unmarshaller().unmarshal(readerFor(responseXml))
(MessageType) jaxbElement.value
}

Under a reasonable amount of load (several threads), the application would report the following exception during an execution of the method:

    javax.xml.bind.UnmarshalException: null
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.createUnmarshalException(AbstractUnmarshallerImpl.java:315) ~[na:1.6.0_24]
...
Caused by: org.xml.sax.SAXException: FWK005 parse may not be called while parsing.
at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source) ~[com.springsource.org.apache.xerces-2.8.1.jar:na]
at org.apache.xerces.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source) ~[com.springsource.org.apache.xerces-2.8.1.jar:na]
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:211) ~[jaxb-impl-2.1.13.jar:2.1.13]
... 43 common frames omitted

I've seen the error in the past when parsing XML in a multi-threaded application using Xerces. Several mailing lists have had questions about this error over the years which point to a concurrency issue in the Xerces parser. In my application, the parser is used inside multiple threads.

Most of the postings suggest synchronizing access to the parser. I attempted to do so by adding the synchronized keyword to the method signature:

    synchronized private def messageObjectFrom(String responseXml) {
def jaxbElement = (JAXBElement) unmarshaller().unmarshal(readerFor(responseXml))
(MessageType) jaxbElement.value
}

This indeed did resolve the issue as I haven't run into a FWK005 error since. Its unfortunate the parser itself is not thread-safe, but this solution will do for me for now.

Hope this may help someone else who runs into a similar situation. Thanks!

3 comments:

  1. The documentation for the SAX XMLReader [1] is pretty clear that you can't call parse() while a parse is in progress. That's a stronger statement than it not being thread-safe. It's not re-entrant either, which means you can't even call it again from within the same thread (e.g from your ContentHandler) while it's still busy. Xerces is just enforcing a spec requirement.

    http://docs.oracle.com/javase/1.5.0/docs/api/org/xml/sax/XMLReader.html#parse%28org.xml.sax.InputSource%29

    ReplyDelete
  2. Thank you! Your article was the first Google hit, others validate the information you have shared.

    Rick

    ReplyDelete