Effective pattern for data access with JPA

Posted: May 5th, 2011 | Author: | 4 Comments »

Since Java EE 6 is out, many of patterns and blueprints that were described with J2EE are deprecated. The main reason is due to the new architecture offers new components that simplify the development. One of these components is EntityManager, which can be consider as the implementation of DAO pattern. This object provides us common functions to operate with our model in a relational database. Some of these functions are save, retrieve, update and delete entities, that is, tipical CRUD operations.

Where is the problem?

It all depends on how you layerizer your application. Many of code that you can see about data access with JPA uses the EntityManager injected directly in the business objects or web controllers. In my opinion, with this approach couples too much the business logic with the technology used in the persistence layer. Think for a moment that an entire application developed by using this way has serious performance problems and the reponsible determines to move the persistence layer to NoSql approach, this decision would mean having to change this reference from every class. As you can see, it would mean an unbelievable effort.

Creating the indirection

First of all, the idea of using a facade to access JPA looks mandatory if we want to uncouple the technology with the data access. In this line, the next interface is proposed:

public interface PersistenceService<K, E> {

	E save(E entity);

	E update(E entity);

	void remove(E entity);

	E findById(K id);

	List<E> findAll();

	Long getTotalResult();
}

By using Java Generics this interface provides the common operation with entities. Each class that implements this interface have to indicate what the type of entity it manages E and the type of identificator K. Obviously, this class will have to implement the methods too :D

Now, we have to define abstract classes either for the entities or for persistence services. These abstract classes help us to put in the same location all the common code, leaving the concrete classes that they implements only the specific code.

In JPA to model entities, we need a classes with Entity annotation, but there is some code that is mandatory in each entity, for example the identificator. In addition, we use named queries for those queries that are typical in any scenario, so the entities need the constants for these named queries. The abstract entity is as follow:

@MappedSuperclass
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class AbstractEntity implements Serializable {

    public static final String FIND_ALL = "Entity.findAll";

    public static final String TOTAL_RESULT = "Entity.totalResult";

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    protected Long id;

    // Getters and Setters
}

With @MappedSuperclass and @Inheritance we indicates that this class doesn’t have to be mapped to a table and the constants will be used in the named queries. Due to JPA 2.0 doesn’t allow inheritance for named queries, these two queries will be defined in each specific entity.

Now, the code for the abstract persistence service. This class performs the CRUD operations through the EntityManager. The code is:

public abstract class AbstractJPAPersistenceService<K, E extends AbstractEntity> implements PersistenceService<K, E> {

    protected Class<E> entityClass;

    @PersistenceContext
    protected EntityManager em;

    @PostConstruct
    public void init() {
        ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass();
        this.entityClass = (Class<E>) genericSuperclass.getActualTypeArguments()[1];
    }

    @Override
    public E save(final E entity) {
        em.persist(entity);
        return entity;
    }

    @Override
    public E update(final E entity) {
        return em.merge(entity);
    }

    @Override
    public void remove(final E entity) {
        em.remove(em.merge(entity));
    }

    @Override
    public E findById(final K id) {
        return em.find(entityClass, id);
    }

    @Override
    public List<E> findAll() {
        return em.createNamedQuery(AbstractEntity.FIND_ALL).getResultList();
    }

    @Override
    public Long getTotalResult() {
        return (Long) em.createNamedQuery(AbstractEntity.TOTAL_RESULT).getSingleResult();
    }

}

With this class, each subclass just implements its specific method for queries. Perhaps, the most important part is in the method init() where the entity class is created by using reflection through generic values. Due to the idea is to expose the persistence services as EJB, this method is annotated with @PostConstruct that is called each time its subclass is injected. Furthermore, the queries are implemented with the constants declared in the AbstractEntity, the query will be defined in the specific entity.

Implementing an example

Ok, the skeleton for persistence services is ready, just need to use in a real scenario. In this case, to show how easy it is to use this “pattern”, the example is about the Book entity.

@Entity
@NamedQueries({
    @NamedQuery(name = Book.FIND_ALL, query = "select b from Book b"),
    @NamedQuery(name = Book.TOTAL_RESULT, query = "select count(b) from Book b"),
    @NamedQuery(name = Book.FIND_BY_TITLE, query = "select b from Book b where b.title = :title"),
    @NamedQuery(name = Book.FIND_BY_ISBN, query = "select b from Book b where b.isbn = :isbn")
})
public class Book extends AbstractEntity {

