Allow ExchangeStrategies customizations in WebClient
Prior to this commit, developers could configure their WebClient to use their custom `ExchangeStrategies`, by providing it in the `WebClient.Builder` chain. Once created, an `ExchangeStrategies` instance is not mutable, which makes it hard for further customizations by other components. In the case of the reported issue, other components would override the default configuration for the codecs maxInMemorySize. This commit makes the `ExchangeStrategies` mutable and uses that fact to further customize them with a new `WebClient.Builder#exchangeStrategies` `Consumer` variant. This commit is also deprecating those mutating variants in favor of a new `WebClient.Builder#exchangeStrategies` that takes a `ExchangeStrategies#Builder` directly and avoids mutation issues altogether. Closes gh-24106
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -63,6 +63,11 @@ public interface ClientCodecConfigurer extends CodecConfigurer {
|
||||
@Override
|
||||
ClientDefaultCodecs defaultCodecs();
|
||||
|
||||
/**
|
||||
* Clone this {@link ClientCodecConfigurer}.
|
||||
*/
|
||||
@Override
|
||||
ClientCodecConfigurer clone();
|
||||
|
||||
/**
|
||||
* Static factory method for a {@code ClientCodecConfigurer}.
|
||||
|
||||
@@ -87,6 +87,12 @@ public interface CodecConfigurer {
|
||||
*/
|
||||
List<HttpMessageWriter<?>> getWriters();
|
||||
|
||||
/**
|
||||
* Clone this {@link CodecConfigurer}.
|
||||
* @since 5.1.12
|
||||
*/
|
||||
CodecConfigurer clone();
|
||||
|
||||
|
||||
/**
|
||||
* Customize or replace the HTTP message readers and writers registered by
|
||||
|
||||
@@ -34,13 +34,14 @@ import org.springframework.util.Assert;
|
||||
* client and server specific variants.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Brian Clozel
|
||||
* @since 5.0
|
||||
*/
|
||||
class BaseCodecConfigurer implements CodecConfigurer {
|
||||
|
||||
private final BaseDefaultCodecs defaultCodecs;
|
||||
protected final BaseDefaultCodecs defaultCodecs;
|
||||
|
||||
private final DefaultCustomCodecs customCodecs = new DefaultCustomCodecs();
|
||||
protected final DefaultCustomCodecs customCodecs;
|
||||
|
||||
|
||||
/**
|
||||
@@ -50,6 +51,16 @@ class BaseCodecConfigurer implements CodecConfigurer {
|
||||
BaseCodecConfigurer(BaseDefaultCodecs defaultCodecs) {
|
||||
Assert.notNull(defaultCodecs, "'defaultCodecs' is required");
|
||||
this.defaultCodecs = defaultCodecs;
|
||||
this.customCodecs = new DefaultCustomCodecs();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor with another {@link BaseCodecConfigurer} to copy
|
||||
* the configuration from.
|
||||
*/
|
||||
BaseCodecConfigurer(BaseCodecConfigurer other) {
|
||||
this.defaultCodecs = other.cloneDefaultCodecs();
|
||||
this.customCodecs = new DefaultCustomCodecs(other.customCodecs);
|
||||
}
|
||||
|
||||
|
||||
@@ -87,6 +98,17 @@ class BaseCodecConfigurer implements CodecConfigurer {
|
||||
return getWritersInternal(false);
|
||||
}
|
||||
|
||||
|
||||
@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"),
|
||||
@@ -110,7 +132,7 @@ class BaseCodecConfigurer implements CodecConfigurer {
|
||||
/**
|
||||
* Default implementation of {@code CustomCodecs}.
|
||||
*/
|
||||
private static final class DefaultCustomCodecs implements CustomCodecs {
|
||||
protected static final class DefaultCustomCodecs implements CustomCodecs {
|
||||
|
||||
private final List<HttpMessageReader<?>> typedReaders = new ArrayList<>();
|
||||
|
||||
@@ -121,6 +143,16 @@ class BaseCodecConfigurer implements CodecConfigurer {
|
||||
private final List<HttpMessageWriter<?>> objectWriters = new ArrayList<>();
|
||||
|
||||
|
||||
DefaultCustomCodecs() {
|
||||
}
|
||||
|
||||
DefaultCustomCodecs(DefaultCustomCodecs other) {
|
||||
other.typedReaders.addAll(this.typedReaders);
|
||||
other.typedWriters.addAll(this.typedWriters);
|
||||
other.objectReaders.addAll(this.objectReaders);
|
||||
other.objectWriters.addAll(this.objectWriters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decoder(Decoder<?> decoder) {
|
||||
reader(new DecoderHttpMessageReader<>(decoder));
|
||||
@@ -143,7 +175,6 @@ class BaseCodecConfigurer implements CodecConfigurer {
|
||||
(canWriteObject ? this.objectWriters : this.typedWriters).add(writer);
|
||||
}
|
||||
|
||||
|
||||
// Package private accessors...
|
||||
|
||||
List<HttpMessageReader<?>> getTypedReaders() {
|
||||
|
||||
@@ -105,6 +105,21 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs {
|
||||
private boolean registerDefaults = true;
|
||||
|
||||
|
||||
BaseDefaultCodecs() {
|
||||
}
|
||||
|
||||
protected BaseDefaultCodecs(BaseDefaultCodecs other) {
|
||||
this.jackson2JsonDecoder = other.jackson2JsonDecoder;
|
||||
this.jackson2JsonEncoder = other.jackson2JsonEncoder;
|
||||
this.protobufDecoder = other.protobufDecoder;
|
||||
this.protobufEncoder = other.protobufEncoder;
|
||||
this.jaxb2Decoder = other.jaxb2Decoder;
|
||||
this.jaxb2Encoder = other.jaxb2Encoder;
|
||||
this.maxInMemorySize = other.maxInMemorySize;
|
||||
this.enableLoggingRequestDetails = other.enableLoggingRequestDetails;
|
||||
this.registerDefaults = other.registerDefaults;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jackson2JsonDecoder(Decoder<?> decoder) {
|
||||
this.jackson2JsonDecoder = decoder;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -49,6 +49,17 @@ class ClientDefaultCodecsImpl extends BaseDefaultCodecs implements ClientCodecCo
|
||||
private Supplier<List<HttpMessageWriter<?>>> partWritersSupplier;
|
||||
|
||||
|
||||
ClientDefaultCodecsImpl() {
|
||||
}
|
||||
|
||||
ClientDefaultCodecsImpl(ClientDefaultCodecsImpl other) {
|
||||
super(other);
|
||||
this.multipartCodecs = new DefaultMultipartCodecs(other.multipartCodecs);
|
||||
this.sseDecoder = other.sseDecoder;
|
||||
this.partWritersSupplier = other.partWritersSupplier;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set a supplier for part writers to use when
|
||||
* {@link #multipartCodecs()} are not explicitly configured.
|
||||
@@ -73,6 +84,14 @@ class ClientDefaultCodecsImpl extends BaseDefaultCodecs implements ClientCodecCo
|
||||
this.sseDecoder = decoder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientDefaultCodecsImpl clone() {
|
||||
ClientDefaultCodecsImpl codecs = new ClientDefaultCodecsImpl();
|
||||
codecs.multipartCodecs = this.multipartCodecs;
|
||||
codecs.sseDecoder = this.sseDecoder;
|
||||
codecs.partWritersSupplier = this.partWritersSupplier;
|
||||
return codecs;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void extendObjectReaders(List<HttpMessageReader<?>> objectReaders) {
|
||||
@@ -116,6 +135,17 @@ class ClientDefaultCodecsImpl extends BaseDefaultCodecs implements ClientCodecCo
|
||||
|
||||
private final List<HttpMessageWriter<?>> writers = new ArrayList<>();
|
||||
|
||||
|
||||
DefaultMultipartCodecs() {
|
||||
}
|
||||
|
||||
DefaultMultipartCodecs(@Nullable DefaultMultipartCodecs other) {
|
||||
if (other != null) {
|
||||
this.writers.addAll(other.writers);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ClientCodecConfigurer.MultipartCodecs encoder(Encoder<?> encoder) {
|
||||
writer(new EncoderHttpMessageWriter<>(encoder));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -26,14 +26,30 @@ import org.springframework.http.codec.ClientCodecConfigurer;
|
||||
*/
|
||||
public class DefaultClientCodecConfigurer extends BaseCodecConfigurer implements ClientCodecConfigurer {
|
||||
|
||||
|
||||
public DefaultClientCodecConfigurer() {
|
||||
super(new ClientDefaultCodecsImpl());
|
||||
((ClientDefaultCodecsImpl) defaultCodecs()).setPartWritersSupplier(() -> getWritersInternal(true));
|
||||
}
|
||||
|
||||
private DefaultClientCodecConfigurer(DefaultClientCodecConfigurer other) {
|
||||
super(other);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ClientDefaultCodecs defaultCodecs() {
|
||||
return (ClientDefaultCodecs) super.defaultCodecs();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultClientCodecConfigurer clone() {
|
||||
return new DefaultClientCodecConfigurer(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BaseDefaultCodecs cloneDefaultCodecs() {
|
||||
return new ClientDefaultCodecsImpl((ClientDefaultCodecsImpl) defaultCodecs());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -26,13 +26,28 @@ import org.springframework.http.codec.ServerCodecConfigurer;
|
||||
*/
|
||||
public class DefaultServerCodecConfigurer extends BaseCodecConfigurer implements ServerCodecConfigurer {
|
||||
|
||||
|
||||
public DefaultServerCodecConfigurer() {
|
||||
super(new ServerDefaultCodecsImpl());
|
||||
}
|
||||
|
||||
private DefaultServerCodecConfigurer(BaseCodecConfigurer other) {
|
||||
super(other);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ServerDefaultCodecs defaultCodecs() {
|
||||
return (ServerDefaultCodecs) super.defaultCodecs();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultServerCodecConfigurer clone() {
|
||||
return new DefaultServerCodecConfigurer(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BaseDefaultCodecs cloneDefaultCodecs() {
|
||||
return new ServerDefaultCodecsImpl((ServerDefaultCodecsImpl) defaultCodecs());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,16 @@ class ServerDefaultCodecsImpl extends BaseDefaultCodecs implements ServerCodecCo
|
||||
private Encoder<?> sseEncoder;
|
||||
|
||||
|
||||
ServerDefaultCodecsImpl() {
|
||||
}
|
||||
|
||||
ServerDefaultCodecsImpl(ServerDefaultCodecsImpl other) {
|
||||
super(other);
|
||||
this.multipartReader = other.multipartReader;
|
||||
this.sseEncoder = other.sseEncoder;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void multipartReader(HttpMessageReader<?> reader) {
|
||||
this.multipartReader = reader;
|
||||
|
||||
Reference in New Issue
Block a user