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!
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.
ReplyDeletehttp://docs.oracle.com/javase/1.5.0/docs/api/org/xml/sax/XMLReader.html#parse%28org.xml.sax.InputSource%29
Thanks for the info!
ReplyDeleteThank you! Your article was the first Google hit, others validate the information you have shared.
ReplyDeleteRick
Cool and I have a dandy give: What Do House Renovations Cost house renovation quotes
ReplyDelete