首页 > 解决方案 > WebFlux 主体序列化为依赖于运行时的模型?

问题描述

当有一个ClientResponse来自 WebClient 的时候,在最简单的情况下我们使用 clientResponse.bodyToMono(MyResponseModel.class)来序列化响应体。

但目前尚不清楚当响应格式因情况而异时该怎么办。

例如,当响应可能是两种类型之一时

type 1: {"a": <number>, "b": <string>}
type 2: {"c": <date>, "d": {"items": <array>}}

我想基本算法应该是这样的

  1. 尝试序列化为类型 1
  2. 如果确定返回类型 1 的模型
  3. 否则尝试序列化为类型 2
  4. 如果确定返回类型 2 的模型
  5. else 序列化错误

使用 Spring WebFlux 处理这种序列化场景的正确方法是什么?

标签: javajsonspringserializationspring-webflux

解决方案


您可以自己反序列化 JSON 响应。首先将响应作为 json 获取String,然后使用提供和配置的 Jackson 自己进行反序列化ObjectMapper,如果有JsonMappingException使用模型 2 的尝试。这可能不如 spring 在内部使用Jackson2JsonDecoder它的效率高,因为它InputStream直接处理而不创建副本但这似乎是目前使用 try/catch 方法的唯一方法。

@RestController
class Controller {

    private ObjectMapper objectMapper;

    public Controller(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }

    @GetMapping("/handler")
    public Mono<Object> getHandler() {
        return WebClient
            .create("https://baseurl.com")
            .get()
            .uri("/someUri")
            .retrieve()
            .bodyToMono(String.class)
            .flatMap(json ->
                Mono.<Object>fromCallable(() -> objectMapper.readValue(json, Model1.class))
                .onErrorResume(JsonMappingException.class, e ->
                        Mono.fromCallable(() -> objectMapper.readValue(json, Model2.class))
                )
            );
    }
}

另一种解决方案是为响应类型创建一个基类或接口,然后JsonDeserializer为它实现一个自定义 Jackson。这可以检测应该使用哪种类型,然后执行反序列化。


推荐阅读