如何在Spring Data自定义方法实现中使用类型参数?

时间:2013-08-07 17:32:51

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

根据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方法的实现中,我需要知道提供的类型参数Class<T>的{​​{1}},以便我可以创建JPA查询。我不想add custom behavior to all repositories,因为我不希望所有存储库都可以搜索。我只想应用T接口来选择存储库。

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

2 个答案:

答案 0 :(得分:2)

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> { }

答案 1 :(得分:1)

您可以将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不是真正的春天最好的实践,而只是为了展示这个想法