    public static final String FIND_BY_TITLE = "Book.findByTitle";

    public static final String FIND_BY_ISBN = "Book.findByISBN";

    private String title;

    private String description;

    private String isbn;

    // Getters and Setters

The code is quite basic: declaration of attributes (fields in the table), specific queries and named queries with @NamedQueries.

Finally, the implementation of PersistenceService to manage books is as follow:

@Stateless
public class BookPersistenceService extends AbstractJPAPersistenceService<Long, Book> {

    public List<Book> findByTitle(String title) {
        return em.createNamedQuery(Book.FIND_BY_TITLE).setParameter("title", title).getResultList();
    }

    public List<Book> findByISBN(String isbn) {
        return em.createNamedQuery(Book.FIND_BY_ISBN).setParameter("isbn", isbn).getResultList();
    }
}

As you can see, the code is very light because the complexity is in AbstractJPAPersistenceService. To use this service, just inject it in your business logic.


Tags: , , , ,

Custom constraints with Bean Validation

Posted: February 28th, 2011 | Author: | No Comments »

One of the more interesting components that Java EE 6 brings us is Bean Validation JSR-303, which helps you to define constraints on your model making possible to divide the model validation and the business logic. Besides, this component can be used in any layer you are working, for instance, JSF uses Bean Validation to validate the data in a web forms and JPA uses to validate data before storing the entity in the database.

The specification comes with some validations that you can use directly by using their annotations: @NotNull, @Min, @Max, @Pattern, etc. Despite these annotations are very useful, they don’t cover all your model constraints and sometimes it’s necessary to define custom constraints according to real world.

Creating custom constraints

Imagine you are developing a typical product order where you have two customer types (normal and premium) and two product types (normal and exclusive) and your model has the following constraint:

“Normal customer can buy two exclusive products in his order. On the other hand, premium customer doesn’t have any limitation about this.”

First of all, you have these entities of your model:

public class Product {

    public Product () { }

    public Product(String name, Integer cost, ProductType type) {
        this.name = name;
        this.cost = cost;
        this.type = type;
    }

    private String name;

    private Integer cost;

    private ProductType type;

    public enum ProductType { NORMAL, EXCLUSIVE };

    // Getters and Setters

}

public class Order {

    public Order() { }

    public Order(Customer customer) {
        this.customer = customer;
    }

    private List<OrderLine> lines = new LinkedList<OrderLine>();

    private Customer customer;

    // Getters and Setters

}

public class OrderLine {

    public OrderLine() { }

    public OrderLine (Product product, Integer quantity){
        this.product = product;
        this.quantity = quantity;
    }

    private Product product;

    private Integer quantity;

    // Getters and Setters

}

Customer class will be defined soon. The next step is to create the annotation and put in the correct place. The annotation have to have the form:

@Retention(RUNTIME)
@Target({TYPE, FIELD, METHOD})
@Constraint(validatedBy = ExclusiveProductsValidator.class)
public @interface ExclusiveProducts {

    String message() default "Exclusive products constraint has been violated";

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

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

    int max() default 0;
}

The meaning of attributes are:

  • message – Indicates what is the message returned if the bean doesn’t satisfied the constraint. You can also use bundle JSF message here.
  • groups – Array of groups to filter the validating according a criteria.
  • payload – Indicates the severity of validation.
  • max – This attribute indicates the maximun quantity of exclusive products a customer can order, in this example, the value will be two.

It just need to know where to put this annotation. As you can think, constraint is associated to list of OrderLine in Order class, so this class would be as follows:

public class Order {

    // ...

    @ExclusiveProducts(max = 2)
    private List<OrderLine> lines = new LinkedList<OrderLine>();

    // ...
}

At this moment you are thinking “ok, I’ve created the annotation and I’ve put it in the bean, but where is the validation code?”. As you can see in the definition of annotation, it uses another annotation to declare what class should validate the bean, in this case this class is ExclusiveProductValidator. The code of this class is:

public class ExclusiveProductsValidator implements ConstraintValidator<ExclusiveProducts, List<OrderLine>> {

    int max;

    @Override
    public void initialize(ExclusiveProducts constraintAnnotation) {
        max = constraintAnnotation.max();
    }

