parent
d4209392d2
commit
acfeb77d41
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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}.
|
||||
*/
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -62,6 +62,12 @@ public interface ServerCodecConfigurer extends CodecConfigurer {
|
|||
@Override
|
||||
ServerDefaultCodecs defaultCodecs();
|
||||
|
||||
/**
|
||||
* {@inheritDoc}.
|
||||
*/
|
||||
@Override
|
||||
ServerCodecConfigurer clone();
|
||||
|
||||
|
||||
/**
|
||||
* Static factory method for a {@code ServerCodecConfigurer}.
|
||||
|
|
|
@ -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 {
|
|||
}
|
||||
|
||||
/**
|
||||
* 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 {
|
|||
}
|
||||
|
||||
|
||||
@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 {
|
|||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract CodecConfigurer clone();
|
||||
|
||||
|
||||
/**
|
||||
* Default implementation of {@code CustomCodecs}.
|
||||
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
|||
.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());
|
||||
|
|
|
@ -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;
|
|||
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 {
|
|||
}
|
||||
|
||||
@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 {
|
|||
private static class TestCodecConfigurer extends BaseCodecConfigurer {
|
||||
|
||||
TestCodecConfigurer() {
|
||||
super(new TestDefaultCodecs());
|
||||
super(new BaseDefaultCodecs());
|
||||
}
|
||||
|
||||
private static class TestDefaultCodecs extends BaseDefaultCodecs {
|
||||
TestCodecConfigurer(TestCodecConfigurer other) {
|
||||
super(other);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BaseDefaultCodecs cloneDefaultCodecs() {
|
||||
return new BaseDefaultCodecs((BaseDefaultCodecs) defaultCodecs());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodecConfigurer clone() {
|
||||
return new TestCodecConfigurer(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
|||
public List<HttpMessageWriter<?>> messageWriters() {
|
||||
return this.writers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder mutate() {
|
||||
return new DefaultExchangeStrategiesBuilder(this);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 {
|
|||
@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 {
|
|||
|
||||
@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 {
|
|||
@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();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
|||
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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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(builder -> {
|
||||
return builder.codecs(codecConfigurer -> {
|
||||
//...
|
||||
});
|
||||
};
|
||||
|
||||
WebClient client = WebClient.builder()
|
||||
.exchangeStrategies(customizeCodecs)
|
||||
})
|
||||
.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
|
|||
[[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
|
|||
.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
|
|||
.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
|
||||
|
||||
|
|
|
@ -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…
Reference in New Issue