Skip to content

Commit acfeb77

Browse files
committed
Polishing
See gh-23961
1 parent d420939 commit acfeb77

File tree

18 files changed

+250
-104
lines changed

18 files changed

+250
-104
lines changed

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

-6
Original file line numberDiff line numberDiff line change
@@ -143,12 +143,6 @@ public WebTestClient.Builder exchangeStrategies(ExchangeStrategies strategies) {
143143
return this;
144144
}
145145

146-
@Override
147-
public WebTestClient.Builder exchangeStrategies(ExchangeStrategies.Builder strategies) {
148-
this.webClientBuilder.exchangeStrategies(strategies);
149-
return this;
150-
}
151-
152146
@Override
153147
public WebTestClient.Builder exchangeStrategies(Consumer<ExchangeStrategies.Builder> configurer) {
154148
this.webClientBuilder.exchangeStrategies(configurer);

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

+10-19
Original file line numberDiff line numberDiff line change
@@ -444,30 +444,21 @@ interface Builder {
444444

445445
/**
446446
* Configure the {@link ExchangeStrategies} to use.
447-
* <p>This is useful for changing the default settings, yet still allowing
448-
* further customizations via {@link #exchangeStrategies(Consumer)}.
449-
* By default {@link ExchangeStrategies#withDefaults()} is used.
447+
* <p>Note that in a scenario where the builder is configured by
448+
* multiple parties, it is preferable to use
449+
* {@link #exchangeStrategies(Consumer)} in order to customize the same
450+
* {@code ExchangeStrategies}. This method here sets the strategies that
451+
* everyone else then can customize.
452+
* <p>By default this is {@link ExchangeStrategies#withDefaults()}.
450453
* @param strategies the strategies to use
451-
* @deprecated as of 5.1 in favor of {@link #exchangeStrategies(ExchangeStrategies.Builder)}
452454
*/
453-
@Deprecated
454455
Builder exchangeStrategies(ExchangeStrategies strategies);
455456

456457
/**
457-
* Configure the {@link ExchangeStrategies.Builder} to use.
458-
* <p>This is useful for changing the default settings, yet still allowing
459-
* further customizations via {@link #exchangeStrategies(Consumer)}.
460-
* By default {@link ExchangeStrategies#builder()} is used.
461-
* @param strategies the strategies to use
462-
* @since 5.1.12
463-
*/
464-
Builder exchangeStrategies(ExchangeStrategies.Builder strategies);
465-
466-
/**
467-
* Customize the {@link ExchangeStrategies}.
468-
* <p>Allows further customization on {@link ExchangeStrategies},
469-
* mutating them if they were {@link #exchangeStrategies(ExchangeStrategies) set},
470-
* or starting from {@link ExchangeStrategies#withDefaults() defaults}.
458+
* Customize the strategies configured via
459+
* {@link #exchangeStrategies(ExchangeStrategies)}. This method is
460+
* designed for use in scenarios where multiple parties wish to update
461+
* the {@code ExchangeStrategies}.
471462
* @since 5.1.12
472463
*/
473464
Builder exchangeStrategies(Consumer<ExchangeStrategies.Builder> configurer);

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,12 @@ public interface ClientCodecConfigurer extends CodecConfigurer {
6464
ClientDefaultCodecs defaultCodecs();
6565

6666
/**
67-
* Clone this {@link ClientCodecConfigurer}.
67+
* {@inheritDoc}.
6868
*/
6969
@Override
7070
ClientCodecConfigurer clone();
7171

72+
7273
/**
7374
* Static factory method for a {@code ClientCodecConfigurer}.
7475
*/

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

+4-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,10 @@ public interface CodecConfigurer {
8888
List<HttpMessageWriter<?>> getWriters();
8989

9090
/**
91-
* Clone this {@link CodecConfigurer}.
91+
* Create a copy of this {@link CodecConfigurer}. The returned clone has its
92+
* own lists of default and custom codecs and generally can be configured
93+
* independently. Keep in mind however that codec instances (if any are
94+
* configured) are themselves not cloned.
9295
* @since 5.1.12
9396
*/
9497
CodecConfigurer clone();

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

+6
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,12 @@ public interface ServerCodecConfigurer extends CodecConfigurer {
6262
@Override
6363
ServerDefaultCodecs defaultCodecs();
6464

65+
/**
66+
* {@inheritDoc}.
67+
*/
68+
@Override
69+
ServerCodecConfigurer clone();
70+
6571

6672
/**
6773
* Static factory method for a {@code ServerCodecConfigurer}.

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

+18-14
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
* @author Brian Clozel
3838
* @since 5.0
3939
*/
40-
class BaseCodecConfigurer implements CodecConfigurer {
40+
abstract class BaseCodecConfigurer implements CodecConfigurer {
4141

4242
protected final BaseDefaultCodecs defaultCodecs;
4343

@@ -55,14 +55,21 @@ class BaseCodecConfigurer implements CodecConfigurer {
5555
}
5656

5757
/**
58-
* Constructor with another {@link BaseCodecConfigurer} to copy
59-
* the configuration from.
58+
* Create a deep copy of the given {@link BaseCodecConfigurer}.
59+
* @since 5.1.12
6060
*/
61-
BaseCodecConfigurer(BaseCodecConfigurer other) {
61+
protected BaseCodecConfigurer(BaseCodecConfigurer other) {
6262
this.defaultCodecs = other.cloneDefaultCodecs();
6363
this.customCodecs = new DefaultCustomCodecs(other.customCodecs);
6464
}
6565

66+
/**
67+
* Sub-classes should override this to create deep copy of
68+
* {@link BaseDefaultCodecs} which can can be client or server specific.
69+
* @since 5.1.12
70+
*/
71+
protected abstract BaseDefaultCodecs cloneDefaultCodecs();
72+
6673

6774
@Override
6875
public DefaultCodecs defaultCodecs() {
@@ -99,16 +106,6 @@ public List<HttpMessageWriter<?>> getWriters() {
99106
}
100107

101108

102-
@Override
103-
public CodecConfigurer clone() {
104-
return new BaseCodecConfigurer(this);
105-
}
106-
107-
protected BaseDefaultCodecs cloneDefaultCodecs() {
108-
return new BaseDefaultCodecs(this.defaultCodecs);
109-
}
110-
111-
112109
/**
113110
* Internal method that returns the configured writers.
114111
* @param forMultipart whether to returns writers for general use ("false"),
@@ -128,6 +125,9 @@ protected List<HttpMessageWriter<?>> getWritersInternal(boolean forMultipart) {
128125
return result;
129126
}
130127

128+
@Override
129+
public abstract CodecConfigurer clone();
130+
131131

132132
/**
133133
* Default implementation of {@code CustomCodecs}.
@@ -146,6 +146,10 @@ protected static final class DefaultCustomCodecs implements CustomCodecs {
146146
DefaultCustomCodecs() {
147147
}
148148

149+
/**
150+
* Create a deep copy of the given {@link DefaultCustomCodecs}.
151+
* @since 5.1.12
152+
*/
149153
DefaultCustomCodecs(DefaultCustomCodecs other) {
150154
other.typedReaders.addAll(this.typedReaders);
151155
other.typedWriters.addAll(this.typedWriters);

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

+3
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,9 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs {
109109
BaseDefaultCodecs() {
110110
}
111111

112+
/**
113+
* Create a deep copy of the given {@link BaseDefaultCodecs}.
114+
*/
112115
protected BaseDefaultCodecs(BaseDefaultCodecs other) {
113116
this.jackson2JsonDecoder = other.jackson2JsonDecoder;
114117
this.jackson2JsonEncoder = other.jackson2JsonEncoder;

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

+42
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import java.util.Collections;
2323
import java.util.List;
2424
import java.util.concurrent.atomic.AtomicInteger;
25+
import java.util.stream.Collectors;
2526

2627
import org.junit.jupiter.api.Test;
2728
import reactor.core.publisher.Flux;
@@ -123,6 +124,47 @@ public void jackson2EncoderOverride() {
123124
.filter(e -> e == decoder).orElse(null)).isSameAs(decoder);
124125
}
125126

127+
@Test
128+
public void cloneConfigurer() {
129+
ClientCodecConfigurer clone = this.configurer.clone();
130+
131+
Jackson2JsonDecoder jackson2Decoder = new Jackson2JsonDecoder();
132+
clone.defaultCodecs().serverSentEventDecoder(jackson2Decoder);
133+
clone.defaultCodecs().multipartCodecs().encoder(new Jackson2SmileEncoder());
134+
clone.defaultCodecs().multipartCodecs().writer(new ResourceHttpMessageWriter());
135+
136+
// Clone has the customizations
137+
138+
Decoder<?> sseDecoder = clone.getReaders().stream()
139+
.filter(reader -> reader instanceof ServerSentEventHttpMessageReader)
140+
.map(reader -> ((ServerSentEventHttpMessageReader) reader).getDecoder())
141+
.findFirst()
142+
.get();
143+
144+
List<HttpMessageWriter<?>> multipartWriters = clone.getWriters().stream()
145+
.filter(writer -> writer instanceof MultipartHttpMessageWriter)
146+
.flatMap(writer -> ((MultipartHttpMessageWriter) writer).getPartWriters().stream())
147+
.collect(Collectors.toList());
148+
149+
assertThat(sseDecoder).isSameAs(jackson2Decoder);
150+
assertThat(multipartWriters).hasSize(2);
151+
152+
// Original does not have the customizations
153+
154+
sseDecoder = this.configurer.getReaders().stream()
155+
.filter(reader -> reader instanceof ServerSentEventHttpMessageReader)
156+
.map(reader -> ((ServerSentEventHttpMessageReader) reader).getDecoder())
157+
.findFirst()
158+
.get();
159+
160+
multipartWriters = this.configurer.getWriters().stream()
161+
.filter(writer -> writer instanceof MultipartHttpMessageWriter)
162+
.flatMap(writer -> ((MultipartHttpMessageWriter) writer).getPartWriters().stream())
163+
.collect(Collectors.toList());
164+
165+
assertThat(sseDecoder).isNotSameAs(jackson2Decoder);
166+
assertThat(multipartWriters).hasSize(10);
167+
}
126168

127169
private Decoder<?> getNextDecoder(List<HttpMessageReader<?>> readers) {
128170
HttpMessageReader<?> reader = readers.get(this.index.getAndIncrement());

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

+76-5
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import java.util.List;
2020
import java.util.concurrent.atomic.AtomicInteger;
21+
import java.util.stream.Collectors;
2122

2223
import com.google.protobuf.ExtensionRegistry;
2324
import org.junit.jupiter.api.Test;
@@ -42,6 +43,8 @@
4243
import org.springframework.http.codec.HttpMessageWriter;
4344
import org.springframework.http.codec.ResourceHttpMessageReader;
4445
import org.springframework.http.codec.ResourceHttpMessageWriter;
46+
import org.springframework.http.codec.ServerSentEventHttpMessageReader;
47+
import org.springframework.http.codec.ServerSentEventHttpMessageWriter;
4548
import org.springframework.http.codec.json.Jackson2JsonDecoder;
4649
import org.springframework.http.codec.json.Jackson2JsonEncoder;
4750
import org.springframework.http.codec.json.Jackson2SmileDecoder;
@@ -269,11 +272,68 @@ public void encoderDecoderOverrides() {
269272
}
270273

271274
@Test
272-
public void cloneConfigurer() {
273-
CodecConfigurer clone = this.configurer.clone();
275+
public void cloneCustomCodecs() {
274276
this.configurer.registerDefaults(false);
277+
CodecConfigurer clone = this.configurer.clone();
278+
279+
clone.customCodecs().encoder(new Jackson2JsonEncoder());
280+
clone.customCodecs().decoder(new Jackson2JsonDecoder());
281+
clone.customCodecs().reader(new ServerSentEventHttpMessageReader());
282+
clone.customCodecs().writer(new ServerSentEventHttpMessageWriter());
283+
275284
assertThat(this.configurer.getReaders().size()).isEqualTo(0);
276-
assertThat(clone.getReaders().size()).isEqualTo(11);
285+
assertThat(this.configurer.getWriters().size()).isEqualTo(0);
286+
assertThat(clone.getReaders().size()).isEqualTo(2);
287+
assertThat(clone.getWriters().size()).isEqualTo(2);
288+
}
289+
290+
@Test
291+
public void cloneDefaultCodecs() {
292+
CodecConfigurer clone = this.configurer.clone();
293+
294+
Jackson2JsonDecoder jacksonDecoder = new Jackson2JsonDecoder();
295+
Jackson2JsonEncoder jacksonEncoder = new Jackson2JsonEncoder();
296+
Jaxb2XmlDecoder jaxb2Decoder = new Jaxb2XmlDecoder();
297+
Jaxb2XmlEncoder jaxb2Encoder = new Jaxb2XmlEncoder();
298+
ProtobufDecoder protoDecoder = new ProtobufDecoder();
299+
ProtobufEncoder protoEncoder = new ProtobufEncoder();
300+
301+
clone.defaultCodecs().jackson2JsonDecoder(jacksonDecoder);
302+
clone.defaultCodecs().jackson2JsonEncoder(jacksonEncoder);
303+
clone.defaultCodecs().jaxb2Decoder(jaxb2Decoder);
304+
clone.defaultCodecs().jaxb2Encoder(jaxb2Encoder);
305+
clone.defaultCodecs().protobufDecoder(protoDecoder);
306+
clone.defaultCodecs().protobufEncoder(protoEncoder);
307+
308+
// Clone has the customized the customizations
309+
310+
List<Decoder<?>> decoders = clone.getReaders().stream()
311+
.filter(reader -> reader instanceof DecoderHttpMessageReader)
312+
.map(reader -> ((DecoderHttpMessageReader<?>) reader).getDecoder())
313+
.collect(Collectors.toList());
314+
315+
List<Encoder<?>> encoders = clone.getWriters().stream()
316+
.filter(writer -> writer instanceof EncoderHttpMessageWriter)
317+
.map(reader -> ((EncoderHttpMessageWriter<?>) reader).getEncoder())
318+
.collect(Collectors.toList());
319+
320+
assertThat(decoders).contains(jacksonDecoder, jaxb2Decoder, protoDecoder);
321+
assertThat(encoders).contains(jacksonEncoder, jaxb2Encoder, protoEncoder);
322+
323+
// Original does not have the customizations
324+
325+
decoders = this.configurer.getReaders().stream()
326+
.filter(reader -> reader instanceof DecoderHttpMessageReader)
327+
.map(reader -> ((DecoderHttpMessageReader<?>) reader).getDecoder())
328+
.collect(Collectors.toList());
329+
330+
encoders = this.configurer.getWriters().stream()
331+
.filter(writer -> writer instanceof EncoderHttpMessageWriter)
332+
.map(reader -> ((EncoderHttpMessageWriter<?>) reader).getEncoder())
333+
.collect(Collectors.toList());
334+
335+
assertThat(decoders).doesNotContain(jacksonDecoder, jaxb2Decoder, protoDecoder);
336+
assertThat(encoders).doesNotContain(jacksonEncoder, jaxb2Encoder, protoEncoder);
277337
}
278338

279339
private Decoder<?> getNextDecoder(List<HttpMessageReader<?>> readers) {
@@ -324,10 +384,21 @@ private void assertEncoderInstance(Encoder<?> encoder) {
324384
private static class TestCodecConfigurer extends BaseCodecConfigurer {
325385

326386
TestCodecConfigurer() {
327-
super(new TestDefaultCodecs());
387+
super(new BaseDefaultCodecs());
388+
}
389+
390+
TestCodecConfigurer(TestCodecConfigurer other) {
391+
super(other);
392+
}
393+
394+
@Override
395+
protected BaseDefaultCodecs cloneDefaultCodecs() {
396+
return new BaseDefaultCodecs((BaseDefaultCodecs) defaultCodecs());
328397
}
329398

330-
private static class TestDefaultCodecs extends BaseDefaultCodecs {
399+
@Override
400+
public CodecConfigurer clone() {
401+
return new TestCodecConfigurer(this);
331402
}
332403
}
333404

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

+44
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,50 @@ public void maxInMemorySize() {
154154
assertThat(((StringDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size);
155155
}
156156

157+
@Test
158+
public void cloneConfigurer() {
159+
ServerCodecConfigurer clone = this.configurer.clone();
160+
161+
MultipartHttpMessageReader reader = new MultipartHttpMessageReader(new SynchronossPartHttpMessageReader());
162+
Jackson2JsonEncoder encoder = new Jackson2JsonEncoder();
163+
clone.defaultCodecs().multipartReader(reader);
164+
clone.defaultCodecs().serverSentEventEncoder(encoder);
165+
166+
// Clone has the customizations
167+
168+
HttpMessageReader<?> actualReader = clone.getReaders().stream()
169+
.filter(r -> r instanceof MultipartHttpMessageReader)
170+
.findFirst()
171+
.get();
172+
173+
Encoder<?> actualEncoder = clone.getWriters().stream()
174+
.filter(writer -> writer instanceof ServerSentEventHttpMessageWriter)
175+
.map(writer -> ((ServerSentEventHttpMessageWriter) writer).getEncoder())
176+
.findFirst()
177+
.get();
178+
179+
180+
assertThat(actualReader).isSameAs(reader);
181+
assertThat(actualEncoder).isSameAs(encoder);
182+
183+
// Original does not have the customizations
184+
185+
actualReader = this.configurer.getReaders().stream()
186+
.filter(r -> r instanceof MultipartHttpMessageReader)
187+
.findFirst()
188+
.get();
189+
190+
actualEncoder = this.configurer.getWriters().stream()
191+
.filter(writer -> writer instanceof ServerSentEventHttpMessageWriter)
192+
.map(writer -> ((ServerSentEventHttpMessageWriter) writer).getEncoder())
193+
.findFirst()
194+
.get();
195+
196+
197+
assertThat(actualReader).isNotSameAs(reader);
198+
assertThat(actualEncoder).isNotSameAs(encoder);
199+
}
200+
157201
private Decoder<?> getNextDecoder(List<HttpMessageReader<?>> readers) {
158202
HttpMessageReader<?> reader = nextReader(readers);
159203
assertThat(reader.getClass()).isEqualTo(DecoderHttpMessageReader.class);

0 commit comments

Comments
 (0)