We are having some issue with XML file generation using JAXB.(The generated file is corrupted/jumbled even if we validate against XSD). But no errors are reported in server logs(catalina.out)
While we were doing the investigations, we happened to found the following code segment in com.sun.xml.internal.bind.v2.runtime.MarshallerImpl(This is the runtime class used by java to marshall the JAXB objects to XML).
/**
* All the marshal method invocation eventually comes down to this call.
*/
private void write(Object obj, XmlOutput out, Runnable postInitAction) throws JAXBException {
try {
if( obj == null )
throw new IllegalArgumentException(Messages.NOT_MARSHALLABLE.format());
if( schema!=null ) {
// send the output to the validator as well
ValidatorHandler validator = schema.newValidatorHandler();
validator.setErrorHandler(new FatalAdapter(serializer));
// work around a bug in JAXP validator in Tiger
XMLFilterImpl f = new XMLFilterImpl() {
@Override
public void startPrefixMapping(String prefix, String uri) throws SAXException {
super.startPrefixMapping(prefix.intern(), uri.intern());
}
};
f.setContentHandler(validator);
out = new ForkXmlOutput( new SAXOutput(f) {
@Override
public void startDocument(XMLSerializer serializer, boolean fragment, int[] nsUriIndex2prefixIndex, NamespaceContextImpl nsContext) throws SAXException, IOException, XMLStreamException {
super.startDocument(serializer, false, nsUriIndex2prefixIndex, nsContext);
}
@Override
public void endDocument(boolean fragment) throws SAXException, IOException, XMLStreamException {
super.endDocument(false);
}
}, out );
}
try {
prewrite(out,isFragment(),postInitAction);
serializer.childAsRoot(obj);
postwrite();
} catch( SAXException e ) {
throw new MarshalException(e);
} catch (IOException e) {
throw new MarshalException(e);
} catch (XMLStreamException e) {
throw new MarshalException(e);
} finally {
serializer.close();
}
} finally {
cleanUp();
}
}
private void cleanUp() {
if(toBeFlushed!=null)
try {
toBeFlushed.flush();
} catch (IOException e) {
// ignore
}
if(toBeClosed!=null)
try {
toBeClosed.close();
} catch (IOException e) {
// ignore
}
toBeFlushed = null;
toBeClosed = null;
}
The method write(Object obj, XmlOutput out, Runnable postInitAction) calls the cleanup method in the finally clause and there is the flushing is happening. But in this cleanup method while flushing if any IOException happens, they ignore the exception.
We are wondering, whether this segments generated the corrupted XML as it does not throw back the exception and simply eats up the exception.
Also we have found the following statement in API documentation of XML serializer.
class: org.apache.xml.serialize.XMLSerializer
If an I/O exception occurs while serializing, the serializer will not throw an exception directly, but only throw it at the end of serializing (either DOM or SAX's DocumentHandler.endDocument().
Any help is appreciated.
Regards, Mayuran