Spring Data JPA: Implementing Custom Repository Behavior with Specifications

I would like to create a Spring Data JPA repository with custom behavior, and implement that custom behavior using Specifications. I have gone through the Spring Data JPA documentation for implementing custom behavior in a single repository to set this up, except there is no example of using a Spring Data Specification from within a custom repository. How would one do this, if even possible?

I do not see a way to inject something into the custom implementation that takes a specification. I thought I would be tricky and inject the CRUD repository portion of the repository into the custom portion, but that results in a circular instantiation dependency.

I am not using QueryDSL. Thanks.


I guess the primary source for inspiration could be how SimpleJpaRepository handles specifications. The key spots to have a look at are:

  • SimpleJpaRepository.getQuery(…) - it's basically creating a CriteriaQuery and bootstraps a select using a JPA Root . Whether the latter applies to your use case is already up to you. I think the former will apply definitely.
  • SimpleJpaRepository.applySpecificationToCriteria(…) - it basically uses the artifacts produced in getQuery(…) (ie the Root and the CriteriaQuery ) and applies the given Specification to exactly these artifacts.

  • this is not using Specification, so not sure if it's relevant to you, but one way that I was able to inject custom behavior is as follows,

  • Basic structure: as follows

    i. create a generic interface for the set of entity classes which are modeled after a generic parent entity. Note, this is optional. In my case I had a need for this hierarchy, but it's not necessary

    public interface GenericRepository<T> {
    
    // add any common methods to your entity hierarchy objects, 
    // so that you don't have to repeat them in each of the children entities
    // since you will be extending from this interface
    }
    

    ii. Extend a specific repository from generic (step 1) and JPARepository as

    public interface MySpecificEntityRepository extends GenericRepository<MySpecificEntity>, JpaRepository<MySpecificEntity, Long> {
    
    // add all methods based on column names, entity graphs or JPQL that you would like to 
    // have here in addition to what's offered by JpaRepository
    }
    

    iii. Use the above repository in your service implementation class

  • Now, the Service class may look like this,

    public interface GenericService<T extends GenericEntity, ID extends Serializable> {
       // add specific methods you want to extend to user
    }
    
  • The generic implementation class can be as follows,

    public abstract class GenericServiceImpl<T extends GenericEntity, J extends JpaRepository<T, Long> & GenericRepository<T>> implements GenericService<T, Long> {
    
    // constructor takes in specific repository
        public GenericServiceImpl(J genericRepository) {
           // save this to local var
        } 
      // using the above repository, specific methods are programmed
    
    }
    
  • specific implementation class can be

    public class MySpecificEntityServiceImpl extends GenericServiceImpl<MySpecificEntity, MySpecificEntityRepository> implements MySpecificEntityService {
    
        // the specific repository is autowired
        @Autowired
        public MySpecificEntityServiceImpl(MySpecificEntityRepository genericRepository) {
             super(genericRepository);
             this.genericRepository = (MySpecificEntityRepository) genericRepository;
         }
     }
    
  • 链接地址: http://www.djcxy.com/p/44090.html

    上一篇: Spring数据JPA + Hibernate + PostgreSQL

    下一篇: Spring Data JPA:使用规范实现自定义存储库行为