Tuesday, February 16, 2010

Bookmark and Share

One question I'm being asked pretty often when talking about the Bean Validation API (JSR 303) is, how cross-field validation can be done. The canonical example for this is a class representing a calendar event, where the end date of an event shall always be later than the start date.

This and other scenarios where validation depends on the values of multiple attributes of a given object can be realized by implementing a class-level constraint.

That basically works pretty well, nevertheless this is one part of the BV spec, I'm not too comfortable with. This is mainly for two reasons:

  • You'll probably need a dedicated constraint for every reasonably complex business object. Providing an annotation, a validator implementation and an error message for each can become pretty tedious.
  • Business objects typically know best themselves, whether they are in a consistent, valid state or not. By putting validation logic into a separate constraint validator class, objects have to expose their internal state, which otherwise might not be required.

To circumvent these problems, I suggested a while ago a generic constraint annotation, which allows the use of script expressions written in languages such as Groovy to implement validation logic directly at the validated class.

This approach frees you from the need to implement dedicated constraints for each relevant business object, but also comes at the cost of losing type-safety at compile-time.

The constraint presented in the following therefore tries to combine genericity with compile-time type safety. The basic idea is to implement validation logic within the business objects themselves and to invoke this logic from within a generic constraint class.

In order to do so let's first define an interface to be implemented by any validatable class:

1
2
3
4
public interface Validatable {

    public boolean isValid();
}

Next we define a constraint annotation, @SelfValidating, which we'll use later on to annotate Validatable implementations:

