42

我正在使用spring-webflux WebClient (build 20170502.221452-172) 来访问一个 Web 应用程序,该应用程序生成一个Entry对象流 (application/stream+json),如下所示:

final WebClient producerClient = WebClient.create("http://localhost:8080/");

Flux<Entry> entries = producerClient.get().uri("json-stream")
        .accept(MediaType.APPLICATION_STREAM_JSON)
        .exchange()
        .flatMapMany(clientResponse -> clientResponse.bodyToFlux(Entry.class));

虽然Entry对象的反序列化对于使用标准通用类型(包括 java.time.Instant 等 Java 时间 (JSR-310) 数据类型)的 POJO 工作正常,但我想知道我必须做什么才能将任何自定义 JSON 添加到 Java 反序列化(例如,自定义 Jackson ObjectMapper)。

我在WebClient或其构建器和流式 API 生成的对象的类中找不到任何 API来执行此操作。

有没有人使用自定义反序列化的 WebClient ?

(也许 API 还不存在?)

4

6 回答 6

49

这是一个自定义ObjectMapperJSON(反)序列化的示例。请注意,出于流媒体目的,正在使用不同的编码器/解码器,但其配置的原理保持不变。

    ExchangeStrategies strategies = ExchangeStrategies
            .builder()
            .codecs(clientDefaultCodecsConfigurer -> {
                clientDefaultCodecsConfigurer.defaultCodecs().jackson2JsonEncoder(new Jackson2JsonEncoder(new ObjectMapper(), MediaType.APPLICATION_JSON));
                clientDefaultCodecsConfigurer.defaultCodecs().jackson2JsonDecoder(new Jackson2JsonDecoder(new ObjectMapper(), MediaType.APPLICATION_JSON));

            }).build();

    WebClient webClient = WebClient.builder().exchangeStrategies(strategies).build();
于 2017-05-16T09:07:56.810 回答
8

您可以为特定的 WebClient 配置它:

@Autowired
public ItunesAlbumServiceImpl(ObjectMapper mapper) {
    ExchangeStrategies strategies = ExchangeStrategies.builder().codecs(clientCodecConfigurer ->
        clientCodecConfigurer.customCodecs().decoder(
                new Jackson2JsonDecoder(mapper,
                        new MimeType("text", "javascript", StandardCharsets.UTF_8)))
    ).build();

    webClient = WebClient.builder()
            .exchangeStrategies(strategies)
            .baseUrl("https://itunes.apple.com")
            .build();
}

但也在“应用程序级别”

通过配置一个CodecCustomizer

@Bean
public CodecCustomizer jacksonLegacyJsonCustomizer(ObjectMapper mapper) {
    return (configurer) -> {
        MimeType textJavascript = new MimeType("text", "javascript", StandardCharsets.UTF_8);
        CodecConfigurer.CustomCodecs customCodecs = configurer.customCodecs();
        customCodecs.decoder(
                new Jackson2JsonDecoder(mapper, textJavascript));
        customCodecs.encoder(
                new Jackson2JsonEncoder(mapper, textJavascript));
    };
}

这将通过WebClientAutoConfiguration作为WebClient.Builderbean 生效:

@Autowired
public ItunesAlbumServiceImpl(WebClient.Builder webclientBuilder) {
    webClient = webclientBuilder.baseUrl("https://itunes.apple.com").build();
}
于 2017-08-16T15:06:37.840 回答
6

根据上面的回复,我最终得到了这段代码:

final ObjectMapper mapper = new ObjectMapper()
    .findAndRegisterModules()
    .enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);
final ExchangeStrategies exchangeStrategies = ExchangeStrategies.builder()
    .codecs(configurer -> configurer.defaultCodecs()
    .jackson2JsonDecoder(new Jackson2JsonDecoder(mapper)))
    .build();
final WebClient webClient = WebClient.builder()
    .exchangeStrategies(exchangeStrategies)
    .build();

如果您不包含.findAndRegisterModules(),那么当您想要反序列化 Java 8 的时间对象之类的东西时就会遇到问题。

于 2020-09-28T15:33:16.103 回答
4

使用 webflux 5.0.2,取消注册默认值

val strategies = ExchangeStrategies.builder()
                .codecs { configurer ->
                    configurer.registerDefaults(false)
                    configurer.customCodecs().encoder(Jackson2JsonEncoder(objectMapper, APPLICATION_JSON))
                    configurer.customCodecs().decoder(Jackson2JsonDecoder(objectMapper, APPLICATION_JSON))
                }.build()
于 2018-01-25T16:31:10.110 回答
2

全局配置:

@Configuration
public class AppConfig {

    private final ObjectMapper objectMapper;

    @Autowired
    public AppConfig(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
        this.webClientBuilder = WebClient.builder()
                .exchangeStrategies(exchangeStrategies());
    }

    private ExchangeStrategies exchangeStrategies() {
        Jackson2JsonEncoder encoder = new Jackson2JsonEncoder(objectMapper);
        Jackson2JsonDecoder decoder = new Jackson2JsonDecoder(objectMapper);
        return ExchangeStrategies
                .builder()
                .codecs(configurer -> {
                    configurer.defaultCodecs().jackson2JsonEncoder(encoder);
                    configurer.defaultCodecs().jackson2JsonDecoder(decoder);
                }).build();
    }
}
于 2020-04-15T12:50:36.943 回答
2

从 Spring开始5.1.13,您可以使用专用.codec方法来自定义它们:

WebClient.builder()
    .codecs(configurer -> {
        configurer.defaultCodecs().jackson2JsonEncoder(new Jackson2JsonEncoder(new ObjectMapper(), MediaType.APPLICATION_JSON));
        configurer.defaultCodecs().jackson2JsonDecoder(new Jackson2JsonDecoder(new ObjectMapper(), MediaType.APPLICATION_JSON));
     })
    .build();
于 2020-05-18T10:02:12.563 回答