Should I use Java 8 default methods for manually implemented Spring Data repository methods?

前端 未结 3 1400
感情败类
感情败类 2021-02-12 19:00

When using the new Spring Data Evans release it\'s nice to be able to use some of the nice stuff that came with java 8. One of them is default implementations in interfaces. The

3条回答
  •  南笙
    南笙 (楼主)
    2021-02-12 19:50

    What i ended up doing is creating a repository base which has a getEntityManager()

    But it isn't all straight forward to get the base class working with spring boot

    // DomainRepository.java
    import org.springframework.data.jpa.repository.JpaRepository;
    import org.springframework.data.repository.NoRepositoryBean;
    
    import javax.persistence.EntityManager;
    import java.io.Serializable;
    
    @NoRepositoryBean
    public interface DomainRepository extends JpaRepository {
    
        EntityManager getEntityManager();
    
    }
    

    Then the implementation

    // DomainRepositoryImpl.java
    import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
    
    import javax.persistence.EntityManager;
    import java.io.Serializable;
    
    public class DomainRepositoryImpl extends SimpleJpaRepository implements DomainRepository {
    
        private EntityManager entityManager;
    
        public DomainRepositoryImpl(Class domainClass, EntityManager entityManager) {
            super(domainClass, entityManager);
            this.entityManager = entityManager;
        }
    
        public EntityManager getEntityManager() {
            return entityManager;
        }
    }
    

    But then spring needs to know how to create domain repositories so we need to create a factory.

    // DomainRepositoryFactoryBean.java
    import org.springframework.data.jpa.repository.JpaRepository;
    import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;
    import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean;
    import org.springframework.data.repository.core.RepositoryMetadata;
    import org.springframework.data.repository.core.support.RepositoryFactorySupport;
    
    import javax.persistence.EntityManager;
    import java.io.Serializable;
    
    public class DomainRepositoryFactoryBean, T, I extends Serializable> extends JpaRepositoryFactoryBean {
    
        protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
            return new RepositoryBaseFactory(entityManager);
        }
    
        private static class RepositoryBaseFactory extends JpaRepositoryFactory {
    
            private EntityManager entityManager;
    
            public RepositoryBaseFactory(EntityManager entityManager) {
                super(entityManager);
    
                this.entityManager = entityManager;
            }
    
            protected Object getTargetRepository(RepositoryMetadata metadata) {
    
                return new DomainRepositoryImpl((Class) metadata.getDomainType(), entityManager);
            }
    
            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 DomainRepository.class;
            }
        }
    }
    

    And then to tell spring boot to use this factory when creating repositories

    // DomainConfig.java
    @Configuration
    @EnableJpaRepositories(repositoryFactoryBeanClass = DomainRepositoryFactoryBean.class, basePackages = {"com.mysite.domain"})
    @EnableTransactionManagement
    public class DomainConfig {
    }
    

    and then change the UserRepository to use it instead.

    @Repository
    public interface UserRepository extends DomainRepository {
        public default Optional findByLogin(String login) {
            JPAQuery query = new JPAQuery(getEntityManager());
            ...
        }
    }
    

提交回复
热议问题