Volodymyr Bakhmatiuk Volodymyr Bakhmatiuk - 1 month ago 16
Java Question

Repository pattern benefits and Spring implementation

In the article Don’t use DAO, use Repository there is a pretty good explanation of the differences between DAO and repository patterns.

My brief retelling - DAO makes us to bloat interface with multiple methods, which obstruct changes and testing. In turn, repository encapsulate all customizations/changes with

query
method, which accept
Specification
as an argument. When you need a new behavior at repository - you shouldn't change it, instead create a new heir of
Specification
.

My conslusion - repository pattern is better than DAO due its interfaces are closed to modification.

Am I right so far? Haven't I missed some benefits of repository pattern?

BUT, if you'd look at Spring's accessing data JPA guide, you'll find the next code:

public interface CustomerRepository extends CrudRepository<Customer, Long> {
List<Customer> findByLastName(String lastName); //each time you need custom behavior you need to add a method
//...
}


Doesn't it conflict with the previous article? Why Spring's repository force us to add new methods to interface?

Answer

My conslusion - repository pattern is better than DAO due its interfaces are closed to modification

It depends on...
Because repository pattern is more complex since it requires more code to write and has a bigger level of abstraction than DAO pattern for both clients of repository and implementation of it.
When you need to have flexibility in your queries and/or your queries mix multiple entities in the result , repository pattern can address these needs. If you need to have mainly simple crud operations on a table (basic create, read, update and delete operations), I think that using a real repository (so with specifications) may be an overhead.

BUT, if you'd look at Spring's accessing data JPA guide, you'll find the next code:

 public interface CustomerRepository extends CrudRepository<Customer,Long> {
    List<Customer> findByLastName(String lastName); //each time you need custom behavior you need to add a method
     //... }

Doesn't it conflict with the previous article? Why Spring's repository force us to add new methods to interface?

Yes. I think that the problem comes from Spring which uses a fashion term (repository) to stand for a class which is not a repository according to pattern literature. (http://martinfowler.com/eaaCatalog/repository.html)
I think you should consider Spring Repository as DAO since the base functional interface of Spring repository is CrudRepository. And by nature CRUD operations are operations we find in a DAO...

After, nothing prevents you from enriching the repository to provide repository methods with Spring specifications as in the 2.4 point of the official documentation of Spring data.
Spring proposes you to extend the org.springframework.data.repository.CrudRepository interface as in your example. It is the easier way of doing and I imagine it is the most common way of doing...

public interface CustomerRepository extends CrudRepository<Customer, Long>, JpaSpecificationExecutor {
 …
}

And JpaSpecificationExecutor provides methods which use specifications and therefore promote the reduction of duplicate processings in queries source code :

/*
 * Copyright 2008-2011 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.springframework.data.jpa.repository;

import java.util.List;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;

/**
 * Interface to allow execution of {@link Specification}s based on the JPA criteria API.
 * 
 * @author Oliver Gierke
 */
public interface JpaSpecificationExecutor<T> {

    /**
     * Returns a single entity matching the given {@link Specification}.
     * 
     * @param spec
     * @return
     */
    T findOne(Specification<T> spec);

    /**
     * Returns all entities matching the given {@link Specification}.
     * 
     * @param spec
     * @return
     */
    List<T> findAll(Specification<T> spec);

    /**
     * Returns a {@link Page} of entities matching the given {@link Specification}.
     * 
     * @param spec
     * @param pageable
     * @return
     */
    Page<T> findAll(Specification<T> spec, Pageable pageable);

    /**
     * Returns all entities matching the given {@link Specification} and {@link Sort}.
     * 
     * @param spec
     * @param sort
     * @return
     */
    List<T> findAll(Specification<T> spec, Sort sort);

    /**
     * Returns the number of instances that the given {@link Specification} will return.
     * 
     * @param spec the {@link Specification} to count instances for
     * @return the number of instances
     */
    long count(Specification<T> spec);
}

But I think that it will create the Frankenstein creature : half DAO, half repository.

The other solution is implementing directly the base and marker interface : org.springframework.data.repository.Repository and the JpaSpecificationExecutor interface like that :

public interface CustomerRepository extends Repository<Customer, Long>, JpaSpecificationExecutor {
 …
}

In this way, you could have a real repository, with only specification methods.
I don't know if it works. I never tried that.

Edit : response to comment

Repository pattern is a concept that Hibernate doesn't provide with an out of box solution.
But Hibernate and more generally the JPA 2 specification provide indeed Criteria as basic ingredient to create specifications as classes.
You can then create a custom class which implements the Repository pattern by proposing required methods with specifications as input. I think you can use ORM and repositories since you can use ORM with specifications by using criteria API. Some people oppose ORM and Repository and I disagree. ORM is not based on DAO pattern. DAO is the way to manipulate data in database. ORM is the way to structure data objects to represent database structures. For example, by using both, you can benefit both from the flexibility of specifications and the power of relational-object mapping and of the weaving between entities.
If you don't use ORM or ORM like as IBatis, you should code yourself what ORM offers to you : the object relational mapping.

Comments