Showing posts with label JAVA. Show all posts
Showing posts with label JAVA. Show all posts

Sunday, April 13, 2014

Conditional bean validation using Hibernate Validator

In this post, we’ll see how to achieve conditional bean validation in a few steps using Hibernate Validator.

Thorough explanation on how to implement bean validation is out of this article's scope, so the reader is assumed to already have practical experience with bean validation (aka JSR-303).


Example use case

Suppose we have a bean of type ContactInfo.java that stores user contact information. For simplicity sake, we consider it only holds a country, a zip code and a phone number. Depending on the user’s country we may want the zip code to be mandatory or optional.

Here’s our bean:

package domain;

import javax.validation.constraints.NotNull;

import validationgroup.USValidation;


public class ContactData {
 private Country country; // ENUM indicating the user's country

 private String zipCode;

 private String phoneNumber;

 public ContactData(Country country, String zipCode, String phoneNumber) {
  this.country = country;
  this.phoneNumber = phoneNumber;
  this.zipCode = zipCode;
 }

 public Country getCountry(){
  return this.country;
 }
 
 public String getZipCode() {
  return zipCode;
 }
 
 public String getPhoneNumber() {
  return phoneNumber;
 }
 
}

Step 1 - Define a validation group

Create a marker interface. This will be used as an identifier to a group of validation rules:


public interface USValidation {

}

Step 2 - Add validation rules to our validation group

Add the @Null annotation on the zipCode getter as follows:


@NotNull(message="Zip code is mandatory", groups={USValidation.class})
 public String getZipCode() {
  return zipCode;
 }

The groups attribute specifies the group(s) to which the validation rule belongs to.

Step 3 - Configure the validator

Tell the validator object to apply the validation rules from our group, in addition to the default ones (which are the validation rules with no groups attribute specified).

There are actually two ways to configure the validator:

Solution A 

The simplest way is when we got a reference to the validator object. In that case, we just need to pass it the bean instance to validate, plus the interface that corresponds to the group we defined at step 1.


ContactData cd = new ContactData(Country.US, null, null);
Set<ConstraintViolation<ContactData>> validationResult = validator.validate(cd);
Assert.assertEquals(validationResult.size(), 0);

Solution B 

In case we don’t get a reference to the validator object  (for instance, when we rely on the @Valid Spring annotation to trigger bean validation from within a Controller), we can define a custom Sequence Provider to specify which are the validation groups that must be applied.

To define a custom Sequence Provider, we just need to create a class that implements the DefaultSequenceProvider interface. This interface exposes a single method that returns a list of classes that correspond to the validation groups we want to apply. 

NOTE: the class type of the bean we want to validate must be added to the returned list. Otherwise an exception like the following is thrown:

domain.ContactDataBis must be part of the redefined default group sequence.

This behavior ensures that the underlying validator object will get the default validation rules at the very least.

Here’s our custom Sequence Provider:

public class ContactDataSequenceProvider implements DefaultGroupSequenceProvider<ContactData>{
 
 
 public List<Class<?>> getValidationGroups(ContactData contactData) {
  List<Class<?>> sequence = new ArrayList<Class<?>>();
  
  /*
   * ContactDataBis must be added to the returned list so that the validator gets to know
   * the default validation rules, at the very least.
   */
  sequence.add(ContactDataBis.class);
  
  /*
   *  Here, we can implement a certain logic to determine what are the additional group of rules
   *  that must be applied. 
   */
  if(contactData != null && contactData.getCountry() == Country.US){
   sequence.add(USValidation.class);
  }
  
  return sequence;
 }

}


Once our custom sequence provider is defined, we just need to annotate the bean class with @GroupSequenceProvider like this:

@GroupSequenceProvider(value = ContactDataSequenceProvider.class)
public class ContactDataBis extends ContactData{

 public ContactDataBis(Country country, String zipCode, String phoneNumber) {
  super(country, zipCode, phoneNumber);
 }
 
}

