Specification using JPA 2.0 Criteria API – Source Code

11 07 2011

In my previous article I showed how to create composed specifications using the JPA 2.0 Criteria API. This article shows the source code of the Specification interface and the core components (including boolean operators).

We first start with the Specification interface:

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

/**
* <code>Specification</code> is used to test an object to see if it satisfies
* a certain criteria.
*
* @author had
* @author http://dddsample.sourceforge.net/
*
* @param  The type of the object to test.
*/
public interface Specification {
  /**
  * Tests the specified <code>candidate</code> if it satisfies the criteria
  * of this specification.
  * @param candidate The object to test.
  * @return <code>true</code> if <code>testObject</code> satisfies the
  * criteria of this specification, <code>false</code> otherwise.
  */
  boolean isSatisfiedBy(T candidate);

  /**
  * Transforms this specification into a predicate. (optional)
  * @param cb The criteria builder to use, must not be null.
  * @param query The query object to use, must not be null.
  * @param root The starting point, must not be null.
  * @return The created predicate which checks the rules.
  * @throws UnsupportedOperationException If this specification does not
  *  support predicate transformation.
  */
  Predicate toPredicate(CriteriaBuilder cb, CriteriaQuery query, Root root) throws UnsupportedOperationException;

  Specification and(Specification other);

  Specification or(Specification other);

  Specification not();
}

Based on the ideas published by Eric Evans (author of the book “Domain Driven Design”), this interface contains the following methods:

  • isSatisfiedBy – to check an in-memory object if it satisifies the specification
  • and, or, not – for boolean operations on the specification

The interface above has an additional method called toPredicate. This method transforms the (business-driven) intention of the specification into a Predicate which is used to fetch all persisted objects satisfying the specification – one important aspect of the Specification concept. The Predicate interface is defined by the JPA 2.0 Criteria API and can be used to build dynamic queries using predicates (as shown in the previous article).

An abstract specification implements the Specification interface as follows:

public abstract class AbstractSpecification<T> implements Specification<T> {
  @Override
  public Specification<T> and(Specification<T> other) {
    return new AndSpecification<T>(this, other);
  }

  @Override
  public Specification<T> or(Specification<T> other) {
    return new OrSpecification<T>(this, other);
  }

  @Override
  public Specification<T> not() {
    return new NotSpecification<T>(this);
  }
}

Last but not least, we need common implementations for the boolean operators:

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

public class AndSpecification<T> extends AbstractSpecification<T> {
  private final Specification<T> a;
  private final Specification<T> b;
	
  public AndSpecification(Specification<T> a, Specification<T> b) {
    this.a = a;
    this.b = b;
  }
	
  @Override
  public boolean isSatisfiedBy(T candidate) {
    return a.isSatisfiedBy(candidate) && b.isSatisfiedBy(candidate);
  }

  @Override
  public Predicate toPredicate(CriteriaBuilder cb, CriteriaQuery<T> query, Root<T> root) throws UnsupportedOperationException {
    return cb.and(a.toPredicate(cb, query, root), b.toPredicate(cb, query, root));
  }
}

One can easily imagine, how the OrSpecification and the NotSpecification look like.

Advertisement

Actions

Information

One response

12 07 2011
shay

great addition !!

thank you,
Shay

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s




Follow

Get every new post delivered to your Inbox.