如何将泛型传递给 Spring CRUD 存储库的保存方法



假设我们有三个具有名称和id的JPA对象。我用getters+setters为名称和id创建了一个接口。

class Car implements MetadataObject
class Bus implements MetadataObject
class Train implements MetadataObject

我们还有三个用于这些JPA对象的存储库:

interface CarRepository extends CrudRepository<Car, Long>
interface BusRepository extends CrudRepository<Bus, Long>
interface TrainRepository extends CrudRepository<Train, Long>

对于这些对象中的每一个,我们都希望在spring服务中运行相同的方法。(高度简化(

private void importMetadata(CrudRepository<? extends MetadataObject, String> mRepository) {
Optional<? extends MetadataObject> currentOptional = mRepository.findById(1);
if (currentOptional.isPresent()) {
MetadataObject current = (MetadataObject) currentOptional.get();
current.setName("a1");
mRepository.save(current);
}
}

的同一春季服务可调用

@Autowired
private CarRepository carRepository;
...
importMetadata(carRepository);

这导致错误:

The method save(S) in the type CrudRepository<capture#4-of ? extends MetadataObject, Long> is not applicable for the arguments (MetadataObject)

如果我查看Springs CRUD存储库:CrudRepository<T, ID>及其保存方法:<S extends T> S save(S entity);,这很奇怪。

在我们的例子中,我们有T = ? extends MetadataObjectS = ? extends ? extends MetadataObjects

如果我们将我的函数更改为private void importMetadata(CrudRepository<MetadataObject, String> bdbRepository),则保存方法是正确的,但我不能再使用carRepository 调用该方法

The method importMetadata(CrudRepository<MetadataObject,String>) in the type <...> is not applicable for the arguments (CarRepository)

注意:我高度简化了这个例子。我知道在这个例子中,这些JPA类的接口没有任何意义。我也知道我的方法毫无意义,但它完美地突出了问题。

我的问题是:传递什么来保存,或者如何重写这个函数?这里到底有什么问题?

您可以使用此方法定义:

private void <T extends MetadataObject>importMetadata(CrudRepository<T, String> mRepository) {
Optional<T> currentOptional = mRepository.findById(1);
if (currentOptional.isPresent()) {
T current = currentOptional.get();
current.setName("a1");
mRepository.save(current);
}
} 

我将尝试解释CrudRepository<? extends MetadataObject, String> mRepository的方法save失败的原因。

假设我们有一个通用类:

class C<T> {
public void save (T t) {
// .. whatever
}
}

当我们写这样的东西时:

void f (C<? extends Object> c) {
c.save(new Object());
}

编译器抱怨CCD_ 8行。

这是因为,当应用类型限制时,编译器不知道c引用实际上是指向C<Object>还是指向C<Number>或其他什么,因为C<Object>C<Number>都被接受为f的参数。

因此,编译器不知道save方法的参数是否被允许,因此出现了错误。

最新更新