Based on this, the validator will look for the validation groups it should apply by executing the getValidationGroups method from our Sequence Provider.

Source code

Source code and running examples (unit tests) are available here.

Friday, May 18, 2012

TestNG for starters : running a same test method several times with different parameter values

When using TestNg to write unit tests, one of the most common mistake I see people make is writing a test method in which they make several assertions in order to test giving different values as input to the method to be tested.

To illustrate this common mistake, let's assume we have a class named StringConcatener, which provides a static method to concatenate 2 given String objects :

public class StringConcatener {
 
 public static String concatStrings(String s1, String s2){
  if(s1 == null){
   s1 = "null";
  }
  
  return s1 + s2;
 }
}

Now, we are going to write a test class in which we will implement a method that will check the behavior of our concatStrings( ) method against different input values. To do this, new TestNg users often tend to stuff lots of assertions inside a same test method, just like this : 


public class TestStringConcatener {

 @Test
 public void testConcatener() {
  Assert.assertEquals(StringConcatener.concatStrings("null", "null"), "nullnull");
  Assert.assertEquals(StringConcatener.concatStrings(null, null), "nullnull");
  Assert.assertEquals(StringConcatener.concatStrings("StringA", "StringB"), "StringAStringB");
  Assert.assertEquals(StringConcatener.concatStrings("StringA", null), "StringAnull");
  // and many other assertions...
 }
}

This test method works fine but only if every assertions get the expected result. Suppose the 1st assertion does not get the expected result. Then, none of the assertions that follows it will be tested. That, obviously, is not how you want your test class to behave.

Solution


  1. Write a test method with 3 arguments : the 2 String objects to be concatenated + the expected result
  2. Marked this test method with @Test(dataProvider="EqualsAssertionsProvider") : this method is a test method which expects input from the DataProvider named "EqualsAssertionsProvider"
  3. Write the method that will provide the set of input values to the test method, and mark it with @DataProvider(name="EqualsAssertionsProvider"). The name attribute in the @DataProvider annotation specifies its name. 

public class TestStringConcatener {
 
 @DataProvider(name="EqualsAssertionsProvider")
 public Object[][] createConcatenationAssertionSet(){
  return new Object[][]{
    new Object []{"null", "null", "nullnull"},
    new Object []{null, null, "nullnull"},
    new Object []{"StringA", "StringB", "StringAStringB"},
    new Object []{"StringA", null, "StringAnull"},
  };
 }
 
 @Test(dataProvider="EqualsAssertionsProvider")
 public void testConcatener(String s1, String s2, String expectedResult){
  Assert.assertEquals(StringConcatener.concatStrings(s1, s2), expectedResult);
 }
}

As you can see, in the example above, the createConcatenationAssertionSet( ) method returns a 2 dimensional Object array :

  • the first dimension determines how many input sets the DataProvider holds (that is, how many times our test method will run)
  • the second dimension holds Object arrays that contains the values for each argument from our test method. As there are 3 arguments in our test method, each of these Object arrays contains 3 values.
Now that you're working with a DataProvider, should one of your assertions fail, the following ones will still be tested. To illustrate that, let's modify the expected result of the third input set from our DataProvider : 

new Object []{"StringA", "StringB", "StringAStringB"}

becomes

new Object []{"StringA", "StringB", "StringAStringX"}
Let's run our TestClass and see what are the results :


As you can see, the third assertions failed (the exact reason is shown on the right column), but the 4th assertions has still been checked. VoilĂ !

Look out!

As strange as it may look, DataProvider methods can only have 2 type of returns : Object[ ][ ] or Iterator<Object>[ ]. Maybe that would change in the future but at the time I wrote this post, I was using the latest available version of TestNg (6.3.1)

Sunday, April 8, 2012

Jamon : a quick and easy way to monitor Java web applications' performances

In this post, I would like to introduce a very handy way to monitor a Java web application's performance, using Jamon (click on the link to get to the Jamon project homepage). 


