【问题标题】:How do you use type arguments in a Spring Data custom method implementation?如何在 Spring Data 自定义方法实现中使用类型参数?
【发布时间】:2013-08-09 05:14:51
【问题描述】:

根据 Spring Data Commons documentation,将自定义方法实现添加到 Spring Data 存储库非常简单:

interface UserRepositoryCustom {
    public void someCustomMethod(User user);
}

class UserRepositoryCustomImpl implements UserRepositoryCustom {
    public void someCustomMethod(User user) {
        // Your custom implementation
    }
}

public interface UserRepository extends JpaRepository<User, Long>,
        UserRepositoryCustom {
}

但是,我想不通的是,如果你想使用类型参数怎么办?例如:

interface SearchableRepository<T> {
    public Page<T> search(String query, Pageable page);
}

class SearchableRepositoryImpl<T> implements SearchableRepository<T> {
    public Page<T> search(String query, Pageable page) {
        // Right here, I need the Class<T> of T so that I can create
        // the JPA query
    }
}

public interface UserRepository extends JpaRepository<User, Long>,
        SearchableRepository<User> {
}

public interface NewsRepository extends JpaRepository<Article, Long>,
        SearchableRepository<Article> {
}

在该search 方法的实现中,我需要知道提供的类型参数TClass&lt;T&gt;,以便我可以创建JPA 查询。我不想add custom behavior to all repositories,因为我不希望所有存储库都是可搜索的。我只想应用SearchableRepository接口来选择仓库。

那么你怎么能做到这一点?或者你能做到吗?

【问题讨论】:

    标签: java spring repository spring-data spring-data-jpa


    【解决方案1】:

    Bellabax 的答案是正确的,让我走上了正确的道路,因此他得到了正确答案的赞誉和荣誉。但是对于那些遇到这个问题的人来说,这里有一个更完整的实现,它可以自动发现域类型并且不需要调用 new 任何东西,希望对某人有所帮助。

    SearchableRepository.java

    public interface SearchableRepository<T> {
        public Page<T> search(String query, Pageable page);
    }
    

    AbstractDomainClassAwareRepository.java

    class AbstractDomainClassAwareRepository<T> {
        protected final Class<T> domainClass;
    
        @SuppressWarnings("unchecked")
        protected AbstractDomainClassAwareRepository() {
            Type genericSuperclass = this.getClass().getGenericSuperclass();
            while(!(genericSuperclass instanceof ParameterizedType))
            {
                if(!(genericSuperclass instanceof Class))
                    throw new IllegalStateException("Unable to determine type " +
                            "arguments because generic superclass neither " +
                            "parameterized type nor class.");
                if(genericSuperclass == AbstractDomainClassAwareRepository.class)
                    throw new IllegalStateException("Unable to determine type " +
                            "arguments because no parameterized generic superclass " +
                            "found.");
    
                genericSuperclass = ((Class)genericSuperclass).getGenericSuperclass();
            }
    
            ParameterizedType type = (ParameterizedType)genericSuperclass;
            Type[] arguments = type.getActualTypeArguments();
            this.domainClass = (Class<T>)arguments[0];
        }
    }
    

    AbstractSearchableJpaRepository.java

    class AbstractSearchableJpaRepository<T>
            extends AbstractDomainClassAwareRepository<T>
            implements SearchableRepository<T> {
        @PersistenceContext protected EntityManager entityManager;
    
        @Override
        public Page<T> search(String query, Pageable page) {
            // use this.domainClass to reference domain class
        }
    }
    

    UserRepository.java

    public interface UserRepository extends JpaRepository<User, Long>,
            SearchableRepository<User> { }
    

    UserRepositoryImpl.java

    public class UserRepositoryImpl extends AbstractSearchableJpaRepository<User> { }
    

    NewsRepository.java

    public interface NewsRepository extends JpaRepository<Article, Long>,
            SearchableRepository<Article> { }
    

    NewsRepositoryImpl.java

    public class NewsRepositoryImpl extends AbstractSearchableJpaRepository<Article> { }
    

    【讨论】:

      【解决方案2】:

      您可以将 Class 添加到 SearchableRepositoryImpl 并在 NewsRepositoryImpl 中注入(或创建)new SearchableRepositoryImpl(Article.class)

          class SearchableRepositoryImpl<T> implements SearchableRepository<T> {
            private Class<T> klass;
            public SearchableRepositoryImpl(Class<T> klazz){
              this.klass = klazz;
            }
      
            public Page<T> search(String query, Pageable page) {
                  // Right here, I need the Class<T> of T so that I can create
                  // the JPA query
              }
          }
      
          class NewsRepositoryImpl<Article> implements NewsRepository<Article> 
          {
            private SearchableRepository<Article> searchRepo = new SearchableRepositoryImpl(Article.class);
            public Page<T> search(String query, Pageable page){
              // delegate
              return searchRepo.search(query, page);
            }
      }
      

      也许new SearchableRepositoryImpl 并不是真正的春季最佳实践,只是为了展示这个想法

      【讨论】:

      • 啊。我误解了自定义是如何工作的。这为我清除了整个事情。谢谢!
      • 我在下面添加了一个更完整的解决方案,不需要您展示的new。它更像是春天。 :-)
      猜你喜欢
      • 2017-02-09
      • 2016-03-26
      • 1970-01-01
      • 2018-11-18
      • 2016-09-06
      • 2013-06-06
      • 2019-05-28
      • 2016-03-27
      • 1970-01-01
      相关资源
      最近更新 更多