    @Override
    public boolean isValid(List<OrderLine> value, ConstraintValidatorContext context) {
        int count = 0;
        for (OrderLine ol : value) {
            if (ol.getProduct().getType().equals(ProductType.EXCLUSIVE)) {
                count += ol.getQuantity();
            }
        }

        if (count > max) {
            return false;
        }

        return true;
    }
}

This code is easy, the methodinitialize simply stores the max value in an internal attribute and then with isValid validates the OrderLine list by returning false if the quantity of exclusive products is more than the value, otherwise returns true.

Validation groups

So far, the validation doesn’t distinguish between any kind of customer, and our requirement says that this restriction is only applied to normal customer. To this end, we need to create validation groups. Groups allow us to categorize beans to apply a kind of validation or another one, or apply a validation with different values depending the groups. To create a group, you need to declare an interface that extends Default and different subtypes.

public interface CustomerType extends Default { }

public interface NormalCustomer extends CustomerType { }

public interface PremiumCustomer extends CustomerType { }

At this point, the definition of Customer is very clear, this entity will have its own attributes (username, email, etc) and it have to indicate what kind of customer it is. An example of Customer is:

public class Customer {

    public Customer () { }

    public Customer(String username, Class<? extends CustomerType> type) {
        this.username = username;
        this.type = type;
    }

    private String username;

    private Class<? extends CustomerType> type;

    // Getters and Setters

}

And we have to rewrite the validation to use this feature:

public class Order {

    // ...

    @ExclusiveProducts(max = 2, groups = NormalCustomer.class)
    private List<OrderLine> lines = new LinkedList<OrderLine>();

    // ...
}

With this clause we are saying to Bean Validation that this constraints is just applied to order of normal customers.

Testing the constraint

The custom constraint is created and what you need is to know how to test this behaviour and how to validate beans. I’m going to use a simple test case by using JUnit like that:

public class ExclusiveProductValidationTest {

    private static Validator validator;
    private static Customer normalCustomer;
    private static Customer premiumCustomer;
    private static Product normalProduct;
    private static Product exclusiveProduct;

    @BeforeClass
    public static void setUpClass() throws Exception {
        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        validator = factory.getValidator();

        premiumCustomer = new Customer("usertest", PremiumCustomer.class);
        normalCustomer = new Customer("usertest", NormalCustomer.class);

        normalProduct = new Product("Normal product", 12, ProductType.NORMAL);
        exclusiveProduct = new Product("Exclusive product", 25, ProductType.EXCLUSIVE);
    }

    /**
     * Creating some order lines with 2 normal products and 2 exclusive products for
     * a normal customer. Validator shouldn't indicate any constraint violation.
     */
    @Test
    public void testWithTwoExclusiveProductsAndNormalCustomer() {

        OrderLine ol1 = new OrderLine(normalProduct, 2);
        OrderLine ol2 = new OrderLine(exclusiveProduct, 2);

        Order order = new Order(normalCustomer);
        order.getLines().add(ol1);
        order.getLines().add(ol2);

        Set<ConstraintViolation<Order>> violations = validator.validate(order, order.getCustomer().getType());
        assertEquals("It shouldn't have any violation in this case", 0, violations.size());

    }

    /**
     * Creating some order lines with 2 normal products and 3 exclusive products for
     * a normal customer. Validator should indicate the constraint violation.
     */
    @Test
    public void testWithThreeExclusiveProductsAndNormalCustomer() {

        OrderLine ol1 = new OrderLine(normalProduct, 2);
        OrderLine ol2 = new OrderLine(exclusiveProduct, 3);

        Order order = new Order(normalCustomer);
        order.getLines().add(ol1);
        order.getLines().add(ol2);

        Set<ConstraintViolation<Order>> violations = validator.validate(order, order.getCustomer().getType());
        assertEquals("It should have one violation in this case", 1, violations.size());
    }

    /**
     * Creating an order lines with 5 exclusive products for a premium customer.
     * Validator shouldn't indicate any constraint violation.
     */
    @Test
    public void testWithFewExclusiveProductsAndPremiumCustomer() {

        OrderLine ol = new OrderLine(exclusiveProduct, 5);

        Order order = new Order(premiumCustomer);
        order.getLines().add(ol);

        Set<ConstraintViolation<Order>> violations = validator.validate(order, order.getCustomer().getType());
        assertEquals("It shouldn't have any violation in this case", 0, violations.size());

    }
}

In setUpClass we create a validator through of ValidatorFactory, and we use this validator in each test. Remember that if you use Bean Validation in a JSF or JPA environment, the validation of your beans will be automatic and you won’t need an explicit validator (althought you can deactivate it and so, to have more control).


Tags: , ,