假设我们有三个名称和ID的JPA对象。我用getters + setter建立了一个接口来输入名称和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);
}
}
哪个可以被同一spring服务调用
@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 MetadataObject
和S = ? extends ? extends MetadataObjects
。
如果我们将函数更改为private void importMetadata(CrudRepository<MetadataObject, String> bdbRepository)
,则save方法是正确的,但我无法再通过carRepository调用该方法
The method importMetadata(CrudRepository<MetadataObject,String>) in the type <...> is not applicable for the arguments (CarRepository)
请注意:我高度简化了示例。我知道在此示例中,这些JPA类的接口没有任何意义。我也知道我的方法没有意义,但可以完美地突出问题。
我的问题是:保存什么内容或如何重写此功能?这里到底是什么问题?
答案 0 :(得分:3)
您可以使用以下方法定义:
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);
}
}
答案 1 :(得分:0)
我将尝试解释save
的方法CrudRepository<? extends MetadataObject, String> mRepository
失败的原因。
假设我们有一个通用类:
class C<T> {
public void save (T t) {
// .. whatever
}
}
当我们写类似的东西时:
void f (C<? extends Object> c) {
c.save(new Object());
}
编译器抱怨c.save
行。
这是因为,在应用类型限制时,编译器并不知道c
引用实际上是指向C<Object>
还是C<Number>
或其他任何东西,因为{{ 1}}和C<Object>
被接受为C<Number>
的参数。
因此,编译器不知道是否允许使用f
方法的参数,因此会出错。