Wie kann die JSON-Deserialisierung von SpringWebFlux WebClient angepasst werden?

Lesezeit: 3 Minuten

Ich benutze eine spring-webflux WebClient (Build 20170502.221452-172) für den Zugriff auf eine Webanwendung, die einen Stream von Eintrag Objekte (application/stream+json) wie folgt:

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));

Während die Deserialisierung der Eintrag objects funktioniert gut für POJOs, die allgemeine Standardtypen verwenden, einschließlich Java-Zeit (JSR-310)-Datentypen wie java.time.Instant, ich frage mich, was ich tun müsste, um benutzerdefiniertes JSON zur Java-Deserialisierung hinzuzufügen (z. B. einen benutzerdefinierten Jackson ObjectMapper ).

Ich kann darin keine API finden WebClient oder in den Klassen der Objekte, die von seinem Erbauer und fließenden APIs erstellt wurden, um dies zu tun.

Hat jemand WebClient mit angepasster Deserialisierung verwendet?

(Vielleicht ist die API noch nicht da?)

Benutzeravatar von Brian Clozel
Brian Clozel

Hier ist ein Beispiel, das die anpasst ObjectMapper für die (De-)Serialisierung von JSON. Beachten Sie, dass für Streaming-Zwecke unterschiedliche Encoder/Decoder verwendet werden, das Prinzip für ihre Konfiguration jedoch gleich bleibt.

    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();

  • Können Sie den Grund nennen, warum Jackson2ObjectMapperBuilderCustomizer nicht auf Standard-Codecs angewendet wird?

    – Hahn

    20. September 2017 um 19:04 Uhr

  • Das klingt für mich wie eine neue Frage – könnten Sie eine erstellen?

    – Brian Clozel

    20. September 2017 um 19:12 Uhr

  • @hahn Wenn Sie anstelle von Webclient.builder() den vorkonfigurierten WebClient.Builder von spring verwenden, können Sie die objectMapper-Anpassungen automatisch vornehmen lassen Ref: docs.spring.io/spring-boot/docs/current/reference/html/…

    – Saisurya Kattamuri

    26. Mai 2020 um 1:47 Uhr


Sie können dies für einen bestimmten WebClient konfigurieren:

@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();
}

Aber auch auf ‘Anwendungsebene’

durch Konfigurieren von a 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));
    };
}

die wirksam gemacht wird durch die WebClientAutoConfiguration Als ein WebClient.Builder Bohne:

@Autowired
public ItunesAlbumServiceImpl(WebClient.Builder webclientBuilder) {
    webClient = webclientBuilder.baseUrl("https://itunes.apple.com").build();
}

Benutzeravatar von SeverityOne
SchweregradEins

Basierend auf den obigen Antworten habe ich diesen Code erhalten:

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();

Wenn Sie nicht einschließen .findAndRegisterModules()werden Sie Probleme haben, wenn Sie Dinge wie die Zeitobjekte von Java 8 deserialisieren möchten.

Global konfigurieren:

@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();
    }
}

Seit Frühjahr 5.1.13 Sie können einen dedizierten verwenden .codec Methode, um sie anzupassen:

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();

  • Danke dafür – ich sollte die Frage wirklich mit Code für neuere Spring-Versionen aktualisieren …

    – Martin

    18. Mai 2020 um 14:17 Uhr

mit webflux 5.0.2 de-registerDefaults

val strategies = ExchangeStrategies.builder()
                .codecs { configurer ->
                    configurer.registerDefaults(false)
                    configurer.customCodecs().encoder(Jackson2JsonEncoder(objectMapper, APPLICATION_JSON))
                    configurer.customCodecs().decoder(Jackson2JsonDecoder(objectMapper, APPLICATION_JSON))
                }.build()

  • Danke dafür – ich sollte die Frage wirklich mit Code für neuere Spring-Versionen aktualisieren …

    – Martin

    18. Mai 2020 um 14:17 Uhr

1444530cookie-checkWie kann die JSON-Deserialisierung von SpringWebFlux WebClient angepasst werden?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy