Browse Source

Polishing

See gh-23961
pull/24117/head
Rossen Stoyanchev 5 years ago
parent
commit
acfeb77d41
  1. 6
      spring-test/src/main/java/org/springframework/test/web/reactive/server/DefaultWebTestClientBuilder.java
  2. 29
      spring-test/src/main/java/org/springframework/test/web/reactive/server/WebTestClient.java
  3. 3
      spring-web/src/main/java/org/springframework/http/codec/ClientCodecConfigurer.java
  4. 5
      spring-web/src/main/java/org/springframework/http/codec/CodecConfigurer.java
  5. 6
      spring-web/src/main/java/org/springframework/http/codec/ServerCodecConfigurer.java
  6. 32
      spring-web/src/main/java/org/springframework/http/codec/support/BaseCodecConfigurer.java
  7. 3
      spring-web/src/main/java/org/springframework/http/codec/support/BaseDefaultCodecs.java
  8. 42
      spring-web/src/test/java/org/springframework/http/codec/support/ClientCodecConfigurerTests.java
  9. 81
      spring-web/src/test/java/org/springframework/http/codec/support/CodecConfigurerTests.java
  10. 44
      spring-web/src/test/java/org/springframework/http/codec/support/ServerCodecConfigurerTests.java
  11. 11
      spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultExchangeStrategiesBuilder.java
  12. 17
      spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClientBuilder.java
  13. 5
      spring-webflux/src/main/java/org/springframework/web/reactive/function/client/ExchangeStrategies.java
  14. 31
      spring-webflux/src/main/java/org/springframework/web/reactive/function/client/WebClient.java
  15. 4
      spring-webflux/src/test/java/org/springframework/web/reactive/function/client/DefaultWebClientTests.java
  16. 1
      spring-webflux/src/test/java/org/springframework/web/reactive/function/client/ExchangeStrategiesTests.java
  17. 31
      src/docs/asciidoc/web/webflux-webclient.adoc
  18. 3
      src/docs/asciidoc/web/webflux.adoc

6
spring-test/src/main/java/org/springframework/test/web/reactive/server/DefaultWebTestClientBuilder.java

@ -143,12 +143,6 @@ class DefaultWebTestClientBuilder implements WebTestClient.Builder { @@ -143,12 +143,6 @@ class DefaultWebTestClientBuilder implements WebTestClient.Builder {
return this;
}
@Override
public WebTestClient.Builder exchangeStrategies(ExchangeStrategies.Builder strategies) {
this.webClientBuilder.exchangeStrategies(strategies);
return this;
}
@Override
public WebTestClient.Builder exchangeStrategies(Consumer<ExchangeStrategies.Builder> configurer) {
this.webClientBuilder.exchangeStrategies(configurer);

29
spring-test/src/main/java/org/springframework/test/web/reactive/server/WebTestClient.java

@ -444,30 +444,21 @@ public interface WebTestClient { @@ -444,30 +444,21 @@ public interface WebTestClient {
/**
* Configure the {@link ExchangeStrategies} to use.
* <p>This is useful for changing the default settings, yet still allowing
* further customizations via {@link #exchangeStrategies(Consumer)}.
* By default {@link ExchangeStrategies#withDefaults()} is used.
* <p>Note that in a scenario where the builder is configured by
* multiple parties, it is preferable to use
* {@link #exchangeStrategies(Consumer)} in order to customize the same
* {@code ExchangeStrategies}. This method here sets the strategies that
* everyone else then can customize.
* <p>By default this is {@link ExchangeStrategies#withDefaults()}.
* @param strategies the strategies to use
* @deprecated as of 5.1 in favor of {@link #exchangeStrategies(ExchangeStrategies.Builder)}
*/
@Deprecated
Builder exchangeStrategies(ExchangeStrategies strategies);
/**
* Configure the {@link ExchangeStrategies.Builder} to use.
* <p>This is useful for changing the default settings, yet still allowing
* further customizations via {@link #exchangeStrategies(Consumer)}.
* By default {@link ExchangeStrategies#builder()} is used.
* @param strategies the strategies to use
* @since 5.1.12
*/
Builder exchangeStrategies(ExchangeStrategies.Builder strategies);
/**
* Customize the {@link ExchangeStrategies}.
* <p>Allows further customization on {@link ExchangeStrategies},
* mutating them if they were {@link #exchangeStrategies(ExchangeStrategies) set},
* or starting from {@link ExchangeStrategies#withDefaults() defaults}.
* Customize the strategies configured via
* {@link #exchangeStrategies(ExchangeStrategies)}. This method is
* designed for use in scenarios where multiple parties wish to update
* the {@code ExchangeStrategies}.
* @since 5.1.12
*/
Builder exchangeStrategies(Consumer<ExchangeStrategies.Builder> configurer);

3
spring-web/src/main/java/org/springframework/http/codec/ClientCodecConfigurer.java

@ -64,11 +64,12 @@ public interface ClientCodecConfigurer extends CodecConfigurer { @@ -64,11 +64,12 @@ public interface ClientCodecConfigurer extends CodecConfigurer {
ClientDefaultCodecs defaultCodecs();
/**
* Clone this {@link ClientCodecConfigurer}.
* {@inheritDoc}.
*/
@Override
ClientCodecConfigurer clone();
/**
* Static factory method for a {@code ClientCodecConfigurer}.
*/

5
spring-web/src/main/java/org/springframework/http/codec/CodecConfigurer.java

@ -88,7 +88,10 @@ public interface CodecConfigurer { @@ -88,7 +88,10 @@ public interface CodecConfigurer {
List<HttpMessageWriter<?>> getWriters();
/**
* Clone this {@link CodecConfigurer}.
* Create a copy of this {@link CodecConfigurer}. The returned clone has its
* own lists of default and custom codecs and generally can be configured
* independently. Keep in mind however that codec instances (if any are
* configured) are themselves not cloned.
* @since 5.1.12
*/
CodecConfigurer clone();

6
spring-web/src/main/java/org/springframework/http/codec/ServerCodecConfigurer.java

@ -62,6 +62,12 @@ public interface ServerCodecConfigurer extends CodecConfigurer { @@ -62,6 +62,12 @@ public interface ServerCodecConfigurer extends CodecConfigurer {
@Override
ServerDefaultCodecs defaultCodecs();
/**
* {@inheritDoc}.
*/
@Override
ServerCodecConfigurer clone();
/**
* Static factory method for a {@code ServerCodecConfigurer}.

32
spring-web/src/main/java/org/springframework/http/codec/support/BaseCodecConfigurer.java

@ -37,7 +37,7 @@ import org.springframework.util.Assert; @@ -37,7 +37,7 @@ import org.springframework.util.Assert;
* @author Brian Clozel
* @since 5.0
*/
class BaseCodecConfigurer implements CodecConfigurer {
abstract class BaseCodecConfigurer implements CodecConfigurer {
protected final BaseDefaultCodecs defaultCodecs;
@ -55,14 +55,21 @@ class BaseCodecConfigurer implements CodecConfigurer { @@ -55,14 +55,21 @@ class BaseCodecConfigurer implements CodecConfigurer {
}
/**
* Constructor with another {@link BaseCodecConfigurer} to copy
* the configuration from.
* Create a deep copy of the given {@link BaseCodecConfigurer}.
* @since 5.1.12
*/
BaseCodecConfigurer(BaseCodecConfigurer other) {
protected BaseCodecConfigurer(BaseCodecConfigurer other) {
this.defaultCodecs = other.cloneDefaultCodecs();
this.customCodecs = new DefaultCustomCodecs(other.customCodecs);
}
/**
* Sub-classes should override this to create deep copy of
* {@link BaseDefaultCodecs} which can can be client or server specific.
* @since 5.1.12
*/
protected abstract BaseDefaultCodecs cloneDefaultCodecs();
@Override
public DefaultCodecs defaultCodecs() {
@ -99,16 +106,6 @@ class BaseCodecConfigurer implements CodecConfigurer { @@ -99,16 +106,6 @@ class BaseCodecConfigurer implements CodecConfigurer {
}
@Override
public CodecConfigurer clone() {
return new BaseCodecConfigurer(this);
}
protected BaseDefaultCodecs cloneDefaultCodecs() {
return new BaseDefaultCodecs(this.defaultCodecs);
}
/**
* Internal method that returns the configured writers.
* @param forMultipart whether to returns writers for general use ("false"),
@ -128,6 +125,9 @@ class BaseCodecConfigurer implements CodecConfigurer { @@ -128,6 +125,9 @@ class BaseCodecConfigurer implements CodecConfigurer {
return result;
}
@Override
public abstract CodecConfigurer clone();
/**
* Default implementation of {@code CustomCodecs}.
@ -146,6 +146,10 @@ class BaseCodecConfigurer implements CodecConfigurer { @@ -146,6 +146,10 @@ class BaseCodecConfigurer implements CodecConfigurer {
DefaultCustomCodecs() {
}
/**
* Create a deep copy of the given {@link DefaultCustomCodecs}.
* @since 5.1.12
*/
DefaultCustomCodecs(DefaultCustomCodecs other) {
other.typedReaders.addAll(this.typedReaders);
other.typedWriters.addAll(this.typedWriters);

3
spring-web/src/main/java/org/springframework/http/codec/support/BaseDefaultCodecs.java

@ -109,6 +109,9 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs { @@ -109,6 +109,9 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs {
BaseDefaultCodecs() {
}
/**
* Create a deep copy of the given {@link BaseDefaultCodecs}.
*/
protected BaseDefaultCodecs(BaseDefaultCodecs other) {
this.jackson2JsonDecoder = other.jackson2JsonDecoder;
this.jackson2JsonEncoder = other.jackson2JsonEncoder;

42
spring-web/src/test/java/org/springframework/http/codec/support/ClientCodecConfigurerTests.java

@ -22,6 +22,7 @@ import java.util.Arrays; @@ -22,6 +22,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import org.junit.jupiter.api.Test;
import reactor.core.publisher.Flux;
@ -123,6 +124,47 @@ public class ClientCodecConfigurerTests { @@ -123,6 +124,47 @@ public class ClientCodecConfigurerTests {
.filter(e -> e == decoder).orElse(null)).isSameAs(decoder);
}
@Test
public void cloneConfigurer() {
ClientCodecConfigurer clone = this.configurer.clone();
Jackson2JsonDecoder jackson2Decoder = new Jackson2JsonDecoder();
clone.defaultCodecs().serverSentEventDecoder(jackson2Decoder);
clone.defaultCodecs().multipartCodecs().encoder(new Jackson2SmileEncoder());
clone.defaultCodecs().multipartCodecs().writer(new ResourceHttpMessageWriter());
// Clone has the customizations
Decoder<?> sseDecoder = clone.getReaders().stream()
.filter(reader -> reader instanceof ServerSentEventHttpMessageReader)
.map(reader -> ((ServerSentEventHttpMessageReader) reader).getDecoder())
.findFirst()
.get();
List<HttpMessageWriter<?>> multipartWriters = clone.getWriters().stream()
.filter(writer -> writer instanceof MultipartHttpMessageWriter)
.flatMap(writer -> ((MultipartHttpMessageWriter) writer).getPartWriters().stream())
.collect(Collectors.toList());
assertThat(sseDecoder).isSameAs(jackson2Decoder);
assertThat(multipartWriters).hasSize(2);
// Original does not have the customizations
sseDecoder = this.configurer.getReaders().stream()
.filter(reader -> reader instanceof ServerSentEventHttpMessageReader)
.map(reader -> ((ServerSentEventHttpMessageReader) reader).getDecoder())
.findFirst()
.get();
multipartWriters = this.configurer.getWriters().stream()
.filter(writer -> writer instanceof MultipartHttpMessageWriter)
.flatMap(writer -> ((MultipartHttpMessageWriter) writer).getPartWriters().stream())
.collect(Collectors.toList());
assertThat(sseDecoder).isNotSameAs(jackson2Decoder);
assertThat(multipartWriters).hasSize(10);
}
private Decoder<?> getNextDecoder(List<HttpMessageReader<?>> readers) {
HttpMessageReader<?> reader = readers.get(this.index.getAndIncrement());

81
spring-web/src/test/java/org/springframework/http/codec/support/CodecConfigurerTests.java

@ -18,6 +18,7 @@ package org.springframework.http.codec.support; @@ -18,6 +18,7 @@ package org.springframework.http.codec.support;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import com.google.protobuf.ExtensionRegistry;
import org.junit.jupiter.api.Test;
@ -42,6 +43,8 @@ import org.springframework.http.codec.HttpMessageReader; @@ -42,6 +43,8 @@ import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.codec.HttpMessageWriter;
import org.springframework.http.codec.ResourceHttpMessageReader;
import org.springframework.http.codec.ResourceHttpMessageWriter;
import org.springframework.http.codec.ServerSentEventHttpMessageReader;
import org.springframework.http.codec.ServerSentEventHttpMessageWriter;
import org.springframework.http.codec.json.Jackson2JsonDecoder;
import org.springframework.http.codec.json.Jackson2JsonEncoder;
import org.springframework.http.codec.json.Jackson2SmileDecoder;
@ -269,11 +272,68 @@ public class CodecConfigurerTests { @@ -269,11 +272,68 @@ public class CodecConfigurerTests {
}
@Test
public void cloneConfigurer() {
CodecConfigurer clone = this.configurer.clone();
public void cloneCustomCodecs() {
this.configurer.registerDefaults(false);
CodecConfigurer clone = this.configurer.clone();
clone.customCodecs().encoder(new Jackson2JsonEncoder());
clone.customCodecs().decoder(new Jackson2JsonDecoder());
clone.customCodecs().reader(new ServerSentEventHttpMessageReader());
clone.customCodecs().writer(new ServerSentEventHttpMessageWriter());
assertThat(this.configurer.getReaders().size()).isEqualTo(0);
assertThat(clone.getReaders().size()).isEqualTo(11);
assertThat(this.configurer.getWriters().size()).isEqualTo(0);
assertThat(clone.getReaders().size()).isEqualTo(2);
assertThat(clone.getWriters().size()).isEqualTo(2);
}
@Test
public void cloneDefaultCodecs() {
CodecConfigurer clone = this.configurer.clone();
Jackson2JsonDecoder jacksonDecoder = new Jackson2JsonDecoder();
Jackson2JsonEncoder jacksonEncoder = new Jackson2JsonEncoder();
Jaxb2XmlDecoder jaxb2Decoder = new Jaxb2XmlDecoder();
Jaxb2XmlEncoder jaxb2Encoder = new Jaxb2XmlEncoder();
ProtobufDecoder protoDecoder = new ProtobufDecoder();
ProtobufEncoder protoEncoder = new ProtobufEncoder();
clone.defaultCodecs().jackson2JsonDecoder(jacksonDecoder);
clone.defaultCodecs().jackson2JsonEncoder(jacksonEncoder);
clone.defaultCodecs().jaxb2Decoder(jaxb2Decoder);
clone.defaultCodecs().jaxb2Encoder(jaxb2Encoder);
clone.defaultCodecs().protobufDecoder(protoDecoder);
clone.defaultCodecs().protobufEncoder(protoEncoder);
// Clone has the customized the customizations
List<Decoder<?>> decoders = clone.getReaders().stream()
.filter(reader -> reader instanceof DecoderHttpMessageReader)
.map(reader -> ((DecoderHttpMessageReader<?>) reader).getDecoder())
.collect(Collectors.toList());
List<Encoder<?>> encoders = clone.getWriters().stream()
.filter(writer -> writer instanceof EncoderHttpMessageWriter)
.map(reader -> ((EncoderHttpMessageWriter<?>) reader).getEncoder())
.collect(Collectors.toList());
assertThat(decoders).contains(jacksonDecoder, jaxb2Decoder, protoDecoder);
assertThat(encoders).contains(jacksonEncoder, jaxb2Encoder, protoEncoder);
// Original does not have the customizations
decoders = this.configurer.getReaders().stream()
.filter(reader -> reader instanceof DecoderHttpMessageReader)
.map(reader -> ((DecoderHttpMessageReader<?>) reader).getDecoder())
.collect(Collectors.toList());
encoders = this.configurer.getWriters().stream()
.filter(writer -> writer instanceof EncoderHttpMessageWriter)
.map(reader -> ((EncoderHttpMessageWriter<?>) reader).getEncoder())
.collect(Collectors.toList());
assertThat(decoders).doesNotContain(jacksonDecoder, jaxb2Decoder, protoDecoder);
assertThat(encoders).doesNotContain(jacksonEncoder, jaxb2Encoder, protoEncoder);
}
private Decoder<?> getNextDecoder(List<HttpMessageReader<?>> readers) {
@ -324,10 +384,21 @@ public class CodecConfigurerTests { @@ -324,10 +384,21 @@ public class CodecConfigurerTests {
private static class TestCodecConfigurer extends BaseCodecConfigurer {
TestCodecConfigurer() {
super(new TestDefaultCodecs());
super(new BaseDefaultCodecs());
}
TestCodecConfigurer(TestCodecConfigurer other) {
super(other);
}
@Override
protected BaseDefaultCodecs cloneDefaultCodecs() {
return new BaseDefaultCodecs((BaseDefaultCodecs) defaultCodecs());
}
private static class TestDefaultCodecs extends BaseDefaultCodecs {
@Override
public CodecConfigurer clone() {
return new TestCodecConfigurer(this);
}
}

44
spring-web/src/test/java/org/springframework/http/codec/support/ServerCodecConfigurerTests.java

@ -154,6 +154,50 @@ public class ServerCodecConfigurerTests { @@ -154,6 +154,50 @@ public class ServerCodecConfigurerTests {
assertThat(((StringDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size);
}
@Test
public void cloneConfigurer() {
ServerCodecConfigurer clone = this.configurer.clone();
MultipartHttpMessageReader reader = new MultipartHttpMessageReader(new SynchronossPartHttpMessageReader());
Jackson2JsonEncoder encoder = new Jackson2JsonEncoder();
clone.defaultCodecs().multipartReader(reader);
clone.defaultCodecs().serverSentEventEncoder(encoder);
// Clone has the customizations
HttpMessageReader<?> actualReader = clone.getReaders().stream()
.filter(r -> r instanceof MultipartHttpMessageReader)
.findFirst()
.get();
Encoder<?> actualEncoder = clone.getWriters().stream()
.filter(writer -> writer instanceof ServerSentEventHttpMessageWriter)
.map(writer -> ((ServerSentEventHttpMessageWriter) writer).getEncoder())
.findFirst()
.get();
assertThat(actualReader).isSameAs(reader);
assertThat(actualEncoder).isSameAs(encoder);
// Original does not have the customizations
actualReader = this.configurer.getReaders().stream()
.filter(r -> r instanceof MultipartHttpMessageReader)
.findFirst()
.get();
actualEncoder = this.configurer.getWriters().stream()
.filter(writer -> writer instanceof ServerSentEventHttpMessageWriter)
.map(writer -> ((ServerSentEventHttpMessageWriter) writer).getEncoder())
.findFirst()
.get();
assertThat(actualReader).isNotSameAs(reader);
assertThat(actualEncoder).isNotSameAs(encoder);
}
private Decoder<?> getNextDecoder(List<HttpMessageReader<?>> readers) {
HttpMessageReader<?> reader = nextReader(readers);
assertThat(reader.getClass()).isEqualTo(DecoderHttpMessageReader.class);

11
spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultExchangeStrategiesBuilder.java

@ -91,12 +91,6 @@ final class DefaultExchangeStrategiesBuilder implements ExchangeStrategies.Build @@ -91,12 +91,6 @@ final class DefaultExchangeStrategiesBuilder implements ExchangeStrategies.Build
return Collections.unmodifiableList(new ArrayList<>(list));
}
@Override
@Deprecated
public Builder mutate() {
return new DefaultExchangeStrategiesBuilder(this);
}
@Override
public List<HttpMessageReader<?>> messageReaders() {
return this.readers;
@ -106,6 +100,11 @@ final class DefaultExchangeStrategiesBuilder implements ExchangeStrategies.Build @@ -106,6 +100,11 @@ final class DefaultExchangeStrategiesBuilder implements ExchangeStrategies.Build
public List<HttpMessageWriter<?>> messageWriters() {
return this.writers;
}
@Override
public Builder mutate() {
return new DefaultExchangeStrategiesBuilder(this);
}
}
}

17
spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClientBuilder.java

@ -81,8 +81,9 @@ final class DefaultWebClientBuilder implements WebClient.Builder { @@ -81,8 +81,9 @@ final class DefaultWebClientBuilder implements WebClient.Builder {
private ClientHttpConnector connector;
@Nullable
private ExchangeStrategies.Builder strategies;
private ExchangeStrategies strategies;
@Nullable
private List<Consumer<ExchangeStrategies.Builder>> strategiesConfigurers;
@Nullable
@ -208,13 +209,6 @@ final class DefaultWebClientBuilder implements WebClient.Builder { @@ -208,13 +209,6 @@ final class DefaultWebClientBuilder implements WebClient.Builder {
@Override
@Deprecated
public WebClient.Builder exchangeStrategies(ExchangeStrategies strategies) {
Assert.notNull(strategies, "ExchangeStrategies must not be null");
this.strategies = strategies.mutate();
return this;
}
@Override
public WebClient.Builder exchangeStrategies(ExchangeStrategies.Builder strategies) {
Assert.notNull(strategies, "ExchangeStrategies must not be null");
this.strategies = strategies;
return this;
@ -222,6 +216,9 @@ final class DefaultWebClientBuilder implements WebClient.Builder { @@ -222,6 +216,9 @@ final class DefaultWebClientBuilder implements WebClient.Builder {
@Override
public WebClient.Builder exchangeStrategies(Consumer<ExchangeStrategies.Builder> configurer) {
if (this.strategiesConfigurers == null) {
this.strategiesConfigurers = new ArrayList<>(4);
}
this.strategiesConfigurers.add(configurer);
return this;
}
@ -274,11 +271,11 @@ final class DefaultWebClientBuilder implements WebClient.Builder { @@ -274,11 +271,11 @@ final class DefaultWebClientBuilder implements WebClient.Builder {
@SuppressWarnings("deprecation")
private ExchangeStrategies initExchangeStrategies() {
if (CollectionUtils.isEmpty(this.strategiesConfigurers)) {
return this.strategies != null ? this.strategies.build() : ExchangeStrategies.withDefaults();
return this.strategies != null ? this.strategies : ExchangeStrategies.withDefaults();
}
ExchangeStrategies.Builder builder =
this.strategies != null ? this.strategies : ExchangeStrategies.builder();
this.strategies != null ? this.strategies.mutate() : ExchangeStrategies.builder();
this.strategiesConfigurers.forEach(configurer -> configurer.accept(builder));
return builder.build();

5
spring-webflux/src/main/java/org/springframework/web/reactive/function/client/ExchangeStrategies.java

@ -51,12 +51,9 @@ public interface ExchangeStrategies { @@ -51,12 +51,9 @@ public interface ExchangeStrategies {
* Return a builder to create a new {@link ExchangeStrategies} instance
* replicated from the current instance.
* @since 5.1.12
* @deprecated APIs should consume {@link ExchangeStrategies} as final or accept an
* {@link ExchangeStrategies.Builder builder}.
*/
@Deprecated
default Builder mutate() {
throw new UnsupportedOperationException("This ExchangeStrategies implementation does not support mutation.");
throw new UnsupportedOperationException();
}

31
spring-webflux/src/main/java/org/springframework/web/reactive/function/client/WebClient.java

@ -291,31 +291,22 @@ public interface WebClient { @@ -291,31 +291,22 @@ public interface WebClient {
Builder clientConnector(ClientHttpConnector connector);
/**
* Provide the {@link ExchangeStrategies} to use.
* <p>This is useful for changing the default settings, yet still allowing
* further customizations via {@link #exchangeStrategies(Consumer)}.
* If not set, defaults are obtained from {@link ExchangeStrategies#withDefaults()}.
* Configure the {@link ExchangeStrategies} to use.
* <p>Note that in a scenario where the builder is configured by
* multiple parties, it is preferable to use
* {@link #exchangeStrategies(Consumer)} in order to customize the same
* {@code ExchangeStrategies}. This method here sets the strategies that
* everyone else then can customize.
* <p>By default this is {@link ExchangeStrategies#withDefaults()}.
* @param strategies the strategies to use
* @deprecated as of 5.1, in favor of {@link #exchangeStrategies(ExchangeStrategies.Builder)}
*/
@Deprecated
Builder exchangeStrategies(ExchangeStrategies strategies);
/**
* Provide the {@link ExchangeStrategies.Builder} to use.
* <p>This is useful for changing the default settings, yet still allowing
* further customizations via {@link #exchangeStrategies(Consumer)}.
* If not set, defaults are obtained from {@link ExchangeStrategies#builder()}.
* @param strategies the strategies to use
* @since 5.1.12
*/
Builder exchangeStrategies(ExchangeStrategies.Builder strategies);
/**
* Customize the {@link ExchangeStrategies}.
* <p>Allows further customization on {@link ExchangeStrategies},
* mutating them if they were {@link #exchangeStrategies(ExchangeStrategies) set},
* or starting from {@link ExchangeStrategies#withDefaults() defaults}.
* Customize the strategies configured via
* {@link #exchangeStrategies(ExchangeStrategies)}. This method is
* designed for use in scenarios where multiple parties wish to update
* the {@code ExchangeStrategies}.
* @since 5.1.12
*/
Builder exchangeStrategies(Consumer<ExchangeStrategies.Builder> configurer);

4
spring-webflux/src/test/java/org/springframework/web/reactive/function/client/DefaultWebClientTests.java

@ -20,6 +20,8 @@ import java.time.Duration; @@ -20,6 +20,8 @@ import java.time.Duration;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.function.Predicate;
import org.junit.jupiter.api.BeforeEach;
@ -36,6 +38,8 @@ import org.springframework.core.NamedThreadLocal; @@ -36,6 +38,8 @@ import org.springframework.core.NamedThreadLocal;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.codec.FormHttpMessageReader;
import org.springframework.http.codec.FormHttpMessageWriter;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;

1
spring-webflux/src/test/java/org/springframework/web/reactive/function/client/ExchangeStrategiesTests.java

@ -45,6 +45,7 @@ public class ExchangeStrategiesTests { @@ -45,6 +45,7 @@ public class ExchangeStrategiesTests {
ExchangeStrategies strategies = ExchangeStrategies.empty().build();
assertThat(strategies.messageReaders().isEmpty()).isTrue();
assertThat(strategies.messageWriters().isEmpty()).isTrue();
ExchangeStrategies mutated = strategies.mutate().codecs(codecs -> codecs.registerDefaults(true)).build();
assertThat(mutated.messageReaders().isEmpty()).isFalse();
assertThat(mutated.messageWriters().isEmpty()).isFalse();

31
src/docs/asciidoc/web/webflux-webclient.adoc

@ -41,14 +41,12 @@ The following example configures <<web-reactive.adoc#webflux-codecs, HTTP codecs @@ -41,14 +41,12 @@ The following example configures <<web-reactive.adoc#webflux-codecs, HTTP codecs
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
Consumer<ExchangeStrategies.Builder> customizeCodecs = builder -> {
builder.codecs(configurer -> {
//...
});
};
WebClient client = WebClient.builder()
.exchangeStrategies(customizeCodecs)
.exchangeStrategies(builder -> {
return builder.codecs(codecConfigurer -> {
//...
});
})
.build();
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
@ -96,12 +94,9 @@ modified copy without affecting the original instance, as the following example @@ -96,12 +94,9 @@ modified copy without affecting the original instance, as the following example
[[webflux-client-builder-maxinmemorysize]]
=== MaxInMemorySize
Spring WebFlux configures by default a maximum size for buffering data in-memory when decoding
HTTP responses with the `WebClient`. This avoids application memory issues if the received
response is much larger than expected.
The default configured value of 256KB might not be enough for your use case, and your application
might hit that limit with the following:
Spring WebFlux configures <<web-reactive.adoc#webflux-codecs-limits,limits>> for buffering
data in-memory in codec to avoid application memory issues. By the default this is
configured to 256KB and if that's not enough for your use case, you'll see the following:
----
org.springframework.core.io.buffer.DataBufferLimitException: Exceeded limit on max bytes to buffer
@ -113,8 +108,8 @@ You can configure this limit on all default codecs with the following code sampl @@ -113,8 +108,8 @@ You can configure this limit on all default codecs with the following code sampl
.Java
----
WebClient webClient = WebClient.builder()
.exchangeStrategies(configurer ->
configurer.codecs(codecs ->
.exchangeStrategies(builder ->
builder.codecs(codecs ->
codecs.defaultCodecs().maxInMemorySize(2 * 1024 * 1024)
)
)
@ -124,14 +119,16 @@ You can configure this limit on all default codecs with the following code sampl @@ -124,14 +119,16 @@ You can configure this limit on all default codecs with the following code sampl
.Kotlin
----
val webClient = WebClient.builder()
.exchangeStrategies { strategies ->
strategies.codecs {
.exchangeStrategies { builder ->
builder.codecs {
it.defaultCodecs().maxInMemorySize(2 * 1024 * 1024)
}
}
.build()
----
[[webflux-client-builder-reactor]]
=== Reactor Netty

3
src/docs/asciidoc/web/webflux.adoc

@ -833,7 +833,8 @@ To configure buffer sizes, you can check if a given `Decoder` or `HttpMessageRea @@ -833,7 +833,8 @@ To configure buffer sizes, you can check if a given `Decoder` or `HttpMessageRea
exposes a `maxInMemorySize` property and if so the Javadoc will have details about default
values. In WebFlux, the `ServerCodecConfigurer` provides a
<<webflux-config-message-codecs,single place>> from where to set all codecs, through the
`maxInMemorySize` property for default codecs.
`maxInMemorySize` property for default codecs. On the client side, the limit can be changed
in <<web-reactive.adoc#webflux-client-builder-maxinmemorysize, WebClient.Builder>>.
For <<webflux-codecs-multipart,Multipart parsing>> the `maxInMemorySize` property limits
the size of non-file parts. For file parts it determines the threshold at which the part

Loading…
Cancel
Save