n00b
n00b

Reputation: 6350

Would like unknown attributes to error when Jaxb unmarshalling

I'm using Jaxb to unmarshal XML into a java object. I need to know when new attributes/elements are in the XML and fail. However by default the unmarshaller is ignoring new elements/attributes.

Is there a configuration I can set to fail when new attributes/elements exist in the XML that are not specified in the POJO?

My POJO:

import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "ROOT")
public class Model {

    private A a;

    public A getA() {
        return a;
    }

    @XmlElement(name = "A")
    public void setA(A a) {
        this.a = a;
    }

    static class A {

        String country;

        public String getCountry() {
            return country;
        }

        @XmlAttribute(name = "Country")
        public void setCountry(String country) {
            this.country = country;
        }
    }
}

Code to unmarshal:

JAXBContext jaxbContext = JAXBContext.newInstance(Model.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();

String sample = "<ROOT>" +
                    "<A Country=\"0\" NewAttribute=\"0\"></A>" +
                    "<NEWELEMENT> </NEWELEMENT>" +
                "</ROOT>";
InputStream stream = new ByteArrayInputStream(sample.getBytes(StandardCharsets.UTF_8));

Object unmarshal = jaxbUnmarshaller.unmarshal(stream);

Upvotes: 6

Views: 4132

Answers (2)

Michael Glavassevich
Michael Glavassevich

Reputation: 1040

You can block unexpected content by enabling XML Schema validation on the Unmarshaller. If you don't already have an XML Schema for your POJO, you can generate one at runtime from the JAXBContext, build a Schema object and then set it on the Unmarshaller. By default the Unmarshaller will throw an exception if the XML document isn't valid with respect to the schema.

Here's an example of how to do that:

JAXBContext jaxbContext = JAXBContext.newInstance(Model.class);

// Generate XML Schema from the JAXBContext
final List<ByteArrayOutputStream> schemaDocs = new ArrayList<ByteArrayOutputStream>();
jaxbContext.generateSchema(new SchemaOutputResolver() {
    @Override
    public Result createOutput(String namespaceUri, String suggestedFileName)
        throws IOException {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            StreamResult sr = new StreamResult(baos);
            schemaDocs.add(baos);
            sr.setSystemId(suggestedFileName);
            return sr;
        }
    });
SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
int size = schemaDocs.size();
Source[] schemaSources = new Source[size];
for (int i = 0; i < size; ++i) {
    schemaSources[i] = new StreamSource(
        new ByteArrayInputStream(schemaDocs.get(i).toByteArray()));
}
Schema s = sf.newSchema(schemaSources);

// Set the JAXP Schema object on your Unmarshaller.
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
jaxbUnmarshaller.setSchema(s);

String sample = "<ROOT>" +
                    "<A Country=\"0\" NewAttribute=\"0\"></A>" +
                    "<NEWELEMENT> </NEWELEMENT>" +
                "</ROOT>";
InputStream stream = new ByteArrayInputStream(sample.getBytes("UTF-8"));

Object unmarshal = jaxbUnmarshaller.unmarshal(stream);

Combine this with the ValidationEventHandler (set through Unmarshaller.setEventHandler()) suggested in the previous answer if you wish to be notified about multiple errors or filter out validation errors that you want to tolerate.

Upvotes: 3

Andreas
Andreas

Reputation: 159135

You need to call Unmarshaller.setEventHandler() to make invalid XML content fail.

Upvotes: 7

Related Questions