简体   繁体   English

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

[英]How to pass generics to an Spring CRUD Repository's save method

Let's say we have three JPA objects with name and id. 假设我们有三个具有名称和ID的JPA对象。 I made an interface with getters+setters for name and id. 我用getters + setters建立了一个接口来输入名称和ID。

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

We also have three repositories for these JPA objects: 我们还为这些JPA对象提供了三个存储库:

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

For each of these objects we want to run the same method in an spring service. 对于这些对象中的每一个,我们希望在spring服务中运行相同的方法。 (highly simplified) (高度简化)

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);
    }
}

Which is callable by the same spring service by 可以通过同一spring服务调用

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

This results in the error: 这导致错误:

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

Which is odd if I look at Springs CRUD Repository: CrudRepository<T, ID> and its save method: <S extends T> S save(S entity); 如果我查看Springs CRUD存储库,这是很奇怪的: CrudRepository<T, ID>及其保存方法: <S extends T> S save(S entity); .

In our example we have T = ? extends MetadataObject 在我们的示例中,我们有T = ? extends MetadataObject T = ? extends MetadataObject and S = ? extends ? extends MetadataObjects T = ? extends MetadataObject并且S = ? extends ? extends MetadataObjects S = ? extends ? extends MetadataObjects S = ? extends ? extends MetadataObjects . S = ? extends ? extends MetadataObjects

If we change my function to private void importMetadata(CrudRepository<MetadataObject, String> bdbRepository) the save method is correct but I can't call the method with my carRepository anymore 如果我们将函数更改为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)

Be aware: I highly simplified the example. 请注意:我高度简化了示例。 I know that in this example Interfaces for these JPA classes makes no sense. 我知道在此示例中,这些JPA类的接口没有任何意义。 I also know that my method makes no sense but it highlights the problem perfectly. 我也知道我的方法没有意义,但是可以完美地突出问题。

My question would be: What to pass to save or how to rewrite this function that it works? 我的问题是:保存什么内容或如何重写此功能? What exactly is the issue here? 这到底是什么问题?

You can use this method definition: 您可以使用以下方法定义:

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);
   }
} 

I will try the explain the reason the method save of CrudRepository<? extends MetadataObject, String> mRepository 我将尝试解释CrudRepository<? extends MetadataObject, String> mRepository方法saveCrudRepository<? extends MetadataObject, String> mRepository CrudRepository<? extends MetadataObject, String> mRepository fails. CrudRepository<? extends MetadataObject, String> mRepository失败。

Suppose we have a generic class: 假设我们有一个通用类:

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

When we write something like: 当我们写类似的东西时:

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

the compiler complains about the c.save line. 编译器抱怨c.save行。

That's because, when applying the type restriction, the compile doesn't know whether the c reference points, in fact, to C<Object> or C<Number> or whatever, since both C<Object> and C<Number> are accepted as arguments for f . 这是因为,在应用类型限制时,编译器不知道c引用实际上指向C<Object>还是C<Number>或其他任何东西,因为C<Object>C<Number>都被接受作为f参数。

Because of that, the compiler doesn't know whether the save method's argument is allowed or not, hence the error. 因此,编译器不知道是否允许使用save方法的参数,因此会出错。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM