Platinum Partner
java,persistence,hades

DDD Specification Support in Hades

In the first part of this series on Hades I talked about queries and finder support.  In this article, I will talk about another useful feature of Hades called Specification. Specification is a Domain Driven Design concept wherein you define a Predicate to check whether an object matches or does not match a criteria. Hades provides Specification support in the form Specification interface which is a wrapper over JPA Criteria API. The Specification interface provides a callback method that gets CriteriaBuilder, CriteriaQuery<T> and Root<T> as its arguments and returns a Predicate.

public interface Specification<T> {

Predicate toPredicate(Root<T> root, CriteriaQuery<T> query,
CriteriaBuilder builder);
}

Hades GenericDao interface provides two methods with Specification support.

List<T> readAll(final Specification<T> spec); // return list of entities matching spec
Page<T> readAll(final Specification<T> spec, final Pageable pageable); // returns a Page of entities matching the spec

 

Specification offers :

  1. You can easily plug-in new matching strategies: Specification is a strategy interface so it is easy to plug-in new criteria without changing the API. So, you can add strategies like bookByAuthorName or bookWithPriceLessThan or bookByAuthorWithPriceInBetween very easily.
    public static Specification<Book> bookByAuthorName(final String value) {
    return new Specification<Book>() {

    public Predicate toPredicate(Root<Book> root, CriteriaQuery<Book> query, CriteriaBuilder builder) {
    return builder.equal(root.get("author"), value);
    }
    };
    }

    public static Specification<Book> withPriceBetween(final double start, final double end) {
    return new Specification<Book>() {

    public Predicate toPredicate(Root<Book> root, CriteriaQuery<Book> query, CriteriaBuilder builder) {
    return builder.between(root.<Double> get("price"), start, end);
    }
    };
    }
    and the client code
    @Test
    public void shouldFindBookByAuthorNameSpecification() throws Exception {
    List<Book> allBooks = bookDao.readAll(BookSpecifications.bookByAuthorName("shekhar"));
    assertThat(allBooks.size(), is(equalTo(1)));
    }
  2. You can avoid intermingling different entities: suppose that we want to find all the books written by a particular author and Author is an entity of our application. So, if we don't use Specification, we will have to add a method findAllBooksByAuthor(Author author). So, our Book domain dao is now tightly coupled with Author and as we keep adding different entities it all gets dirty. So, with the help of Specification we can avoid this mess.
  3. You can reduce boiler plate code : with Specification you don't have to worry about writing the boiler plate code of creating the CriteriaBuilderCriteriaQuery<T> and Root<T>. You get all this via callback.
  4. You can combine Specifications : One of the coolest thing about Specifications is that you can build complex specifications by joining different specifications together. Hades provides a utility class called Specifications which provides utility methods to combine Specification instances. For example
     public static Specification<Book> bookByAuthorAndPriceBetween(final String authorName, final double priceStart, final double priceEnd) {
    return where(bookByAuthorName(authorName)).and(withPriceBetween(priceStart, priceEnd));
    }


{{ tag }}, {{tag}},

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}
{{ parent.authors[0].realName || parent.author}}

{{ parent.authors[0].tagline || parent.tagline }}

{{ parent.views }} ViewsClicks
Tweet

{{parent.nComments}}