Skip to content

Commit

Permalink
#1134 - Make sure we don't accidentally drop customizations made to W…
Browse files Browse the repository at this point in the history
…ebClient.

We now use the API introduced in Spring Framework 5.2.2 to customize a WebClient to add hypermedia related en- and decoders without dropping customizations potentially made to the WebClient instance.
  • Loading branch information
odrotbohm committed Dec 2, 2019
1 parent f6a4e65 commit 3127c97
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 17 deletions.
Expand Up @@ -15,17 +15,19 @@
*/
package org.springframework.hateoas.config;

import lombok.RequiredArgsConstructor;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

import org.springframework.context.annotation.Configuration;
import org.springframework.core.codec.Decoder;
import org.springframework.core.codec.Encoder;
import org.springframework.hateoas.config.EnableHypermediaSupport.HypermediaType;
import org.springframework.http.codec.ClientCodecConfigurer;
import org.springframework.http.codec.CodecConfigurer.CustomCodecs;
import org.springframework.http.codec.json.Jackson2JsonDecoder;
import org.springframework.http.codec.json.Jackson2JsonEncoder;
import org.springframework.util.Assert;
import org.springframework.util.MimeType;
import org.springframework.web.reactive.function.client.ExchangeStrategies;
import org.springframework.web.reactive.function.client.WebClient;
Expand All @@ -36,40 +38,57 @@
* Assembles {@link ExchangeStrategies} needed to wire a {@link WebClient} with hypermedia support.
*
* @author Greg Turnquist
* @author Oliver Drotbohm
* @since 1.0
*/
@Configuration
@RequiredArgsConstructor
public class WebClientConfigurer {

private final ObjectMapper mapper;
private final List<HypermediaMappingInformation> hypermediaTypes;
Consumer<ClientCodecConfigurer> configurer;

/**
* Return a set of {@link ExchangeStrategies} driven by registered {@link HypermediaType}s.
* Creates a new {@link WebClientConfigurer} for the given {@link ObjectMapper} and
* {@link HypermediaMappingInformation}s.
*
* @return a collection of {@link Encoder}s and {@link Decoder} assembled into a {@link ExchangeStrategies}.
* @param mapper must not be {@literal null}.
* @param hypermediaTypes must not be {@literal null}.
*/
public ExchangeStrategies hypermediaExchangeStrategies() {
public WebClientConfigurer(ObjectMapper mapper, List<HypermediaMappingInformation> hypermediaTypes) {

Assert.notNull(mapper, "ObjectMapper must not be null!");
Assert.notNull(hypermediaTypes, "HypermediaMappingInformations must not be null!");

List<Encoder<?>> encoders = new ArrayList<>();
List<Decoder<?>> decoders = new ArrayList<>();

this.hypermediaTypes.forEach(hypermedia -> {
hypermediaTypes.forEach(hypermedia -> {

ObjectMapper objectMapper = hypermedia.configureObjectMapper(this.mapper.copy());
ObjectMapper objectMapper = hypermedia.configureObjectMapper(mapper.copy());
MimeType[] mimeTypes = hypermedia.getMediaTypes().toArray(new MimeType[0]);

encoders.add(new Jackson2JsonEncoder(objectMapper, mimeTypes));
decoders.add(new Jackson2JsonDecoder(objectMapper, mimeTypes));
});

return ExchangeStrategies.builder().codecs(clientCodecConfigurer -> {
this.configurer = it -> {

encoders.forEach(encoder -> clientCodecConfigurer.customCodecs().encoder(encoder));
decoders.forEach(decoder -> clientCodecConfigurer.customCodecs().decoder(decoder));
CustomCodecs codecs = it.customCodecs();

}).build();
encoders.forEach(codecs::encoder);
decoders.forEach(codecs::decoder);
};
}

/**
* Return a set of {@link ExchangeStrategies} driven by registered {@link HypermediaType}s.
*
* @return a collection of {@link Encoder}s and {@link Decoder} assembled into a {@link ExchangeStrategies}.
*/
public ExchangeStrategies hypermediaExchangeStrategies() {

return ExchangeStrategies.builder() //
.codecs(configurer) //
.build();
}

/**
Expand All @@ -79,6 +98,9 @@ public ExchangeStrategies hypermediaExchangeStrategies() {
* @return mutated webClient with hypermedia support.
*/
public WebClient registerHypermediaTypes(WebClient webClient) {
return webClient.mutate().exchangeStrategies(hypermediaExchangeStrategies()).build();

return webClient.mutate() //
.exchangeStrategies(it -> it.codecs(configurer)) //
.build();
}
}
Expand Up @@ -19,11 +19,12 @@
import static org.springframework.hateoas.support.CustomHypermediaType.*;
import static org.springframework.hateoas.support.MappingUtils.*;

import reactor.core.publisher.Mono;

import java.io.IOException;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import reactor.core.publisher.Mono;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
Expand Down Expand Up @@ -55,7 +56,7 @@ void setUp() {

this.testClient = WebTestClient.bindToApplicationContext(ctx).build() //
.mutate() //
.exchangeStrategies(webClientConfigurer.hypermediaExchangeStrategies()) //
.exchangeStrategies(it -> it.codecs(webClientConfigurer.configurer)) //
.build();
}

Expand Down

0 comments on commit 3127c97

Please sign in to comment.