1
2
3
4
5
6
7
8
9
10
11
12
13
@Target( { TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = SelfValidatingValidator.class)
@Documented
public @interface SelfValidating {

    String message() default "{de.gmorling.moapa.self_validating.SelfValidating.message}";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

}

Of course we also need a constraint validator implementation, which is able to evaluate that constraint:

1
2
3
4
5
6
7
8
9
10
11
public class SelfValidatingValidator implements
    ConstraintValidator<SelfValidating, Validatable> {

    public void initialize(SelfValidating constraintAnnotation) {}

    public boolean isValid(Validatable value,
        ConstraintValidatorContext constraintValidatorContext) {

        return value.isValid();
    }
}

The implementation is trivial, as nothing is to do in initialize() and the isValid() method just delegates the call to the validatable object itself.

Finally we need a properties file named ValidationMessages.properties containing the default error message for the constraint:

1
de.gmorling.moapa.self_validating.SelfValidating.message=Validatable object couldn't be validated successfully.

Taking the calendar event example from the beginning, usage of the constraint might look as follows:

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
@SelfValidating
public class CalendarEvent implements Validatable {

    @NotNull
    private final String title;

    private final Date startDate;

    private final Date endDate;

    public CalendarEvent(String title, Date startDate, Date endDate) {

        this.title = title;
        this.startDate = startDate;
        this.endDate = endDate;
    }

    public boolean isValid() {
        return startDate == null || endDate == null || startDate.before(endDate);
    }

    @Override
    public String toString() {
        DateFormat format = new SimpleDateFormat("dd.MM.yyyy");

        return 
            title + 
            " from " +  (startDate == null ? "-" : format.format(startDate)) + 
            " till " + (endDate == null ? "-" : format.format(endDate));
    }

}

A short unit test shows that the constraint works as expected:

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
public class SelfValidatingTest {

    private static Validator validator;

    private static Date startDate;

    private static Date endDate;

    @BeforeClass
    public static void setUpValidatorAndDates() {

        ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
        validator = validatorFactory.getValidator();

        startDate = new GregorianCalendar(2009, 8, 20).getTime();
        endDate = new GregorianCalendar(2009, 8, 21).getTime();
    }

    @Test
    public void calendarEventIsValidAsEndDateIsAfterStartDate() {

        CalendarEvent testEvent = 
            new CalendarEvent("Team meeting", startDate, endDate);

        assertTrue(validator.validate(testEvent).isEmpty());
    }

    @Test
    public void calendarEventIsInvalidAsEndDateIsBeforeStartDate() {

        CalendarEvent testEvent = 
            new CalendarEvent("Team meeting", endDate, startDate);

        Set<ConstraintViolation<CalendarEvent>> constraintViolations = 
            validator.validate(testEvent);
        assertEquals(1, constraintViolations.size());

        assertEquals(
            "Object couldn't be validated successfully.",
            constraintViolations.iterator().next().getMessage());
    }
}

This works like a charm, only the error message returned by the BV runtime is not yet very expressive. This can easily be solved, as the BV API allows to override error messages within constraint annotations:

1
2
3
4
@SelfValidating(message="{de.gmorling.moapa.self_validating.CalendarEvent.message}")
public class CalendarEvent implements Validatable {
    ...
}

Again we need an entry in ValidationMessages.properties for the specified message key:

1
de.gmorling.moapa.self_validating.CalendarEvent.message=End date of event must be after start date.

Conclusion

Providing dedicated class-level constraints for all business objects that require some sort of cross-field validation logic can be quite a tedious task as you need to create an annotation type, a validator implementation and an error message text.

The @SelfValidating constraint reduces the required work by letting business objects validate themselves. That way all you have to do is implement the Validatable interface, annotate your class with @SelfValidating and optionally provide a customized error message. Furthermore business objects are not required to expose their internal state to make it accessible for an external validator implementation.

The complete source code can be found in my GitHub repository. As always I'd be happy about any feedback.

Saturday, February 6, 2010

Bookmark and Share

JAX-WS as Java's standard API for web services comes with a close integration of JAXB as XML binding framework. More precisely JAXB is actually the only binding technology directly supported by JAX-WS. As JAXB basically does its job pretty well, that's nothing bad per se.

Nevertheless there might be situations where you would like to integrate JAX-WS with other XML binding solutions such as Apache XmlBeans.

For instance you might have used another web service stack and binding framework in the past and now want to migrate your services to JAX-WS. Depending on the number of services, changing your XML binding framework can create quite a lot of work, as you have to rewrite the mapping code which converts between the types generated by the binding framework and your domain objects.

Provider-based endpoints

The key idea for integrating JAX-WS with another binding framework is to create a Provider based endpoint for your web service. Contrary to standard SEI (service endpoint interface) implementations, which solely operate on JAXB generated classes, a provider endpoint has access to the raw XML of incoming and outgoing messages.

That way you can take care of XML marshalling yourself, e.g. by converting incoming XML messages into their corresponding XmlBeans types and the other way around.

In the following a web service for a video rental store shall be built. The service has a single operation, getMovieById, with request and response types in an accompanying XML schema (the service's WSDL and all other sources for this post can be found in my Git repository):

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
<?xml version="1.0" encoding="UTF-8"?>
<schema 
    targetNamespace="http://www.gunnarmorling.de/moapa/videorental/types"
    xmlns="http://www.w3.org/2001/XMLSchema"
    xmlns:videorental="http://www.gunnarmorling.de/moapa/videorental/types">

    <element name="GetMovieByIdRequest" type="videorental:GetMovieByIdRequest" />
    <element name="GetMovieByIdResponse" type="videorental:GetMovieByIdResponse" />

    <complexType name="GetMovieByIdRequest">
        <sequence>
            <element name="Id" type="long" />
        </sequence>
    </complexType>

    <complexType name="GetMovieByIdResponse">
        <sequence>
            <element type="videorental:Movie" name="Movie" minOccurs="0" />
        </sequence>
    </complexType>

    <complexType name="Movie">
        <sequence>
            <element name="Id" type="long" />
            <element name="Title" type="string" />
            <element name="RunTime" type="int" />
        </sequence>
    </complexType>
</schema>

XmlBeans will generate two document types for the elements (GetMovieByIdRequestDocument, GetMovieByIdResponseDocument) as well as types for each of the complex types.

For the service implementation I recommend to work only with the classes representing the complex types (instead of the document types). An interface representing the service's port type and its implementation therefore might look like this:

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
public interface VideoRentalPortType {

    public GetMovieByIdResponse getMovieById(GetMovieByIdRequest request);

}

...

public class VideoRentalPort implements VideoRentalPortType {

    private MovieRepository movieRepository = new MovieRepositoryMockImpl();

    public GetMovieByIdResponse getMovieById(GetMovieByIdRequest request) {

        GetMovieByIdResponse response = GetMovieByIdResponse.Factory.newInstance();

        de.gmorling.moapa.videorental.domain.Movie movie = movieRepository.getMovieById(request.getId());

        if(movie != null) {
            response.setMovie(convert(movie));
        }       

        return response;
    }

    private Movie convert(de.gmorling.moapa.videorental.domain.Movie movie) {

        Movie theValue = Movie.Factory.newInstance();

        theValue.setId(movie.getId());
        theValue.setTitle(movie.getTitle());
        theValue.setRunTime(movie.getRunTime());

        return theValue;
    }
}

This looks pretty similar to a typical SEI-based implementation. The only difference is, that the types in use are generated by XmlBeans instead of JAXB. The implementation is straight forward. It takes the movie id from the incoming request, invokes some backend business service and creates a GetMovieByIdResponse from the result.

Next we need to create the actual Provider implementation which will be called by the JAX-WS runtime, whenever the service is invoked:

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
44
@WebServiceProvider
@ServiceMode(value=Mode.MESSAGE)
public class VideoRentalProvider implements Provider<SOAPMessage> {

    private VideoRentalPortType videoRentalPort = new VideoRentalPort();

    public SOAPMessage invoke(SOAPMessage request) {

        try {

            Node root = request.getSOAPBody().getFirstChild();

            if(root.getNodeName().contains(GetMovieByIdRequest.class.getSimpleName())) {

                GetMovieByIdRequestDocument requestDocument = GetMovieByIdRequestDocument.Factory.parse(root);
                GetMovieByIdResponseDocument responseDocument = GetMovieByIdResponseDocument.Factory.newInstance();
                responseDocument.setGetMovieByIdResponse(videoRentalPort.getMovieById(requestDocument.getGetMovieByIdRequest()));

                return createSOAPMessage(responseDocument);
            }
            else {
                throw new UnsupportedOperationException();
            }
        }
        catch(Exception e) {
            throw new RuntimeException(e);
        }
    }

    private SOAPMessage createSOAPMessage(XmlObject responseDocument) {

        try {

            SOAPMessage message = MessageFactory.newInstance().createMessage();
            Node node = message.getSOAPBody().getOwnerDocument().importNode(responseDocument.getDomNode().getFirstChild(), true);
            message.getSOAPBody().appendChild(node);
            return message;
        }
        catch(Exception e) {
            throw new RuntimeException(e);
        }
    }

}

A provider implementation must be annotated with @WebServiceProvider. By binding the type parameter to SOAPMessage (a comparison with the alternatives Source and DataSource can be found here) and specifying Mode.MESSAGE within the @ServiceMode annotation we achieve, that we can access complete SOAP messages within the implementation.

The Provider interface defines only one method, invoke(). This method is called whenever any of the service's operations is invoked. Therefore we first have to determine the currently invoked operation, which can be done by peeking at the node name of the first body element.

In case of the getMovieById operation then a GetMovieByIdRequestDocument instance representing the contents of the message body is created using a XmlBeans-generated factory class. From that document we retrieve the actual request element and pass it to the port implementation.

The result is put into a new GetMovieByIdResponseDocument instance, which itself is finally wrapped into a SOAPMessage by importing the root DOM node into the message body.

Conclusion

Creating Provider-based endpoints makes it possible to use JAX-WS together with binding frameworks other than JAXB. Whether it should be done depends as always on the specific circumstances.

For new projects working with SEI endpoints and therefore JAXB should be preferred. The JAX-WS tooling will smoothly generate JAXB binding classes as well as port type interfaces, making the creation of new web services pretty simple.

In migration scenarios things can be different though. Re-writing a whole lot of mapping code originally created for another binding framework such as XmlBeans can be quite a time-consuming and error-prone task. In that case implementing Provider-based services can be an interesting alternative.

When pursuing that approach some performance tests should be executed first. A short load test on my machine didn't show significant execution time differences between JAXB/XmlBeans for the video rental service. But things might look different for larger message types due to the involved DOM manipulations.

Sunday, January 17, 2010

Bookmark and Share

In his excellent book "Effective Java (2nd edition)" Joshua Bloch describes a variation of the Builder design pattern for instantiating objects with multiple optional attributes.

Sticking to this pattern frees you from providing multiple constructors with the different optional attributes as parameters (hard to maintain and hard to read for clients) or providing setter methods for the optional attributes (require objects to be mutable, can leave objects in inconsistent state).

As Bloch points out, it's a very good idea to check any invariants applying to the object to be created within the builder's build() method. That way it is ensured, that clients can only retrieve valid object instances from the builder.

If you are using the Bean Validation API (JSR 303) to define constraints for your object model, this can be realized by validating these constraints within the build() method.

The following listing shows an example:

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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
public class Customer {

    private long id;
    private String firstName;
    private String lastName;
    private Date birthday;

    private Customer(Builder builder) {

        this.id = builder.id;
        this.firstName = builder.firstName;
        this.lastName = builder.lastName;
        this.birthday = builder.birthday;
    }

    public static class Builder {

        private static Validator validator = 
            Validation.buildDefaultValidatorFactory().getValidator();

        private long id;
        private String firstName;
        private String lastName;
        private Date birthday;

        public Builder(long id, String lastName) {
            this.id = id;
            this.lastName = lastName;
        }

        public Builder firstName(String firstName) {
            this.firstName = firstName;
            return this;
        }

        public Builder birthday(Date birthday) {
            this.birthday = birthday;
            return this;
        }

        public Customer build() throws ConstraintViolationException {

            Customer customer = new Customer(this);
            Set<ConstraintViolation<Customer>> violations = 
                validator.validate(customer);

            if (!violations.isEmpty()) {
                throw new ConstraintViolationException(
                    new HashSet<ConstraintViolation<?>>(violations));
            }

            return customer;
        }
    }

    @Min(1)
    public long getId() {
        return id;
    }

    @Size(min = 3, max = 80)
    public String getFirstName() {
        return firstName;
    }

    @Size(min = 3, max = 80)
    @NotNull
    public String getLastName() {
        return lastName;
    }

    @Past
    public Date getBirthday() {
        return birthday;
    }

}

The listing shows an exemplary model class Customer for which some invariants apply (e.g. a customer's last name must not be null and must be between 3 and 80 characters long). These invariants are expressed using constraint annotations from the Bean Validation API at the getter methods of the Customer class.

The inner class Builder is in charge of creating Customer instances. All mandatory fields – either primitive (e.g. id) or annotated with @NotNull (e.g. lastName) – are part of the builder's constructor. For all optional fields setter methods on the builder are provided.

Within the build() method the newly created Customer instance is validated using the Validator#validate() method. If any constraint violations occur, a ConstraintViolationException is thrown. That way it's impossible to retrieve an invalid Customer instance. The following unit test shows an example:

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
public class CustomerTest {

    @Test
    public void validCustomer() {
        Customer c = 
            new Customer.Builder(1, "Smith")
                .firstName("Bob")
                .birthday(new GregorianCalendar(1970, 3, 10).getTime())
                .build();

        assertNotNull(c);
    }

    @Test
    public void lastNameNullAndBirthdayInFuture() {
        try {
            new Customer.Builder(1, null)
                .birthday(new GregorianCalendar(2020, 3, 10).getTime())
                .build();
            fail("Expected ConstraintViolationException wasn't thrown.");
        }
        catch (ConstraintViolationException e) {
            assertEquals(2, e.getConstraintViolations().size());
        }
    }
}

If there are multiple classes for which you want to provide a builder in the described way, it is useful to extract the validation routine into a base class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public abstract class AbstractBuilder<T> {

    private static Validator validator = 
        Validation.buildDefaultValidatorFactory().getValidator();

    protected abstract T buildInternal();

    public T build() throws ConstraintViolationException {

        T object = buildInternal();

        Set<ConstraintViolation<T>> violations = validator.validate(object);
        if (!violations.isEmpty()) {
            throw new ConstraintViolationException(
                new HashSet<ConstraintViolation<?>>(violations));
        }

        return object;
    }
}

Concrete builder classes have to extend AbstractBuilder and must implement the buildInternal() method:

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
...
public static class Builder extends AbstractBuilder<Customer> {

    private long id;
    private String firstName;
    private String lastName;
    private Date birthday;

    public Builder(long id, String lastName) {
        this.id = id;
        this.lastName = lastName;
    }

    public Builder firstName(String firstName) {
        this.firstName = firstName;
        return this;
    }

    public Builder birthday(Date birthday) {
        this.birthday = birthday;
        return this;
    }

    @Override
    protected Customer buildInternal() {
        return new Customer(this);
    }
}
...

The complete source code for this post can be found in my Git repository over at github.com.

Wednesday, January 6, 2010

Bookmark and Share

Version 2 of the Java Persistence API (JPA) comes with an out-of-the-box integration of the Bean Validation API (BV). If a BV implementation is found in the runtime environment, any BV constraints placed at JPA entities will be validated whenever an entity is written to the database. In the following I'm going to show how the both APIs play together.

Project setup

Assuming you are working with Apache Maven, begin by adding the following repositories to your settings.xml or the pom.xml of your project:

1
2
3
4
5
6
7
8
9
10
...
<repository>
    <id>JBoss Repo</id>
    <url>http://repository.jboss.com/maven2</url>
</repository>
<repository>
    <id>EclipseLink Repo</id>
    <url>http://www.eclipse.org/downloads/download.php?r=1&nf=1&file=/rt/eclipselink/maven.repo</url>
</repository>   
...

In order to use the reference implementations of both APIs (EclipseLink resp. Hibernate Validator) add the following dependencies to you pom.xml:

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
...
<!-- JPA API and RI -->
<dependency>
    <groupId>javax.persistence</groupId>
    <artifactId>javax.persistence</artifactId>
    <version>2.0-SNAPSHOT</version>
    <scope>compile</scope>
</dependency>
<dependency>
    <groupId>org.eclipse.persistence</groupId>
    <artifactId>eclipselink</artifactId>
    <version>2.0.0</version>
    <scope>runtime</scope>
</dependency>
...
<!-- Bean Validation API and RI -->
<dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <version>1.0.0.GA</version>
    <scope>compile</scope>
</dependency>
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>4.0.2.GA</version>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-jdk14</artifactId>
    <version>1.5.6</version>
    <scope>runtime</scope>
</dependency>
...

Instead of EclipseLink you might also use Hibernate 3.5 (currently beta) as JPA provider:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
...
<dependency>
    <groupId>org.hibernate.java-persistence</groupId>
    <artifactId>jpa-api</artifactId>
    <version>2.0-cr-1</version>
    <scope>compile</scope>
</dependency>
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-entitymanager</artifactId>
    <version>3.5.0-Beta-2</version>
    <scope>runtime</scope>
</dependency>
...

Finally we need a database to execute some unit tests against it. I recommend using Apache Derby as it provides an in-memory mode, which is perfectly suited for unit tests:

1
2
3
4
5
6
7
8
...
<dependency>
    <groupId>org.apache.derby</groupId>
    <artifactId>derby</artifactId>
    <version>10.5.3.0_1</version>
    <scope>test</scope>
</dependency>
...

The model class

Now let's create a simple model class. It's just a POJO with some annotations stemming from JPA (@Entity, @Id etc.) and some from Bean Validation (@NotNull, @Size):

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
@Entity
@NamedQueries( { @NamedQuery(name = Customer.FIND_ALL_CUSTOMERS, query = "SELECT c FROM Customer c") })
public class Customer {

    public final static String FIND_ALL_CUSTOMERS = "findAllCustomers";

    @Id
    @GeneratedValue
    @NotNull
    private Long id;

    @NotNull
    @Size(min = 3, max = 80)
    private String name;

    private boolean archived;

    public Customer() {

    }

    public Customer(String name) {
        this.name = name;
        archived = false;
    }

    //getters and setters ...

}

Configuration

Next we have to setup the file persistence.xml which defines the persistence unit to be used for our module tests:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?xml version="1.0" encoding="UTF-8"?>
<persistence 
    xmlns="http://java.sun.com/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
    version="2.0">

    <persistence-unit name="testPU" transaction-type="RESOURCE_LOCAL">

        <class>de.gmorling.jpa2.model.Customer</class>

        <properties>
            <property name="eclipselink.target-database" value="DERBY" />
            <property name="eclipselink.ddl-generation" value="create-tables" />
            <property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver" />
            <property name="javax.persistence.jdbc.url" value="jdbc:derby:memory:testDB;create=true" />
            <property name="javax.persistence.jdbc.user" value="APP" />
            <property name="javax.persistence.jdbc.password" value="APP" />
        </properties>
    </persistence-unit>
</persistence>

JPA 2 standardizes the property names for driver, user etc. When working with EclipseLink therefore only two provider-specific properties for the target database and the DDL strategy are required.

Using Hibernate the properties would look like the following (at the time of writing this post the standard properties don't seem to be supported yet by Hibernate):

1
2
3
4
5
6
7
8
...
<property name="hibernate.dialect" value="org.hibernate.dialect.DerbyDialect" />
<property name="hibernate.hbm2ddl.auto" value="create" />
<property name="hibernate.connection.driver_class" value="org.apache.derby.jdbc.EmbeddedDriver" />
<property name="hibernate.connection.username" value="APP" />
<property name="hibernate.connection.password" value="APP" />
<property name="hibernate.connection.url" value="jdbc:derby:memory:testDB;create=true" />
...

Note that not a single line of configuration is required to enable the Bean Validation integration, it's working out of the box. If JPA detects a BV implementation on the classpath, it will use it by default to validate any BV constraints, whenever an entity is persisted or updated.

And action ...

To try that, let's write a simple unit test for our model class:

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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
public class CustomerTest {

    private static EntityManagerFactory emf;

    private EntityManager em;

    @BeforeClass
    public static void createEntityManagerFactory() {
        emf = Persistence.createEntityManagerFactory("testPU");
    }

    @AfterClass
    public static void closeEntityManagerFactory() {
        emf.close();
    }

    @Before
    public void beginTransaction() {
        em = emf.createEntityManager();
        em.getTransaction().begin();
    }

    @After
    public void rollbackTransaction() {

        if (em.getTransaction().isActive())
            em.getTransaction().rollback();

        if (em.isOpen())
            em.close();
    }

    @Test
    public void nameTooShort() {

        try {
            Customer customer = new Customer("Bo");
            em.persist(customer);
            fail("Expected ConstraintViolationException wasn't thrown.");
        } 
        catch (ConstraintViolationException e) {
            assertEquals(1, e.getConstraintViolations().size());
            ConstraintViolation<?> violation = 
                e.getConstraintViolations().iterator().next();

            assertEquals("name", violation.getPropertyPath().toString());
            assertEquals(
                Size.class, 
                violation.getConstraintDescriptor().getAnnotation().annotationType());
        }
    }

    @Test
    public void validCustomer() {

        Customer customer = new Customer("Bob");
        em.persist(customer);

        Query query = em.createNamedQuery(Customer.FIND_ALL_CUSTOMERS);

        assertEquals(1, query.getResultList().size());
    }
}

The first four methods are just for setting up resp. closing down an entity manager factory for our persistence unit as well as the entity manager to be used.

In the test method nameTooShort() a ConstraintViolationException is raised, as the @Size constraint of the "name" attribute isn't fulfilled. The method validCustomer() on the other hand shows how a valid Customer instance is persisted and successfully retrieved later on.

Specifying validation groups

By default the constraint annotations of the Default validation group are validated upon inserting a new entity. The same holds true when an existing entity is updated, while no validation takes place by default if an entity is deleted.

If needed this behavior can be overridden by specifying the following properties in the persistence.xml (where values must be comma separated lists of fully-qualified class names of the groups to be validated):

1
2
3
javax.persistence.validation.group.pre-persist
javax.persistence.validation.group.pre-update
javax.persistence.validation.group.pre-remove

Let's assume for example that when a customer account is closed the concerned record from the Customer table is moved to some kind of archive storage. For all migrated records the "archived" flag should be set to true. Using a constraint annotation we would like to ensure now, that only archived Customer records are allowed to be deleted.

To do so we first define a new validation group by declaring an empty interface:

1
public interface DeletionAttributes {}

Now we add an @AssertTrue constraint to the "archived" attribute, which is part of this validation group:

1
2
3
4
5
6
7
public class Customer {

    ...
    @AssertTrue(groups = DeletionAttributes.class)
    private boolean archived;
    ...
}

Then we specify that constraints of the DeletionAttributes group shall be evaluated upon entity removal:

1
2
3
...
<property name="javax.persistence.validation.group.pre-remove" value="de.gmorling.jpa2.model.DeletionAttributes" />
...

As an unit test shows, a ConstraintViolationException will be raised now, if we try to delete a non-archived customer:

1
2
3
4
5
6
7
8
...
@Test(expected = ConstraintViolationException.class)
public void nonArchivedCustomerDeleted() {

    Customer customer = new Customer("Bob");
    em.persist(customer);
    em.remove(customer);
}...

But everything will be fine, if an archived customer gets deleted:

1
2
3
4
5
6
7
8
9
10
11
12
13
...
@Test
public void archivedCustomerDeleted() {

    Customer customer = new Customer("Bob");
    em.persist(customer);

    customer.setArchived(true);
    em.remove(customer);
    assertTrue(
        em.createNamedQuery(Customer.FIND_ALL_CUSTOMERS).getResultList().isEmpty());
}
...

Specifying the validation groups to be evaluated allows a very fine-grained configuration of the constraint checking process. But there might also be situations where you don't want any validation to take place at all. In that case the validation can be turned off completely by setting the validation mode to "NONE" within your persistence.xml:

1
2
3
4
5
6
...
<persistence-unit name="testPU" transaction-type="RESOURCE_LOCAL">
    <validation-mode>NONE</validation-mode> 
    ...
</persistence-unit>
...

Conclusion

As this post shows, JPA and BV API are integrated very well. Validating your entities before they are written to the database is a very powerful tool for improving data quality, as it ensures that all your persisted data adheres to the constraints of your object model.

I really recommend you to try it out yourself and of course I would be very happy on any feedback.

Sunday, January 3, 2010

Bookmark and Share

2009 was my first complete year of blogging, so I thought it might be the right time to present some statistics of the last 12 months:

  • 17,738 visits total
  • 25,394 page views total
  • best month: March (1,958 visits)
  • best day: March, 13 th (335 visits due to the Adam Bien effect ;-))

These were the most visited posts:

The visitors came from 118 different countries, the top 5 being:

  • United States: 26.18%
  • Germany: 14.95%
  • United Kingdom: 7.00%
  • France 4.71%
  • India: 3.00%

Thank you all for reading and commenting. Stay tuned :-)