There are numerous ways to monitor the performances from a Java web application, but how easy it is set up and what kind of information you need in return, will determine the solution you'll choose. This could go from printing out (or logging) execution time, which has been explicitly calculated (stop time - start time), on the standard exit, to AOP using Spring Aspect or AspectJ.


The most interesting feature Jamon provides, is a web application showing you the monitoring's result.

Tools

  • Apache Tomcat 6.0.32
  • Jamon 2.73

How to use it (basic usage)

  1. Download Jamon distribution file
  2. Copy the jamon-2.73.jar library into the classpath of the project for which you want to enable monitoring.

    Remark
    Actually, you would rather copy this library to the directory from you web server, that contains the libraries that are shared across all the deployed applications. In my case, as I deployed a sample application on a Tomcat server, I copied the jamon-2.73.jar library into the %TOMCAT_HOME%/lib directory. Also, if you intend to use the provided monitoring console, you should definitely shared the library across all the applications.
  3. Deploy the provided monitoring console by copying the jamon.war file from the Jamon distribution to the %TOMCAT_HOME%/webapps directory.
  4. Add monitoring instructions to the code section you want to watch. As an example, here's some code to illustrate a practical use of Jamon : 

package org.blog.khy;

import java.io.IOException;
import java.util.Random;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.jamonapi.Monitor;
import com.jamonapi.MonitorFactory;

/**
 * Servlet implementation class JamonDemoServlet
 */
public class JamonDemoServlet extends HttpServlet {
 private static final long serialVersionUID = 1L;
 private static final Random RANDOM = new Random();
 
 @Override
 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  doGet(req, resp);
 }

 @Override
 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  String action = req.getParameter("action");

  if (action.equalsIgnoreCase("LOGIN")) {
   login(req, resp);
  } else if (action.equals("CHECKOUT")) {
   checkoutCart(req, resp);
  }
 }

 private void login(HttpServletRequest req, HttpServletResponse resp) throws IOException {
  Monitor mon = MonitorFactory.start("login");

  // simulating login process
  long randomProcessTime = (long) (RANDOM.nextDouble() * 1000.0);
  resp.getWriter().print("PROCESSED LOGIN REQUEST");
  
  try {
   Thread.sleep(randomProcessTime);
  } catch (InterruptedException e) {
   e.printStackTrace();
  }

  mon.stop();
 }

 private void checkoutCart(HttpServletRequest req, HttpServletResponse resp) throws IOException {
  Monitor mon = MonitorFactory.start("checkout");

  // simulating cart checkout process
  long randomProcessTime = (long) (RANDOM.nextDouble() * 3000.0);
  resp.getWriter().print("PROCESSED CHECKOUT REQUEST");
  
  try {
   Thread.sleep(randomProcessTime);
  } catch (InterruptedException e) {
   e.printStackTrace();
  }

  mon.stop();
 }
}


As you can see,  it's very simple to use Jamon : first, you'll retrieve and start a Monitor object by executing MonitorFactory.start(String label). The "label" argument designates the name under which the code section to monitor will be identified within the monitoring console. 


At the end of the code section that you're monitoring, just call the stop( ) method on the Monitor object. 


And voilĂ ...


I've deployed this sample servlet and had it process a few requests (some with the "action" parameter = LOGIN, some otheres with the value CHECKOUT. 


Monitoring console

Finally, open the Jamon monitoring console which is deployed at the following address : http://localhost:8080/jamon

Click on the "JAMon Admin Page" link and you'll be brought to the page from which you could access all the monitoring info : 




Among all the infos, you'll have the number of times your monitored code has been executed, the average execution time, the longest/shortest execution time, and so on.

Remarks

You might think that Jamon is only useful during development but from my personal experience, you could deploy it along with your application into production : 
  • its footprint is practically non significative
  • you can disable/enable monitoring in one click, from the administration console
  • you can filter the monitor that you want to display in the list
That was just a slight overview of Jamon's features, you should definitely take a look at its documentation, as it provides some other monitoring functionalities.

Tuesday, March 13, 2012

