In a How to validate XML versus XSD in Java tutorial shows you how to validate an validate xml vs xsd file using the javax.xml.validation APIs. In this tutorial shows you how to use JAXB marshal schema validation during marshal operation. Here is a way to leverage the JAXB APIs.
Such as the previous tutorial, you should define Fruit XML schema
Fruit.xsd
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="fruit"> <xs:complexType> <xs:sequence> <xs:element name="id" type="xs:int"></xs:element> <xs:element name="name" type="NameFruit"></xs:element> <xs:element name="produceby" type="ProduceBy" minOccurs="0" /> </xs:sequence> </xs:complexType> </xs:element> <xs:simpleType name="NameFruit"> <xs:restriction base="xs:string"> <xs:maxLength value="10" /> </xs:restriction> </xs:simpleType> <xs:simpleType name="ProduceBy"> <xs:restriction base="xs:string"> <xs:whiteSpace value="collapse" /> <xs:maxLength value="250" /> </xs:restriction> </xs:simpleType> </xs:schema> |
Here, you should use a java model that may be generated by JAXB in Eclipse such as the below figure (you could define manually this model by yourself)

then you get java file
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
package com.javabycode.xml; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlType; @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "", propOrder = { "id", "name", "produceby" }) @XmlRootElement(name = "fruit") public class Fruit { protected int id; @XmlElement(required = true) protected String name; protected String produceby; public int getId() { return id; } public void setId(int value) { this.id = value; } public String getName() { return name; } public void setName(String value) { this.name = value; } public String getProduceby() { return produceby; } public void setProduceby(String value) { this.produceby = value; } } |
Customize the JAXB ValidationEventHandler
ValidationEventHandler catches all events that JAXB reports after finished validation. The event is an instance of ValidationEvent, and provides many details about the validation issue. You could get these details also by using SAXParseException. Here, the CustomValidationEventHandler will get information of all events and print the formatted messages.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
package com.javabycode.xml; import javax.xml.bind.ValidationEvent; import javax.xml.bind.ValidationEventHandler; public class CustomValidationEventHandler implements ValidationEventHandler { public boolean handleEvent(ValidationEvent event) { System.err.println("\nEVENT " + "\nSEVERITY: " + event.getSeverity() + "\nMESSAGE: " + event.getMessage() + "\nLOCATOR" + "\n LINE NUMBER: " + event.getLocator().getLineNumber() + "\n COLUMN NUMBER: " + event.getLocator().getColumnNumber() + "\n OFFSET: " + event.getLocator().getOffset() + "\n OBJECT: " + event.getLocator().getObject() + "\n NODE: " + event.getLocator().getNode() + "\n URL: " + event.getLocator().getURL()); return true; } } |
JAXB marshal schema validation
The validation will be activated when the marshal operation starts. To catch the events you must set a instance of ValidationEventHandler for a marshal instance.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
package com.javabycode.xml; import java.io.File; import javax.xml.XMLConstants; import javax.xml.bind.JAXBContext; import javax.xml.bind.Marshaller; import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory; public class MarshalXMLValidation { public static void main(String[] args) throws Exception { SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); Schema schema = sf.newSchema(new File("src/main/resources/Fruit.xsd")); Fruit fruit = new Fruit(); fruit.setId(0); fruit.setName("Apple from Indonesia"); fruit.setProduceby("Chile"); JAXBContext jc = JAXBContext.newInstance(Fruit.class); Marshaller marshaller = jc.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); marshaller.setSchema(schema); marshaller.setEventHandler(new CustomValidationEventHandler()); marshaller.marshal(fruit, System.out); } } |
OKay, now you run the main class MarshalXMLValidation and here is output:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
EVENT SEVERITY: 2 MESSAGE: cvc-maxLength-valid: Value 'Apple from Indonesia' with length = '20' is not facet-valid with respect to maxLength '10' for type 'NameFruit'. LOCATOR LINE NUMBER: -1 COLUMN NUMBER: -1 OFFSET: -1 OBJECT: com.javabycode.xml.Fruit@7cca494b NODE: null URL: null EVENT SEVERITY: 2 MESSAGE: cvc-type.3.1.3: The value 'Apple from Indonesia' of element 'name' is not valid. LOCATOR LINE NUMBER: -1 COLUMN NUMBER: -1 OFFSET: -1 OBJECT: com.javabycode.xml.Fruit@7cca494b NODE: null URL: null <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <fruit> <id>0</id> <name>Apple from Indonesia</name> <produceby>Chile</produceby> </fruit> |
That’s all on how to do JAXB marshal schema validation. You can download this program source code
MarshalSchemaValidate