Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JAXB marshalling to XML - Is there a way to handle it when Schema validation fails?

I am using JAXB in order to marshall/unmarshall some objects to an XML file for a small service I want to implement. Right now, I have my XML schema (.xsd file) that includes some unique constraints:

<!--....-->
<xs:unique name="uniqueValueID">
    <xs:selector xpath="entry/value"/>
    <xs:field xpath="id"/>
</xs:unique>
<!--....-->

I have loaded my XML schema into my marshaller object:

try {
//....
//Set schema onto the marshaller object
SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); 
Schema schema = sf.newSchema(new File(xsdFileName)); 
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jaxbMarshaller.setSchema(schema);

//Apply marshalling here
jaxbMarshaller.marshal(myObjectToMarshall, new File(xmlFileNName));
} catch (JAXBException | SAXException ex) {
   //Exception handling code here....
}

When the schema is valid then the target file is updated normally, but when the validation fails, then the file is emptied or with incomplete data.

I am guessing that the problem is that the marshaller opens a file stream, but when the validation fails, it does not handle the situation properly. Is there a way to properly handle this, so that when the validation fails, no writing operation is applied into the XML file?

like image 781
Nick Louloudakis Avatar asked Apr 23 '15 02:04

Nick Louloudakis


1 Answers

The JAX-B Marshaller will write to a wide variety of Java™ output interfaces. If I want to make quite certain that no bytes get written to a file or other fixed entity should marshalling fail, I use a string buffer to contain the results of the marshalling process, then write the marshalled XML document contained in the buffer, like so:

     try
     {
        StringWriter output = new StringWriter ();
        JAXBContext jc = JAXBContext.newInstance (packageId);
        FileWriter savedAs;

        // Marshal the XML data to a string buffer here
        Marshaller marshalList = jc.createMarshaller ();
        marshalList.setProperty (Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshalList.marshal (toUpdate, output);

        // append the xml to the file to update here.
        savedAs = new FileWriter (new File (xmlFileName), true);
        savedAs.write (output.toString);
        savedAs.close();
     }
     catch (IOException iox)
     {
        String msg = "IO error on save: " + iox.getMessage ();
        throw new LocalException (msg, 40012, "UNKNOWN", iox);
     }
     catch (JAXBException jbx)
     {
        String msg = "Error writing definitions: " + jbx.getMessage ();
        throw new LocalException (msg, 40005, "UNKNOWN", jbx);
     }
  }

Note that in this example, if the marshalling process fails, the program will never create the output file and it will simply discard the buffer string.

For a slightly more elegant if riskier solution, a buffered writer (java.io.BufferedWriter), which allows the caller that creates it to set the buffer size. If the buffer size exceeds the size of the document, the program will probably not write anything to the file unless the program calls close or flush on the stream.

like image 155
John Spragge Avatar answered Nov 04 '22 19:11

John Spragge