Итак, у меня есть сущности, несколько штук.
InputField
CheckBoxField
SelectField
Все они наследуются от одной абстрактной сущности AbstractEntity
.
Для каждой сущности есть репозиторий, наследующийся от CommonRepository:
@NoRepositoryBean
public interface CommonRepository<E extends AbstractEntity> extends JpaRepository<E, Long>
Я заавтовайрил репозитории в сервис:
@Service
public class ShiftServiceImpl implements ShiftService
и положил в мапу <дискриминатор, бин репозитория>
, вот так:
private Map<String, CommonRepository> fieldRepositories;
fieldRepositories = new HashMap<>();
fieldRepositories.put("input", inputFieldRepository);
fieldRepositories.put("checkbox", checkBoxFieldRepository);
fieldRepositories.put("select", selectFieldRepository);
Далее, мне приходит дискриминатор сущности в виде String
. И, определив по дискриминатору, что за сущность, я хочу дёрнуть нужную мне сущность через соответствующий бин репозитория. То есть, так:
fieldRepositories.get(e.get("type"))
.findById(id)
.ifPresent(i -> entities.add(i));
При этом, IDEA не даёт мне это сделать, подчёркивает последнюю i
пишет:
add (ru.field.AbstractField) in List cannot be applied to
(java.lang.Object)
Подскажите, как правильно типизировать класс / мапу, чтобы всё работало?
UPD:
Заработало, благодаря ответу коллеги, но теперь не до конца чекает тип (Unchecked cast):
UPD2:
Помог комментарий, но теперь отвалилось в другом месте, при сохранении сущности:
entities
.forEach(e -> {
fieldRepositories.get(e.getFieldType().getName()).save(e);
});
Насколько я понял все репозитории в fieldRepositories
работают с сущностями-наследниками AbstractField
, а entities
— коллекция AbstractField
.
Ошибка заключается в том, что из fieldRepositories
это никак не ясно, ведь в него можно добавить другой репозиторий, у которого findById
вернет объект, никак не связанный с AbstractField
.
Исправить можно так:
private Map<String, CommonRepository<? extends AbstractField>> fieldRepositories;
Теперь в fieldRepositories
не получится добавить «неправильный» объект — произойдет ошибка компиляции.
ОБНОВЛЕНИЕ: Да, проблема с типизацией тут глубже. Ошибка в этом коде:
entities
.forEach(e -> {
fieldRepositories.get(e.getFieldType().getName()).save(e);
});
говорит о том, что компилятор не уверен, что в словаре каждой сущности сопоставлен нужный репозиторий.
Например, по ошибке ключ в словаре может отличаться от e.getFieldType().getName()
. Или где-то между сбором и сохранением сущностей Вы можете сделать что-то вроде fieldRepositories.put("input", checkBoxFieldRepository);
Знать, что сопоставление сущность—репозиторий правильное компилятор не может. Этой информации в коде нет. Правильность зависит только от внимательности разработчика, который заполняет Map
. Т.ч. боюсь, обойтись совсем без приведения типов здесь не получится.
Заставить компилятор проглотить ошибку можно так:
entities
.forEach(e -> {
((CommonRepository<AbstractField>)fieldRepositories.get(e.getFieldType().getName())).save(e);
});
Но приведение, тем более непроверенное, выглядит некрасиво. Если без приведения не обойтись, то обычно его стараются изолировать в отдельный метод, например:
//объявление возвращаем, т.к. приведение вынесено в метод
private Map<String, CommonRepository> fieldRepositories;
/**
* Отдельный метод для получения репозитория типа `AbstractField`.
* Так приведение будет только в одном месте.
* Предупреждение компилятора гасим аннотацией.
*/
@SuppressWarnings("unchecked")
CommonRepository<AbstractField> getRepository(Map<String, CommonRepository> map, String key) {
return (CommonRepository<AbstractField>) map.get(key);
}
//Примеры использования
//поиск
getRepository(e.get("type"))
.findById(id)
.ifPresent(i -> entities.add(i));
//сохранение
entities.forEach(e -> {
getRepository(e.getFieldType().getName()).save(e);
});
Строго типизированное решение мне сейчас в голову не приходит. Может кто-нибудь предложит какой-нибудь изощренный вариант.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Подскажите пожалуйста, есть ли возможность установить произвольный (а не только localhost) адрес, который будет приниматься в
Есть файл конфигурации src\main\resources\applicationproperties
У меня есть таблица, и в одну из колонок я хочу добавить ссылки на файлыНа просторах интернета я пока нашел только вот этот код, но я многое...