Wednesday, December 29, 2010

JAXB : validation against XML schema at marshalling/unmarshalling

1 Introduction

One of the most commonly made mistakes when using JAXB to bind XML to Java objects, is to think that marshalling and unmarshalling operations will automatically validate the processed data values against the XML schema that has been given as input to the XJC program to generate corresponding Java classes, but as a matter of fact they don't.

Practically, lots of programmer won't even notice that aspect because they usually don't defined any constraint in their XML schema (multiplicy, pattern, min/max value, min/max length, ...), or because the values they handle remain valid throughout the different steps of their program.

So here's how I turn validations on when using JAXB...

2 Tools
  • JDK 1.6.0_14
  • JAXB 2.1.10 in JDK 6 
3 XML schema


<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.org/users" xmlns:tns="http://www.example.org/users" elementFormDefault="qualified">

    <complexType name="User">
        <sequence>
            <element name="login" type="string" maxOccurs="1"
                minOccurs="1">
            </element>
            <element name="password" maxOccurs="1" minOccurs="1">
                <simpleType>
                    <restriction base="string">
                        <minLength value="6"></minLength>
                        <pattern value=".*\d+.+"></pattern>
                    </restriction>
                </simpleType>
            </element>
            <element name="subscriptionDate" type="date" maxOccurs="1" minOccurs="1"></element>
        </sequence>
    </complexType>

    <complexType name="UserList">
        <sequence>
            <element name="users" type="tns:User" maxOccurs="unbounded" minOccurs="0"></element>
        </sequence>
    </complexType>

    <element name="UserList" type="tns:UserList"></element>
</schema>


As you can see, I've specified several constraints :
  • a user must have a login, a password and a subscription date
  • the password must have at least 8 characters and at least 1 digit

4 Validation when marshalling

Here's some code to illustrate how to turn validation on :

public static void main(String[] args) {
        try {
            JAXBContext context = JAXBContext.newInstance(ObjectFactory.class);
            Marshaller msh = context.createMarshaller();
            // setting a schema on the marshaller instance to activate validation against given XML schema
            msh.setSchema(SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema").newSchema(new File("xsd/users.xsd")));
            // specifies that the XML output must be indented
            msh.setProperty("jaxb.formatted.output", Boolean.TRUE);
           
            // creating a list of user
            UserList userList = new UserList();
           
            // creating an user
            User user = new User();
            user.setLogin("manager");
            user.setPassword("password01");
            user.setSubscriptionDate(DatatypeFactory.newInstance().newXMLGregorianCalendar(new GregorianCalendar(2010, 11, 29)));
           
            // adding the user to the list
            userList.getUsers().add(user);
            JAXBElement<UserList> element = new ObjectFactory().createUserList(userList);
           
            // marshalling the list to XML
            msh.marshal(element, new File("out/users.xml"));
        } catch (Exception e) {
            e.printStackTrace();
        }   
    }

Setting a schema on a marshaller/unmarshaller turns validation on : 

...
Marshaller msh  = context.createMarshaller();
msh.setSchema(SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema").newSchema(new File("xsd/users.xsd")));
...

The highlighted code lines specifies which schema should be used to validate against when marshalling.

Validation for unmarshalling operation is activated the same way : in the above highlighted code line, replace the marshaller instance (msh) by an unmarshaller instance and the trick is done

5 Example of valid and invalid marshalling operations

Based on the XML schema from step 3, trying to marshall a user list with a user whose password is "nopassword" will yield the following exception : 


Marshalling a user without specifying any login will yield the following exception : 


On the other hand, here's an example of valid XML output

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<UserList xmlns="http://www.example.org/users">
    <users>
        <login>manager</login>
        <password>password0</password>
        <subscriptionDate>2010-12-29+01:00</subscriptionDate>
    </users>
</UserList>

6 Source code

For those who aren't that familiar yet with JABX basic functionalities, feel free to leave a comment with your email address and I'll send you the project I used for this post.

5 comments:

  1. Hi, plz send me the code for JaxB marshalling with validations for already available xsds(2 r more). I want generate one xml file by using 3 xsds. this is my mail id:

    lakkykesav@gmail.com

    Thanks

    ReplyDelete
  2. Can you send me the source code of this example ?

    chaaben.jihed@gmail.com

    Thanks very much!!

    ReplyDelete
  3. Hi,

    dnp12078@gmail.com

    I'm using a rest service that consumes data in xml format. The service map the xml data to JXAB object automatically. I perform a validation on JAXB object using xsd schema. I need a way to identify the line where error occurs (now I got line 0, column 0), and also to identify the filed name and the entity name. I have a jaxb nested structure.

    Thanks !

    ReplyDelete
    Replies
    1. Hi there,

      Sorry for the belated answer but I was quite busy these last few weeks.

      As your rest service's consumed input is automatically unmarshalled into a JAXB POJO, I don't see how you could validate it against an XSD and get line and column numbers in return. These, by design, can only be returned when you validate an XML file with a parser.

      Delete
  4. Great writing . Incidentally if you want a CO DoR 104PN , my colleague saw a fillable document here http://pdf.ac/2j6Izm.

    ReplyDelete