One of the ways to modify the default behavior of a Spring Data JPA method is to create another repository base implementation. In the documentation is shown as adds custom behavior to the repository.
The steps to be followed are more or less these:
- create a custom interface for your repositories, and can extend the
JpaRepository
even, something like that:
@NoRepositoryBean
public interface CustomGenericRepository<E extends CustomAbstractEntity, PK extends Serializable> extends
JpaRepository<E, PK>, JpaSpecificationExecutor<E> { }
We will extend as well JpaSpecificationExecutor
, why our custom repository will use Specifications and she supports this.
- the second step is to implement this interface that we have just defined. Below is an example that changes the behavior of
findAll
, using a Specification
which will consider in the query only the records not deleted logically, something like this:
public class CustomGenericRepositoryImpl<E extends CustomAbstractEntity, PK extends Serializable> extends
SimpleJpaRepository<E, PK> implements CustomGenericRepository<E, PK> {
private final EntityManager entityManager;
public CustomGenericRepositoryImpl(final Class<T> domainClass, final EntityManager entityManager) {
super(domainClass, entityManager);
this.entityManager = entityManager;
}
@Override
public List<E> findAll() {
return super.findAll(this.isRemoved());
}
private Specification<E> isRemoved() {
return new Specification<E>() {
@Override
public Predicate toPredicate(final Root<E> root, final CriteriaQuery<?> query, final CriteriaBuilder cb) {
return cb.isFalse(root.<Boolean> get("deleted"));
}
};
}
}
- as we have a different implementation that we will use in our repositories, we need to create a way to instruct container spring as it will create the instances for the repositories. Then, we will create a Factory bean also customized and that also extends from one that is
JPA
, the JpaRepositoryFactoryBean
:
public class CustomGenericRepositoryFactoryBean<T extends JpaRepository<S, ID>, S, ID extends Serializable> extends
JpaRepositoryFactoryBean<T, S, ID> {
@Override
protected RepositoryFactorySupport createRepositoryFactory(final EntityManager entityManager) {
return new RepositoryFactory(entityManager);
}
private static class RepositoryFactory<T, I extends Serializable> extends JpaRepositoryFactory {
public RepositoryFactory(final EntityManager entityManager) {
super(entityManager);
}
protected Object getTargetRepository(final RepositoryMetadata metadata) {
return new CustomGenericRepositoryImpl<T, I>((Class<T>) metadata.getDomainClass(), em);
}
@Override
protected Class<?> getRepositoryBaseClass(final RepositoryMetadata metadata) {
return CustomGenericRepositoryImpl.class;
}
}
}
- Finally, we need to talk to the spring date what is the
factory-class
to create our repositories. Using XML you can use it like this:
<jpa:repositories base-package="com.brunocesar.custom.repository,com.brunocesar.custom.repository.support"
factory-class="com.brunocesar.custom.repository.support.factory.CustomGenericRepositoryFactoryBean"
transaction-manager-ref="transactionManagerCustom" entity-manager-factory-ref="entityManagerFactoryCustom" />
Using Java, considering a class only for configuration of repositories, just configure the attribute factoryClass
of @EnableJpaRepositories
, something like that:
@EnableJpaRepositories(factoryClass = "com.brunocesar.custom.repository.support.factory.CustomGenericRepositoryFactoryBean")
public class JPARepositoryConfig {
// o resto da configuração continua a mesma =)
}
To use, simply extend your repository’s custom interface, CustomGenericRepository
, something like that:
@Repository
public interface PessoaRepository extends CustomGenericRepository<Pessoa, Long> {
}
You need all your repositories to display the behavior of
findAll
changed? A group of repositories only? If so, you need onefactory bean
customized for repositories. If it’s just one (or a small group),property expressions
does not solve your problem? In addition, your problem is in the use of predicates or in the manufacture of Beans?– Bruno César
need for some positorios only, a bit large by the way for custom searches. Do you have any examples of Factory bean ? just so I know if we’re speaking the same language. @Brunocésar desde agradeço
– Otto
This answer is an example of a custom repository and a Factory bean that creates repositories with it as an implementation. I didn’t exactly understand your need, how "personalized" and complex, why jpa data has so many ways to define queries. If you include what you need as a result, it might be simpler to help.
– Bruno César
@Brunocésar very good brother, puts as an answer so I can mark as solved
– Otto
@Brunocésar What I need would be something like using filters for various fields using findall as the basis understood
– Otto
Otto, I don’t understand this last comment. You need something other than the answer that was linked (and included below) or is this just it?
– Bruno César
@I will do the tests to see if you answer and I will be warning in sequence ... since already battered
– Otto