如何从扩展类型的CrudRepository调用CrudRepository上的泛型方法?

时间:2018-10-30 02:22:13

标签: generics spring-data-jpa

当我尝试调用(下面的代码)通用的crudrepository接口的save方法时,出现下面的编译错误。

我应该在crudrepository和IDateDescriptorRepository之间创建一个接口吗?
我是否在crudrepository中遗漏了一个重要内容(例如我应该为所有描述符实体使用一个存储库)? 我是否在当前代码中缺少某些内容以使save()调用正常工作?

错误:

DescriptorRepositoryHelper.java:32: error: no suitable method found for save(Descriptor)
    return descriptorRepoMap.get(descriptor.type).save(descriptor);
                                                 ^
method CrudRepository.<S#1>save(S#1) is not applicable
  (inferred type does not conform to upper bound(s)
    inferred: Descriptor
    upper bound(s): CAP#1)
method CrudRepository.<S#2>save(Iterable<S#2>) is not applicable
  (cannot infer type-variable(s) S#2
    (argument mismatch; Descriptor cannot be converted to Iterable<S#2>))
where S#1,S#2 are type-variables:
 S#1 extends CAP#1 declared in method <S#1>save(S#1)
 S#2 extends CAP#1 declared in method <S#2>save(Iterable<S#2>)
where CAP#1 is a fresh type-variable:
 CAP#1 extends Descriptor from capture of ? extends Descriptor

代码:
DescriptorRepositoryHelper

@Component
public class DescriptorRepositoryHelper {

 @Autowired
 private IDateDescriptorRepository dateDescriptorRepository;

 private Map<DescriptorTypes,CrudRepository<? extends Descriptor,Integer>> descriptorRepoMap = new HashMap<>();

 public DescriptorRepositoryHelper() {
    descriptorRepoMap.put(DescriptorTypes.DATE,dateDescriptorRepository);
 }

 Descriptor save(Descriptor descriptor) {
    return descriptorRepoMap.get(descriptor.type).save(descriptor);
 }
 ...

IDateDescriptorRepository

public interface IDateDescriptorRepository extends CrudRepository<DateDescriptor, Integer> {
}

DateDescriptor

@Entity
public class DateDescriptor extends Descriptor {
...

1 个答案:

答案 0 :(得分:0)

首先查看CrudRepository的源代码。

public interface CrudRepository<T, ID extends Serializable> extends Repository<T, ID> {

    /**
     * Saves a given entity. Use the returned instance for further operations as the save operation might have changed the
     * entity instance completely.
     * 
     * @param entity
     * @return the saved entity
     */
    <S extends T> S save(S entity);

    // Remainder omitted.
}

这将允许您保存T的任何子类型并返回相同的子类型。您可以保存Descriptor的任何子类型,包括但不限于DateDescriptor。像这样更改代码,以使其正常工作。

public interface IDateDescriptorRepository extends CrudRepository<Descriptor, Integer> {

}

public class DescriptorRepositoryHelper {
    @Autowired
    private IDateDescriptorRepository dateDescriptorRepository;

    public DescriptorRepositoryHelper() {
    }

    Descriptor save(Descriptor descriptor) {
        return dateDescriptorRepository.save(descriptor);
    }
}

通过该实现,不再需要使用descriptorRepoMap。由于可以使用相同的存储库来保存Descriptor的任何子类型,因此您将获得保存为return的确切信息。

特别是对于面向文档的数据存储,通常不会看到子类与超类保留在同一存储库中,并且使用S扩展T作为参数使其在支持此类用例时更加灵活。