Remote debugging with Tomcat with Eclipse

Lately, as I was handing over some projects to a new colleague, I realized that remotely debugging a Java application which is deployed on a Tomcat instance, isn't actually trivial to every developer. 
That being said, I guess it is legitimate for a Java developer not to know that nice feature since most of us will probably work through embedding an instance of Tomcat within Eclipse.

However, there are situations in which you would definitely have to debug remotely. That's the reason why I think this topic is worth writing a post...

Configuration
As stated in the Apache Tomcat documentation, in order to enable remote debugging support, you'll need to pass the following argument to the JVM used by Tomcat, when it starts : 

-Xdebug -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n

Since Apache has already announced that they'll stop supporting Tomcat 5 soon, therefore I won't address this version of Tomcat's configuration. 

Regarding Tomcat 6 (and later), it already provides all the required configuration in the catalina.bat file : the default transport type is already set to "dt_socket" (the other supported transport type is "shared memory" but this one is not commonly used - actually, I haven't used it so far so I won't be able to tell you what it is about precisely) and the default port is set to 8000. In case the port number 8000 is already in use in your environment, you can simply change it by editing the catalina.bat file. 

Here's the section from the catalina.bat file that would interest you :

if not ""%1"" == ""jpda"" goto noJpda
set JPDA=jpda
if not "%JPDA_TRANSPORT%" == "" goto gotJpdaTransport
set JPDA_TRANSPORT=dt_socket
:gotJpdaTransport
if not "%JPDA_ADDRESS%" == "" goto gotJpdaAddress
set JPDA_ADDRESS=8000
:gotJpdaAddress
if not "%JPDA_SUSPEND%" == "" goto gotJpdaSuspend
set JPDA_SUSPEND=n
:gotJpdaSuspend
if not "%JPDA_OPTS%" == "" goto gotJpdaOpts
set JPDA_OPTS=-agentlib:jdwp=transport=%JPDA_TRANSPORT%,address=%JPDA_ADDRESS%,server=y,suspend=%JPDA_SUSPEND%
:gotJpdaOpts
shift
:noJpda

Suppose you need to change the default port, you'll, then, set another value to the JPDA_ADDRESS variable.

Running Tomcat with remote debugging enabled
  • deploy the application you need to debug as usually
  • start Tomcat by executing the catalina.bat script and providing the "jpda" argument 
(ex.: D:\Develtools\apache-tomcat-7.0.26\bin>catalina jpda start)

Then, all you need to do is to create a remote Java application in Eclipse through these few steps : 

1° Open the debug configurations 
2° Create a new Remote Java application : 


3° Specify the project you're debugging (in my example, I've configured remote debugging for one on my sample projects, named "Blog - Remote Tomcat debugging")
4° Specify the host on which the application to debug is deployed
5° Specify the port that is opened for debugging purpose (same as the one configured as JPDA_ADDRESS in the catalina.bat file from Tomcat)
6° Launch the Remote application by clicking on "Debug" 

At this point, you could set breakpoints wherever you want in the project's source code and if the code marked with your breakpoints is executed, the running thread will be suspended and you'll be able to watch variables' value, execute expression, and so on.

Tuesday, October 18, 2011

SingleThreadModel : why you should not implement it and what happens if you do

According to the Servlet specifications, the SingleThreadModel interface is deprecated since the 2.4 version of the specs. The reason why it has been deprecated is that it cannot actually guarantee thread-safety, as its name suggests. But do you know what would the consequences be if you still have a servlet implement SingleThreadModel?

The side-effects of having a servlet implement SingleThreadModel are vendor-specific. Having worked with some legacy code deployed on a Tomcat 4.x container which contains a servlet that implements SingleThreadModel, I've noticed the following behavior : the container can processed a maximum of 20 simultaneous POST requests.

Explanations

Since true thread-safety cannot be achieved by implementing SingleThreadModel, each servlet container will have 2 possibilities for treating SingleThreadModel type servlets :

  • the container manages a servlet pool (2 simultaneous requests to a same servlet will actually be handled by 2 distinct instances of the requested servlet).
  • the container synchronizes the service( ) method of the requested servlet
