JAXB Schema Validation Example
In this example, we shall learn how to validate XML against schema using JAXB. Here, we are talking about validating XML against XSD. Validation in context here is the process of verifying that an XML document meets all the constraints expressed in the schema or XSD. JAXB provides functions for validation during unmarshalling but not during marshalling.
Let’s understand this example step by step.
1. Writing the POJO class
The first step is to have a POJO class, for which we will have an XSD. During the unmarshalling of the said POJO class we shall be validating against the XSD.
Let us create 2 classes Employee.java and Address.java for our example.
Employee.java
package com.javacodegeeks.examples.jaxb.validation.entity; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement public class Employee { private int employeeId; private String name; private Address address; private Double salary; public int getEmployeeId() { return employeeId; } public void setEmployeeId(int employeeId) { this.employeeId = employeeId; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } public Double getSalary() { return salary; } public void setSalary(Double salary) { this.salary = salary; } public Employee(int employeeId, String name, Address address, Double salary) { super(); this.employeeId = employeeId; this.name = name; this.address = address; this.salary = salary; } public Employee() { super(); } }
Address.java
package com.javacodegeeks.examples.jaxb.validation.entity; import javax.xml.bind.annotation.XmlType; @XmlType public class Address { private String addressLine1; private String addressLine2; private String city; private String state; private String country; private int zipCode; public String getAddressLine1() { return addressLine1; } public void setAddressLine1(String addressLine1) { this.addressLine1 = addressLine1; } public String getAddressLine2() { return addressLine2; } public void setAddressLine2(String addressLine2) { this.addressLine2 = addressLine2; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } public String getState() { return state; } public void setState(String state) { this.state = state; } public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } public int getZipCode() { return zipCode; } public void setZipCode(int zipCode) { this.zipCode = zipCode; } public Address(String addressLine1, String addressLine2, String city, String state, String country, int zipCode) { super(); this.addressLine1 = addressLine1; this.addressLine2 = addressLine2; this.city = city; this.state = state; this.country = country; this.zipCode = zipCode; } public Address() { super(); } }
2. Generating XML Schema
In the next step, we shall be generating XML Schema for our POJO classes. To do this, right click on the package containing POJO classes in Eclipse’s project explorer, click on New and click on Other.
In this window select JAXB, then Schema from JAXB Classes and click on Next button.
In the next window specify the name of target XSD, Employee.xsd.
Last step, select the class files whose XSD is to be generated, and click on Finish.
Let’s see the XSD generated.
Employee.xsd
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="employee" type="employee"/> <xs:complexType name="address"> <xs:sequence> <xs:element name="addressLine1" type="xs:string" minOccurs="0"/> <xs:element name="addressLine2" type="xs:string" minOccurs="0"/> <xs:element name="city" type="xs:string" minOccurs="0"/> <xs:element name="country" type="xs:string" minOccurs="0"/> <xs:element name="state" type="xs:string" minOccurs="0"/> <xs:element name="zipCode" type="xs:int"/> </xs:sequence> </xs:complexType> <xs:complexType name="employee"> <xs:sequence> <xs:element name="address" type="address" minOccurs="0"/> <xs:element name="employeeId" type="xs:int"/> <xs:element name="name" type="xs:string" minOccurs="0"/> <xs:element name="salary" type="xs:double" minOccurs="0"/> </xs:sequence> </xs:complexType> </xs:schema>
3. Marshalling the object
In the next step, we shall be marshalling the object of Employee class which we shall be later validating against XSD generated in Step 2.
EmployeeMarshaller.java
package com.javacodegeeks.examples.jaxb.validation.main; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import com.javacodegeeks.examples.jaxb.validation.entity.Address; import com.javacodegeeks.examples.jaxb.validation.entity.Employee; public class EmployeeMarshaller { public static void main(String[] args) throws FileNotFoundException, JAXBException { new EmployeeMarshaller().runMarshaller(); } private void runMarshaller() throws JAXBException, FileNotFoundException { Employee emp = createEmployee(); JAXBContext context = JAXBContext.newInstance(Employee.class); Marshaller marshaller = context.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); FileOutputStream fileOutputStream = new FileOutputStream(new File("person.xml")); marshaller.marshal(emp, fileOutputStream); } private Employee createEmployee() { Address address = new Address("addressLine1", "addressLine2", "city", "state", "country", 99999); Employee emp = new Employee(1, "name", address, 100000.00); return emp; } }
On executing the above program, the Employee object shall be marshalled into person.xml as below.
person.xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <employee> <address> <addressLine1>addressLine1</addressLine1> <addressLine2>addressLine2</addressLine2> <city>city</city> <country>country</country> <state>state</state> <zipCode>99999</zipCode> </address> <employeeId>1</employeeId> <name>name</name> <salary>100000.0</salary> </employee>
4. Validating and unmarshalling the object using JAXB
Last step is to validate and unmarshal the project. Let’s write a Java program for the same.
EmployeeUnmarshaller.java
package com.javacodegeeks.examples.jaxb.validation.main; import java.io.File; import javax.xml.XMLConstants; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Unmarshaller; import javax.xml.bind.ValidationEvent; import javax.xml.bind.ValidationEventHandler; import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory; import org.xml.sax.SAXException; import com.javacodegeeks.examples.jaxb.validation.entity.Employee; public class EmployeeUnmarshaller { public static void main(String[] args) throws JAXBException, SAXException { new EmployeeUnmarshaller().runEmployeeUnmarshaller(); } private void runEmployeeUnmarshaller() throws JAXBException, SAXException { JAXBContext context = JAXBContext.newInstance(Employee.class); SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); Schema schema = sf.newSchema(new File("Employee.xsd")); Unmarshaller unmarshaller = context.createUnmarshaller(); unmarshaller.setSchema(schema); unmarshaller.setEventHandler(new EmployeeValidationEventHandler()); Employee employee = (Employee) unmarshaller.unmarshal(new File("person.xml")); System.out.println(employee.getEmployeeId()); System.out.println(employee.getName()); System.out.println(employee.getSalary()); System.out.println(employee.getAddress().getAddressLine1()); System.out.println(employee.getAddress().getAddressLine2()); System.out.println(employee.getAddress().getCity()); System.out.println(employee.getAddress().getState()); System.out.println(employee.getAddress().getCountry()); System.out.println(employee.getAddress().getZipCode()); } } class EmployeeValidationEventHandler implements ValidationEventHandler { @Override public boolean handleEvent(ValidationEvent event) { System.out.println("\nEVENT"); System.out.println("SEVERITY: " + event.getSeverity()); System.out.println("MESSAGE: " + event.getMessage()); System.out.println("LINKED EXCEPTION: " + event.getLinkedException()); System.out.println("LOCATOR"); System.out.println(" LINE NUMBER: " + event.getLocator().getLineNumber()); System.out.println(" COLUMN NUMBER: " + event.getLocator().getColumnNumber()); System.out.println(" OFFSET: " + event.getLocator().getOffset()); System.out.println(" OBJECT: " + event.getLocator().getObject()); System.out.println(" NODE: " + event.getLocator().getNode()); System.out.println(" URL: " + event.getLocator().getURL()); return true; } }
Running this program shall give following output:
1 name 100000.0 addressLine1 addressLine2 city state country 99999
Now, let’s understand this program and how it is validating.
Notice unmarshaller.setSchema(schema);
& unmarshaller.setEventHandler(new EmployeeValidationEventHandler());
. The former one tells JAXB to validate using the object against schema object in method arguments. In the later one, we are telling JAXB to use the event handler in case an error during validation occurs. Also notice that class EmployeeValidationEventHandler
extends interface ValidationEventHandler
. We are overriding its method handleEvent()
, which consist of the action to be performed in case validation fails.
To see this in action, just make some changes to person.xml in order to make it wrong. For e.g., make zipCode
value as String
value, and then run the same program. Output of program in this case would be:
EVENT SEVERITY: 1 MESSAGE: Not a number: hello LINKED EXCEPTION: java.lang.NumberFormatException: Not a number: hello LOCATOR LINE NUMBER: 9 COLUMN NUMBER: 33 OFFSET: -1 OBJECT: null NODE: null URL: file:/Users/saurabharora123/Documents/javacodegeeks/JAXBValidationExample/person.xml EVENT SEVERITY: 2 MESSAGE: cvc-datatype-valid.1.2.1: 'hello' is not a valid value for 'integer'. LINKED EXCEPTION: org.xml.sax.SAXParseException; systemId: file:/Users/saurabharora123/Documents/javacodegeeks/JAXBValidationExample/person.xml; lineNumber: 9; columnNumber: 33; cvc-datatype-valid.1.2.1: 'hello' is not a valid value for 'integer'. LOCATOR LINE NUMBER: 9 COLUMN NUMBER: 33 OFFSET: -1 OBJECT: null NODE: null URL: file:/Users/saurabharora123/Documents/javacodegeeks/JAXBValidationExample/person.xml EVENT SEVERITY: 2 MESSAGE: cvc-type.3.1.3: The value 'hello' of element 'zipCode' is not valid. LINKED EXCEPTION: org.xml.sax.SAXParseException; systemId: file:/Users/saurabharora123/Documents/javacodegeeks/JAXBValidationExample/person.xml; lineNumber: 9; columnNumber: 33; cvc-type.3.1.3: The value 'hello' of element 'zipCode' is not valid. LOCATOR LINE NUMBER: 9 COLUMN NUMBER: 33 OFFSET: -1 OBJECT: null NODE: null URL: file:/Users/saurabharora123/Documents/javacodegeeks/JAXBValidationExample/person.xml 1 name 100000.0 addressLine1 addressLine2 city state country 0
5. Download the source code
This was an example of JAXB Schema Validation.
You can download the full source code of this example here: JAXB Validation Example