1
votes

I wish to understand Generic Repository pattern. I have a generic service interface which is implemented by abstract service which is extended by all service implementations. I want to make sure that all CRUD operations and search by criteria/specifications happens in the abstract service.

All my repositories are interfaces extending JpaRepository and JpaSpecificationExecutor. However, I am not able to perform a findAll(specification, pageable) using the autowired repository in the abstract service.

What changes should I make to the structure so that I can leverage the methods of JpaSpecificationExecutor?

Service Interface:

public interface GenericFoo<T, S> {
     public List<T> search(S criteria, Pageable pageable) {
}

Abstract service:

public abstract class Foo<T, S> implements GenericFoo<T, S> {
    @Autowired
    private JpaRepository<T, Long> repository;

    public List<T> search(S criteria, Pageable pageable) {
         //throws compilation error
         repository.findAll(getSpecification(criteria), pageable);
    }

    protected abstract Specification<T> getSpecification(S criteria);
}

ServiceImpl:

@Component
@Transactional
public class BarServiceImpl extends Foo<Bar, BarSearchCriteria> implements GenericFoo {

    protected Specification<Bar> getSpecification(BarSearchCriteria criteria) {
        //implementation to be filled for each service
        return null;
    }  
}

Repository:

public interface BarRepository extends JpaRepository<Bar, Long>, JpaSpecificationExecutor<Bar> {
}

EDIT: I tried the following as well, although the compilation error goes away, but still the application fails to start up due to Autowiring exceptions.

SimpleJpaRepository:

public interface SimpleRepository<T> extends JpaRepository<T, Long>, JpaSpecificationExecutor<T> {
}

BaseService:

public abstract class BaseService<T, S> implements GenericService<T, S> {
    @Autowired
    private SimpleJpaRepository<T, Long> simpleJpaRepository;

    public List<T> search(S criteria, Pageable pageable) {
        repository.findAll(getSpecification(criteria), pageable);
    }

    protected abstract Specification<T> getSpecification(S criteria);
}

Repository:

public interface BarRepository extends SimpleJpaRepository<Bar, Long> {
}

Stacktrace:

Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.springframework.data.jpa.repository.support.SimpleJpaRepository com.foopackage.barpackage.services.BaseService.simpleJpaRepository; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.data.jpa.repository.support.SimpleJpaRepository] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:573) ~[spring-beans-4.2.8.RELEASE.jar:4.2.8.RELEASE]
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) ~[spring-beans-4.2.8.RELEASE.jar:4.2.8.RELEASE]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331) ~[spring-beans-4.2.8.RELEASE.jar:4.2.8.RELEASE]
... 22 common frames omitted
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.data.jpa.repository.support.SimpleJpaRepository] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1380) ~[spring-beans-4.2.8.RELEASE.jar:4.2.8.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1126) ~[spring-beans-4.2.8.RELEASE.jar:4.2.8.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1021) ~[spring-beans-4.2.8.RELEASE.jar:4.2.8.RELEASE]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:545) ~[spring-beans-4.2.8.RELEASE.jar:4.2.8.RELEASE]
... 24 common frames omitted
2
What is the compilation error you get?aviad
@avid - "cannot resolve method 'findAll(Specification<T>, Pageable)' " and its a bit obvious because if you check JpaRepository source then it doesn't contain the above signature. These method signatures are part of JpaSpecificationExecutor.mancoolgunda

2 Answers

0
votes

What changes should I make to the structure so that I can leverage the methods of JpaSpecificationExecutor?

Creating and using an intermediate interface like this should do the trick:

public interface RepositoryWithExecutor<T> extends JpaRepository<T, Long>, JpaSpecificationExecutor<Bar> {}

Now your BarRepository simply extends RepositoryWithExecutor<Bar>

And the repository of Foo<T> should as well be a RepositoryWithExecutor<T>

Updated to answer the altered question

You are trying to autowire a field of type SimpleJpaRepository<T, Long> but all your ApplicationContext knows about is the BarRepository which is a SimpleJpaRepository<Bar, Long>

You need either a generic implementation of SimpleJpaRepository<T, Long> or you have to create specialized versions of BaseService that has the T specialized to Barand reference that specialized version.

Side note: I don't think you are actually showing the code you are using, because BaseService is abstract and Spring shouldn't try to instantiate it.

0
votes

Try this one:

 @Autowired
 private SimpleJpaRepository<T> simpleJpaRepository;

Just remove the Long parameter in SimpeJpaRepository interface.