Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Jpa adding custom functionality to all repositories and at the same time other custom funcs to a single repository

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;
    }
}
like image 202
lincetto Avatar asked Nov 04 '13 10:11

lincetto


People also ask

Which is better CrudRepository or JpaRepository?

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.

What is the difference between findById and getById?

As a consequence, findById() returns the actual object and getById returns a reference of the entity.

How can we create a custom repository in Spring data JPA?

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.


1 Answers

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"/>
like image 102
kkamenev Avatar answered Sep 22 '22 03:09

kkamenev