LINUX.ORG.RU

Java generics и интерфейсы

 ,


0

1

Есть такой класс:

protected static class SpecificationConverter implements Specification<ProductInboundEntity> {
    protected Specification<ProductInbound> spec;

    public SpecificationConverter(Specification<ProductInbound> spec) {
        this.spec = spec;
    }

    @Override
    public Predicate toPredicate(Root<ProductInboundEntity> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
        return spec.toPredicate(root, query, cb);
    }
}

Specification interface:

public interface Specification<T> {
    Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb);
}

При компиляции выдаёт ошибку:

error: incompatible types: Root<ProductInboundEntity> cannot be converted to Root<ProductInbound>

Класс ProductInboundEntity реализует интерфейс ProductInbound. Т.е. return spec.toPredicate(root, query, cb); ожидает Root<ProductInbound> (интерфейс) а я ему передаю Root<ProductInboundEntity> (объект класса реализующий этот интерфейс).

В чём может быть проблема?

★★

В дженериках нет неявного восходящего преобразования. Specification<ProductInbound> параметризован конкретным типом - ProductInbound, а тебе нужен bounded wildcard Specification<? extends ProductInbound> что означает любые классы реализующие интерфейс ProductInbound.

Aber ★★★★★
()
Ответ на: комментарий от Aber

Тогда примерно всё то же самое:

private static class SpecificationConverter implements Specification<ProductInboundEntity> {
    private Specification<? extends ProductInbound> spec;

    public SpecificationConverter(Specification<? extends ProductInbound> spec) {
        this.spec = spec;
    }

    @Override
    public Predicate toPredicate(Root<ProductInboundEntity> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
        return spec.toPredicate(root, query, cb);
    }
}

Ошибка:

error: incompatible types: Root<ProductInboundEntity> cannot be converted to Root<CAP#1>
            return spec.toPredicate(root, query, cb);
                                    ^
  where CAP#1 is a fresh type-variable:
    CAP#1 extends ProductInbound from capture of ? extends ProductInbound
SaBo ★★
() автор топика

а я ему передаю Root<ProductInboundEntity> (объект класса реализующий этот интерфейс).

а зачем это указывать в Specification<ProductInboundEntity> сделай там Specification<ProductInbound> и все

Deleted
()
Ответ на: комментарий от SaBo

Такой вариант:

protected static class SpecificationConverter<T extends  ProductInbound> implements Specification<T> {
    protected Specification<T> spec;

    public SpecificationConverter(Specification<T> spec) {
        this.spec = spec;
    }

    @Override
    public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
        return spec.toPredicate(root, query, cb);
    }
}
Но конструктор SpecificationConverter придется без параметризации вызывать с @SuppressWarnings(«rawtypes»)

Aber ★★★★★
()
Ответ на: комментарий от Deleted

Тогда я не смогу передать Specification в JpaSpecificationExecutor<ProductInboundEntity>, т.к. он явно требует класс, а я буду передавать интерфейс.

SaBo ★★
() автор топика
Ответ на: комментарий от SaBo

AbstractSingletonProxyFactoryBean не поможет?

anonymous
()
Ответ на: комментарий от SaBo

у тебя там какая-то херня накручена.

когда вконец затрахаешься сделай

return spec.toPredicate((Root)root, query, cb);

но учти это плохо и не правильно

Deleted
()
Ответ на: комментарий от Aber

О, крутняк, работает! Спасибо!

SaBo ★★
() автор топика
Ответ на: комментарий от Deleted

Я пытаюсь скрыть реализацию модуля интерфейсами. Затык в сприноговом JPA, т.к. скрыть реализацию всех возможных фильтров очень сложно.

SaBo ★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.