Подклассы с лямбдами Java 8 и опционально - PullRequest
0 голосов
/ 11 декабря 2018

Я не понимаю, почему следующий код не компилируется:

private ResponseEntity<JSendResponse> buildResponse(RequestModel requestModel,
                                                    RequestModelParamConverter paramConverter,
                                                    Supplier<String> xsdSupplier,
                                                    Supplier<String> xmlTemplateSupplier) {

    return Optional.ofNullable(new RequestErrorHandler<>().validate(validator, requestModel))
            .map(validationErrors -> new ResponseEntity<>(validationErrors, HttpStatus.BAD_REQUEST))
            .orElse(this.buildResponseForValidRequest(requestModel, paramConverter, xsdSupplier, xmlTemplateSupplier));
}

Ошибка компиляции:

orElse (org.springframework.http.ResponseEntity) в Необязательно не может быть применен к (org.springframework.http.ResponseEntity)

В то время как этот код (который я считаю логически одним и тем же кодом) компилируется:

private ResponseEntity<JSendResponse> buildResponse(RequestModel requestModel,
                                                    RequestModelParamConverter paramConverter,
                                                    Supplier<String> xsdSupplier,
                                                    Supplier<String> xmlTemplateSupplier) {

    JSendResponse validationErrors = new RequestErrorHandler<>().validate(validator, requestModel);

    if(validationErrors == null) {
        return this.buildResponseForValidRequest(requestModel, paramConverter, xsdSupplier, xmlTemplateSupplier);
    }
    else
    {
        return new ResponseEntity<>(validationErrors, HttpStatus.BAD_REQUEST);
    }
}

Кажется, проблема в том, что метод RequestErrorHandler <> (). Validateвозвращает класс с именем JSendFailResponse, если проверка не удалась.JSendFailResponse является подклассом JSendResponse, который в конечном итоге возвращается.Кажется, что лямбда-код не может понять, что JSendFailResponse является JSendResponse.

Я могу заставить его скомпилировать, если я приведу validationErrors к JSendResponse в лямбда-карте, но затем я потеряю некоторые из полей наthe JSendFailResponse.

РЕДАКТИРОВАТЬ: Этот код также не удается скомпилировать:

private ResponseEntity<? extends JSendResponse> buildResponse(RequestModel requestModel,
                                                    RequestModelParamConverter paramConverter,
                                                    Supplier<String> xsdSupplier,
                                                    Supplier<String> xmlTemplateSupplier) {

    return Optional.ofNullable(new RequestErrorHandler<>().validate(validator, requestModel))
            .map(validationErrors -> new ResponseEntity<>(validationErrors, HttpStatus.BAD_REQUEST))
            .orElse(this.buildResponseForValidRequest(requestModel, paramConverter, xsdSupplier, xmlTemplateSupplier));
}

РЕДАКТИРОВАТЬ2: Вот упрощенный пример, который вы можете скопировать / вставить в IDE, чтобы увидеть для себя.

import java.util.*;

public class GemLamDemo {

    public static void main(String... args) {

        GemLamDemo gld = new GemLamDemo();

        gld.getList(null);

    }

    public List<? extends TypeA> getList(TypeA ta) {

        return Optional.ofNullable(ta)
                .map(a -> new ArrayList<TypeA>(Arrays.asList(a)))
                .orElse(new ArrayList<TypeB>(Arrays.asList(new TypeB())));
    }

    public class TypeA {

    }

    public class TypeB extends TypeA {

    }
}

EDIT3: Я думал, что понял эту проблему, основываясь на помощи, которую я получил до сих пор, но следующий код компилируется и работает.

Optional.ofNullable(val1)
                .map(a -> new TypeA())
                .orElse(new TypeB());

Таким образом, проблема не в том, что карта и orElse должны возвращать один и тот же тип, похоже, это связано с параметризацией.Таким образом, map может испускать TypeA, а orElse может испускать TypeB, если это подкласс TypeA.Но они не могут испускать различные параметризованные типы List.List и List , похоже, не считаются подтипами друг друга, и теперь, когда я думаю об этом, они не являются.

ResponseEntity - это другой тип, чем ResponseEntity .Если бы я возвращал обычные JSendResponse и JSendFailResponse из лямбд, это, вероятно, сработало бы.Но я не являюсь, я выпускаю разные версии ResponseEntity, которые на самом деле не связаны иерархией.Так что, я думаю, все сводится к тому, как Optional поддерживает (или не поддерживает) универсальные шаблоны.Я не могу установить тип Необязательного для ResponseEntity, поэтому я ограничен строгими иерархиями типов.

EDIT4:

Приведенный выше пример неверен, поскольку типы переключаются из исходного регистра.Я думаю, что понял, спасибо всем.

Ответы [ 2 ]

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

Тип, выданный из map(), выводится как JSendFailResponse, но вы предлагаете другой тип в orElse(), и оба типа должны совпадать.

Явно введите тип для вызова map() собщий тип:

.<JSendResponse>map(validationErrors -> new ResponseEntity<>(validationErrors, HttpStatus.BAD_REQUEST))
0 голосов
/ 11 декабря 2018

Если вы проверите документацию оракула: https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html,

Подпись метода .ofNullable(): public static <T> Optional<T> ofNullable(T value)

и orElse(): public T orElse(T other)

Таким образом, параметр для обоих типов методов равен T, а orElse() не имеет <? extends T> в качестве параметра, они оба должны иметь T в качестве типа, поэтому ваш метод не должен работать, я думаю,

вы должны попробовать что-то такое (используя ваш упрощенный пример):

public List<TypeA> getList(TypeA ta) {

        ArrayList<TypeA> typeAinstance = new ArrayList<>();
        return Optional.ofNullable(ta)
                .map(a -> new ArrayList<TypeA>(Arrays.asList(a)))
                .orElse(typeAinstance.getClass().cast(Arrays.asList(new TypeB())));
    }

    public class TypeA {

    }

    public class TypeB extends TypeA {

    }

Надеюсь, это поможет

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...