Spring documentation here http://docs.spring.io/spring-data/data-jpa/docs/current/reference/html/repositories.html#repositories.custom-implementations gives example to add custom functionalities to all repositories or to a single repositories, not both.
Let suppose I want to add some custom funcs to all repositories (using Custom Repository Factory Bean) and some other only to a single repositories (docs says to use a Custom Interface and a Custom Impl); how can I achieve this?
Some example code where I added "setCurrentTenansInSession" method to all repositories; now I want to add a custom method, e.g. "newCustomMethod", to ona single repository (that is a MyJpaRepository, as for my custom repository factory). How do I do this?
Custom behaviour interface:
@NoRepositoryBean
public interface MyJpaRepository<T, ID extends Serializable> extends JpaRepository<T, ID> {
public void setCurrentTenantInSession(Object object);
}
Custom behaviour implementation:
public class MultiTenantSimpleJpaRepository<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements MyJpaRepository<T, ID> {
public void setCurrentTenantInSession(Object object) {
//custom impl
}
}
Custom repository factory bean :
public class MultiTenantJpaRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extends Serializable> extends JpaRepositoryFactoryBean<T, S, ID> {
@Override
protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
return new MultiTenantJpaRepositoryFactory(entityManager);
}
}
And finally the custom repository factory :
public class MultiTenantJpaRepositoryFactory extends JpaRepositoryFactory {
public MultiTenantJpaRepositoryFactory(EntityManager entityManager) {
super(entityManager);
}
@Override
protected JpaRepository<?, ?> getTargetRepository(RepositoryMetadata metadata, EntityManager entityManager) {
final JpaEntityInformation<?, Serializable> entityInformation = getEntityInformation(metadata.getDomainType());
final SimpleJpaRepository<?, ?> repo = new MultiTenantSimpleJpaRepository(entityInformation, entityManager);
repo.setLockMetadataProvider(LockModeRepositoryPostProcessor.INSTANCE.getLockMetadataProvider());
return repo;
}
@Override
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
return MultiTenantSimpleJpaRepository.class;
}
}
Crud Repository doesn't provide methods for implementing pagination and sorting. JpaRepository ties your repositories to the JPA persistence technology so it should be avoided. We should use CrudRepository or PagingAndSortingRepository depending on whether you need sorting and paging or not.
As a consequence, findById() returns the actual object and getById returns a reference of the entity.
We just need to let EmployeeRepository implement the custom interface and define the implementation for the customized repository. Following this design, we can easy to apply query-by-example, the query-method as well as other Spring Data JPA features. You might wonder where we put the @Repository annotation.
You just need to combine the approaches on the doc page you mentioned. Let Car
be the entity you want to have a custom repository for.
CommonCustomRepository
defines the methods added to all repos:
@NoRepositoryBean
public interface CommonCustomRepository<T, ID extends Serializable> extends JpaRepository<T, ID> {
String getCustomValue();
}
The implementation for this repo:
public class CommonCustomRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements CommonCustomRepository<T, ID> {
public CommonCustomRepositoryImpl(Class<T> domainClass, EntityManager em) {
super(domainClass, em);
}
public CommonCustomRepositoryImpl(JpaEntityInformation<T, ?> entityInformation,
EntityManager entityManager) {
super(entityInformation, entityManager);
}
@Override
public String getCustomValue() {
return "CustomValue";
}
}
Custom methods for CarRepository
@NoRepositoryBean
public interface CustomCarRepository {
public String getCustomCarValue();
}
Implementation of the custom car-related methods
public class CarRepositoryImpl implements CustomCarRepository {
@PersistenceContext
private EntityManager em;
@Override
public String getCustomCarValue() {
return "CustomCarValue";
}
}
The combined interface for CarRepository
public interface CarRepository extends CommonCustomRepository<Car, Long>, CustomCarRepository {
}
Custom repo factory, just like in the documentation
public class CustomRepositoryFactoryBean<R extends JpaRepository<T, I>, T, I extends Serializable> extends
JpaRepositoryFactoryBean<R, T, I> {
@Override
protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
return new CustomRepositoryFactory(entityManager);
}
private static class CustomRepositoryFactory<T, I extends Serializable> extends JpaRepositoryFactory {
private EntityManager entityManager;
public CustomRepositoryFactory(EntityManager entityManager) {
super(entityManager);
this.entityManager = entityManager;
}
@Override
protected Object getTargetRepository(RepositoryMetadata metadata) {
return new CommonCustomRepositoryImpl<T, I>((Class<T>) metadata.getDomainType(), entityManager);
}
@Override
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
// The RepositoryMetadata can be safely ignored, it is used by the JpaRepositoryFactory
// to check for QueryDslJpaRepository's which is out of scope.
return CommonCustomRepositoryImpl.class;
}
}
}
The final bit of configuration, just like in the docs
<jpa:repositories base-package="com.example" factory-class="com.example.CustomRepositoryFactoryBean"/>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With