Как передать дженерики в метод сохранения репозитория Spring CRUD - PullRequest
0 голосов
/ 14 декабря 2018

Допустим, у нас есть три объекта JPA с именем и идентификатором.Я сделал интерфейс с getters + setters для имени и идентификатора.

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>

Для каждого из этих объектов, которые мы хотим запуститьтот же метод в весенней службе.(очень упрощенно)

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 MetadataObject и S = ? 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 не имеют смысла.Я также знаю, что мой метод не имеет смысла, но он прекрасно освещает проблему.

Мой вопрос будет таким: что передать, чтобы сохранить, или как переписать эту функцию, чтобы она работала?В чем здесь проблема?

Ответы [ 2 ]

0 голосов
/ 14 декабря 2018

Я попытаюсь объяснить причину сбоя метода 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> или что-либо еще, поскольку C<Object> и C<Number> принимаются в качестве аргументов для f.

Из-за этого компилятор не знает, разрешен или нет аргумент метода save, отсюда и ошибка.

0 голосов
/ 14 декабря 2018

Вы можете использовать этот метод определения:

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);
   }
} 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...