bind

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.

Step1
Select New –> Other

In this window select JAXB, then Schema from JAXB Classes and click on Next button.

Step2
Select JAXB –> Schema from JAXB Classes

In the next window specify the name of target XSD, Employee.xsd.

Step3
Enter desired XSD name

Last step, select the class files whose XSD is to be generated, and click on Finish.

Step4
Select JAXB Classes

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.

Download
You can download the full source code of this example here: JAXB Validation Example

Saurabh Arora

Saurabh graduated with an engineering degree in Information Technology from YMCA Institute of Engineering, India. He is SCJP, OCWCD certified and currently working as Technical Lead with one of the biggest service based firms and is involved in projects extensively using Java and JEE technologies. He has worked in E-Commerce, Banking and Telecom domain.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button