Почему Flux.fromIterable () возвращается в RestController и возвращается как одна конкатенированная строка? - PullRequest
0 голосов
/ 25 февраля 2019

У меня есть Rest Conotroller, который возвращает Flux<String>, но когда я пытаюсь собрать это в список, это один элемент из всех сцепленных строк.как я могу получить его как фактический список?

Контроллер:

@RestController
public class TestRestController
{
    @GetMapping( "/getflux" )
    public Flux<String> getFlux()
    {
        return Flux.fromIterable(
            Arrays.asList(
                "String 1", 
                "String 2"
            )
        );
    }
}

Вызов контроллера:

//This returns as a list of one item: "String 1String 2
List<String> response = WebClient.builder()
    .baseUrl( "http://localhost:" + port + "/" )
    .build()
    .get()
    .uri( "/getflux" )
    .retrieve()
    .bodyToFlux( String.class )
    .collectList()
    .block();

Как мне получить фактический список?

Ответы [ 2 ]

0 голосов
/ 25 февраля 2019

После некоторых исследований выясняется, что это ошибка Spring, помеченная как «работающая по назначению».

https://github.com/spring-projects/spring-framework/issues/20807

Это ожидаемое поведение.По умолчанию байтовые массивы, байтовые буферы и строка обрабатываются как содержимое низкого уровня (сериализованный вывод) и отображаются как есть.Фактически поток передается с каждой записанной строкой и сразу же сбрасывается.

Кодер Джексона явно отменяет тип элемента String.Я понимаю, что String и массив String могут быть отображены как JSON, но есть два способа обработки содержимого String, и это то, что мы выбрали по умолчанию.

Единственное решение - никогда не возвращатьFlux<String>, но вместо этого возвращает список некоторого класса-оболочки, который вы создаете.Это по-прежнему позволяет использовать Flux и противодавление, и Spring правильно обрабатывает такие сложные объекты.

Ниже отлично работает:

@GetMapping("/getflux")
public Flux<List<StringWrapper>> getFlux() {
    return Flux.fromIterable(
        Arrays.asList(
            new StringWrapper( "String 1" ),
            new StringWrapper( "String 2" )

        )
    );
}
0 голосов
/ 25 февраля 2019

Похоже, проблема с десериализацией List<String> (например, List<Integer> и многие другие типы работают хорошо).Я попытался настроить конфигурацию ObjectMapper Джексона, но потерпел неудачу.Может быть, вы тоже должны попробовать это сами или даже поставить вопрос об этом в репозитории Jackson Github.

В качестве обходного пути вы можете вернуть Mono<List<String>> из метода контроллера:

@GetMapping("/getflux")
public Mono<List<String>> getFlux() {
    return Flux.fromIterable(
            Arrays.asList(
                    "String 1",
                    "String 2"

            )
    ).collectList();
}

,и назовите это так:

List<String> block = WebClient.builder()
    .baseUrl("http://localhost:" + 8080 + "/")
    .build()
    .get()
    .uri("/getflux")
    .retrieve()
    .bodyToMono(new ParameterizedTypeReference<List<String>>() {
    })
    .block();

Результат - ["String 1","String 2"].То же самое можно вернуть, вызвав метод контроллера непосредственно из веб-браузера / curl / и т. Д.

...