Use-case : SingleThreadModel servlet deployed on Tomcat
 
Here's the code for the servlet we'll deployed onto any version of Tomcat for our test purpose :


public class TestServlet extends HttpServlet implements SingleThreadModel {
 private static int requestCounter = 0;
 
 @Override
 protected void doPost(HttpServletRequest req, HttpServletResponse resp)
   throws ServletException, IOException {
  
  doGet(req, resp);
 }
 
 @Override
 protected void doGet(HttpServletRequest req, HttpServletResponse resp)
   throws ServletException, IOException {
  
  try {
   System.out.println("Start processing request with servlet " 
                        + instance : " + this + "[CPT : " + ++requestCounter + "]");
   Thread.sleep(1000000); // simulate a uber long request
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
 }
}

How to run the test?

Simply send 21 POST requests to the servlet and you'll see that the 21st request and the following ones aren't not processed by the container :



Where is this limit of 20 servlet instances configured?





Conclusion


Having a servlet implement SingleThreadModel is definitely a conception flaw that could lead to performance breakdown in the best case scenario, and to a deadlock in the worse case scenario.



Sunday, April 3, 2011

The importance of overriding Object's hashCode( ) method

During a recent conversation with some colleagues of mine, I figured out that some of them seem not to know what is the actual importance and utility of overriding the hashCode( ) method from the Object class.
Therefore, I wanted to dedicate a post for this topic.

1. Where is it used and how
The main purpose of the hashing algorithm is to improve performance of object retrieval from a hash collection such as a HashSet, HashMap and so on. Basically, such a collection can be seen as a series of buckets in which, objects will be stored. Each of these buckets is implicitly identified through the hashcode. Here's, for instance, how a HashSet can be seen : 
Fig. 1 - Empty HashSet

Every time an Object will be added to the HashSet, 2 operations will actually be done : 
  • The Object's HashCode ( ) method is executed in order to identify the bucket in which is will be stored
  • Since we are working with a Set, after having identify the appropriate bucket, the Object's equals(Object obj) method will be executed against each objects that are already stored in the same bucket to make sure a same object is not added twice to the Set.
Fig. 2 - Adding an Object to the HashSet

 2. hashCode( ) method's common issues

If the hashCode( ) method is not appropriately implemented or implemented at all : 
  • Several Objects that should be considered identical can be redundantly stored in the HashSet given they're not stored in the same bucket.
  • The contains(Object obj) method of the HashSet can return a wrong result because it was checking the wrong bucket
  • The remove(Object obj) method of the HashSet does not remove anything because, again, it was looking for the object to remove in the wrong bucket

3. Performance issues
Theoretically, an optimal hashCode( ) method would distribute the objects to store in a Hash collection among all the available buckets, so that the number of execution of the equals(Object obj) method is more or less the same regardless the bucket in which an object insertion/comparison/removal will be done

In order to check this by myself, I've written the following classes : 


package main;

public class Car {
 private String brand;
 private String model;
 
 public Car(String brand, String model){
  this.brand = brand;
  this.model = model;
 }
 
 public String getBrand() {
  return brand;
 }
 
 public void setBrand(String brand) {
  this.brand = brand;
 }
 
 public String getModel() {
  return model;
 }
 
 public void setModel(String model) {
  this.model = model;
 }

 @Override
 public boolean equals(Object obj) {  
  if (obj == null) {
   return false;
  }
  
  if (!(obj instanceof Car)) {
   return false;
  }
  
  Car other = (Car) obj;
  if (brand == null) {
   if (other.brand != null) {
    return false;
   }
  } else if (!brand.equalsIgnoreCase(other.brand)) {
   return false;
  }
  
  if (model == null) {
   if (other.model != null) {
    return false;
   }
  } else if (!model.equalsIgnoreCase(other.model)) {
   return false;
  }
  
  return true;
 }
 
 @Override
 public int hashCode() {
  final int prime = 31;
  int result = 1;
  result = prime * result + ((brand == null) ? 0 : brand.hashCode());
  result = prime * result + ((model == null) ? 0 : model.hashCode());
  return result;
 }
}

package main;

import java.util.HashSet;
import java.util.Set;

public class HashMain {
 private static final int CATALOG_SIZE = 10000;
 
 public static void main(String[] args) {
  Set<Car> carCatalog = new HashSet<Car>();
  
  populateCarCatalog(carCatalog);
  emptyCarCatalog(carCatalog);
 }
 
 private static void populateCarCatalog(Set<Car> carCatalog){
  for(int i=1; i <= CATALOG_SIZE; i++){
   Car car = new Car("Brand ".concat(Integer.toString(i)), "Model ".concat(Integer.toString(i)));
   carCatalog.add(car);
  }
 }
 
 private static void emptyCarCatalog(Set<Car> carCatalog){
  long startTime = System.currentTimeMillis();
  
  for(int i=1; i <= CATALOG_SIZE; i++){
   Car car = new Car("Brand ".concat(Integer.toString(i)), "Model ".concat(Integer.toString(i)));
   carCatalog.remove(car);
  }
  
  System.out.println("Catalog emptied in : " + ((System.currentTimeMillis() - startTime) / 1000.0));
 }
} 

I had the Eclipse IDE generate the equals(Object obj) and hashCode( ) methods and the execution took around 0.01 second.

After making the hashCode( ) method constantly return the value 1, the execution took 2.681 sec.

The reason is that at the first removal, we had to make 10000 comparisons because all the Car objects were stored in the same bucket. At the second removal, 9999 comparisons. At the third removal, 9998. And so on ...

4. Conclusion
A good practice would be to always implement the equals(Object obj) and hashCode( ) methods when defining a POJO class, no matter it will be stored in a hash collection or not.  

Saturday, February 5, 2011

Communication between Java threads : exception propagation example

In this article, I'll show you how a child thread can report an exception to its parent thread.
This mechanism prove to be very useful and convenient when the parent thread needs to take some action whenever one of its child thread fails to execute to its completion.

In the following example, a TaskManager instance acts as the main thread and a Task instance, as its child thread. The TaskManager launches a Task and the latter will throw an Exception. If we want the main thread to be notified when an exception is thrown in its child thread, one solution is to have it implement the ExceptionListener interface and to have the child thread class get a reference to the instance of ExceptionListener. 

For those who have been working with Java Swing, SWT, ..., the principle is similar to adding a listener to a graphical component.

The following code excerpt is rather straightforward, so, I guess you won't need any further explanation. By the way, I called the sleep(...) method on both threads to simulate a more realistic behavior for the TaskManager as well as the Task.



package main;

import java.beans.ExceptionListener;
import java.io.IOException;

public class TaskManager implements ExceptionListener{
   
    @Override
    public void exceptionThrown(Exception e) {
        System.out.println("An error occured in subtask --> TaskManager may need to take some action");
    }
   
   
    public static void main(String[] args) {
        TaskManager tm = new TaskManager();
        Task t = new Task(tm);
       
        Thread th = new Thread(t);
        th.start();
       
        int cpt = 0;
       
        // Main thread doing its own work
        while(cpt++ < 10){
            try {
                Thread.sleep(1000);
                System.out.println("Thread : " + Thread.currentThread().getName() + " - doing its job");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }   
}

class Task implements Runnable{
    private ExceptionListener listener;
   
    public Task(ExceptionListener listener){
        this.listener = listener;
    }
   
    @Override
    public void run(){
        try{
            // ... simulating some processing done by the child Thread
            Thread.sleep(4000);
            throw new IOException("... the specified file does not exist (for instance)");
        }catch(IOException ioe){
            if(this.listener != null){
                // propagating the caught Exception to the ExceptionListener
                listener.exceptionThrown(ioe);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
   
}

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.