Skip to content

Commit 634aba4

Browse files
committed
Fix cloning issue in CodecConfigurer for multipart writers
Backport of b236176 Closes gh-24194
1 parent 26a2d38 commit 634aba4

File tree

5 files changed

+73
-41
lines changed

5 files changed

+73
-41
lines changed

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

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -105,25 +105,12 @@ public List<HttpMessageReader<?>> getReaders() {
105105
@Override
106106
public List<HttpMessageWriter<?>> getWriters() {
107107
this.defaultCodecs.applyDefaultConfig(this.customCodecs);
108-
return getWritersInternal(false);
109-
}
110-
111108

112-
/**
113-
* Internal method that returns the configured writers.
114-
* @param forMultipart whether to returns writers for general use ("false"),
115-
* or for multipart requests only ("true"). Generally the two sets are the
116-
* same except for the multipart writer itself.
117-
*/
118-
protected List<HttpMessageWriter<?>> getWritersInternal(boolean forMultipart) {
119109
List<HttpMessageWriter<?>> result = new ArrayList<>();
120-
121-
result.addAll(this.defaultCodecs.getTypedWriters(forMultipart));
110+
result.addAll(this.defaultCodecs.getTypedWriters());
122111
result.addAll(this.customCodecs.getTypedWriters().keySet());
123-
124-
result.addAll(this.defaultCodecs.getObjectWriters(forMultipart));
112+
result.addAll(this.defaultCodecs.getObjectWriters());
125113
result.addAll(this.customCodecs.getObjectWriters().keySet());
126-
127114
result.addAll(this.defaultCodecs.getCatchAllWriters());
128115
return result;
129116
}

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

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -354,13 +354,23 @@ final List<HttpMessageReader<?>> getCatchAllReaders() {
354354
}
355355

356356
/**
357-
* Return writers that support specific types.
358-
* @param forMultipart whether to returns writers for general use ("false"),
359-
* or for multipart requests only ("true"). Generally the two sets are the
360-
* same except for the multipart writer itself.
357+
* Return all writers that support specific types.
358+
*/
359+
@SuppressWarnings({"rawtypes" })
360+
final List<HttpMessageWriter<?>> getTypedWriters() {
361+
if (!this.registerDefaults) {
362+
return Collections.emptyList();
363+
}
364+
List<HttpMessageWriter<?>> writers = getBaseTypedWriters();
365+
extendTypedWriters(writers);
366+
return writers;
367+
}
368+
369+
/**
370+
* Return "base" typed writers only, i.e. common to client and server.
361371
*/
362372
@SuppressWarnings("unchecked")
363-
final List<HttpMessageWriter<?>> getTypedWriters(boolean forMultipart) {
373+
final List<HttpMessageWriter<?>> getBaseTypedWriters() {
364374
if (!this.registerDefaults) {
365375
return Collections.emptyList();
366376
}
@@ -370,10 +380,6 @@ final List<HttpMessageWriter<?>> getTypedWriters(boolean forMultipart) {
370380
writers.add(new EncoderHttpMessageWriter<>(new DataBufferEncoder()));
371381
writers.add(new ResourceHttpMessageWriter());
372382
writers.add(new EncoderHttpMessageWriter<>(CharSequenceEncoder.textPlainOnly()));
373-
// No client or server specific multipart writers currently..
374-
if (!forMultipart) {
375-
extendTypedWriters(writers);
376-
}
377383
if (protobufPresent) {
378384
Encoder<?> encoder = this.protobufEncoder != null ? this.protobufEncoder : new ProtobufEncoder();
379385
writers.add(new ProtobufHttpMessageWriter((Encoder) encoder));
@@ -389,14 +395,20 @@ protected void extendTypedWriters(List<HttpMessageWriter<?>> typedWriters) {
389395

390396
/**
391397
* Return Object writers (JSON, XML, SSE).
392-
* @param forMultipart whether to returns writers for general use ("false"),
393-
* or for multipart requests only ("true"). Generally the two sets are the
394-
* same except for the multipart writer itself.
395398
*/
396-
final List<HttpMessageWriter<?>> getObjectWriters(boolean forMultipart) {
399+
final List<HttpMessageWriter<?>> getObjectWriters() {
397400
if (!this.registerDefaults) {
398401
return Collections.emptyList();
399402
}
403+
List<HttpMessageWriter<?>> writers = getBaseObjectWriters();
404+
extendObjectWriters(writers);
405+
return writers;
406+
}
407+
408+
/**
409+
* Return "base" object writers only, i.e. common to client and server.
410+
*/
411+
final List<HttpMessageWriter<?>> getBaseObjectWriters() {
400412
List<HttpMessageWriter<?>> writers = new ArrayList<>();
401413
if (jackson2Present) {
402414
writers.add(new EncoderHttpMessageWriter<>(getJackson2JsonEncoder()));
@@ -408,10 +420,6 @@ final List<HttpMessageWriter<?>> getObjectWriters(boolean forMultipart) {
408420
Encoder<?> encoder = this.jaxb2Encoder != null ? this.jaxb2Encoder : new Jaxb2XmlEncoder();
409421
writers.add(new EncoderHttpMessageWriter<>(encoder));
410422
}
411-
// No client or server specific multipart writers currently..
412-
if (!forMultipart) {
413-
extendObjectWriters(writers);
414-
}
415423
return writers;
416424
}
417425

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

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,9 @@ class ClientDefaultCodecsImpl extends BaseDefaultCodecs implements ClientCodecCo
5454

5555
ClientDefaultCodecsImpl(ClientDefaultCodecsImpl other) {
5656
super(other);
57-
this.multipartCodecs = new DefaultMultipartCodecs(other.multipartCodecs);
57+
this.multipartCodecs = (other.multipartCodecs != null ?
58+
new DefaultMultipartCodecs(other.multipartCodecs) : null);
5859
this.sseDecoder = other.sseDecoder;
59-
this.partWritersSupplier = other.partWritersSupplier;
6060
}
6161

6262

@@ -132,10 +132,8 @@ private static class DefaultMultipartCodecs implements ClientCodecConfigurer.Mul
132132
DefaultMultipartCodecs() {
133133
}
134134

135-
DefaultMultipartCodecs(@Nullable DefaultMultipartCodecs other) {
136-
if (other != null) {
137-
this.writers.addAll(other.writers);
138-
}
135+
DefaultMultipartCodecs(DefaultMultipartCodecs other) {
136+
this.writers.addAll(other.writers);
139137
}
140138

141139

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

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,11 @@
1616

1717
package org.springframework.http.codec.support;
1818

19+
import java.util.ArrayList;
20+
import java.util.List;
21+
1922
import org.springframework.http.codec.ClientCodecConfigurer;
23+
import org.springframework.http.codec.HttpMessageWriter;
2024

2125
/**
2226
* Default implementation of {@link ClientCodecConfigurer}.
@@ -29,11 +33,12 @@ public class DefaultClientCodecConfigurer extends BaseCodecConfigurer implements
2933

3034
public DefaultClientCodecConfigurer() {
3135
super(new ClientDefaultCodecsImpl());
32-
((ClientDefaultCodecsImpl) defaultCodecs()).setPartWritersSupplier(() -> getWritersInternal(true));
36+
((ClientDefaultCodecsImpl) defaultCodecs()).setPartWritersSupplier(this::getPartWriters);
3337
}
3438

3539
private DefaultClientCodecConfigurer(DefaultClientCodecConfigurer other) {
3640
super(other);
41+
((ClientDefaultCodecsImpl) defaultCodecs()).setPartWritersSupplier(this::getPartWriters);
3742
}
3843

3944

@@ -52,4 +57,14 @@ protected BaseDefaultCodecs cloneDefaultCodecs() {
5257
return new ClientDefaultCodecsImpl((ClientDefaultCodecsImpl) defaultCodecs());
5358
}
5459

60+
private List<HttpMessageWriter<?>> getPartWriters() {
61+
List<HttpMessageWriter<?>> result = new ArrayList<>();
62+
result.addAll(this.customCodecs.getTypedWriters().keySet());
63+
result.addAll(this.defaultCodecs.getBaseTypedWriters());
64+
result.addAll(this.customCodecs.getObjectWriters().keySet());
65+
result.addAll(this.defaultCodecs.getBaseObjectWriters());
66+
result.addAll(this.defaultCodecs.getCatchAllWriters());
67+
return result;
68+
}
69+
5570
}

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

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,8 @@ public void defaultWriters() {
106106
assertEquals(DataBufferEncoder.class, getNextEncoder(writers).getClass());
107107
assertEquals(ResourceHttpMessageWriter.class, writers.get(index.getAndIncrement()).getClass());
108108
assertStringEncoder(getNextEncoder(writers), true);
109-
assertEquals(MultipartHttpMessageWriter.class, writers.get(this.index.getAndIncrement()).getClass());
110109
assertEquals(ProtobufHttpMessageWriter.class, writers.get(index.getAndIncrement()).getClass());
110+
assertEquals(MultipartHttpMessageWriter.class, writers.get(this.index.getAndIncrement()).getClass());
111111
assertEquals(Jackson2JsonEncoder.class, getNextEncoder(writers).getClass());
112112
assertEquals(Jackson2SmileEncoder.class, getNextEncoder(writers).getClass());
113113
assertEquals(Jaxb2XmlEncoder.class, getNextEncoder(writers).getClass());
@@ -161,7 +161,7 @@ public void enableLoggingRequestDetails() {
161161
}
162162

163163
@Test
164-
public void cloneConfigurer() {
164+
public void clonedConfigurer() {
165165
ClientCodecConfigurer clone = this.configurer.clone();
166166

167167
Jackson2JsonDecoder jackson2Decoder = new Jackson2JsonDecoder();
@@ -186,6 +186,30 @@ public void cloneConfigurer() {
186186
assertEquals(10, writers.size());
187187
}
188188

189+
@Test // gh-24194
190+
public void cloneShouldNotDropMultipartCodecs() {
191+
192+
ClientCodecConfigurer clone = this.configurer.clone();
193+
List<HttpMessageWriter<?>> writers =
194+
findCodec(clone.getWriters(), MultipartHttpMessageWriter.class).getPartWriters();
195+
196+
assertEquals(10, writers.size());
197+
}
198+
199+
@Test
200+
public void cloneShouldNotBeImpactedByChangesToOriginal() {
201+
202+
ClientCodecConfigurer clone = this.configurer.clone();
203+
204+
this.configurer.registerDefaults(false);
205+
this.configurer.customCodecs().register(new Jackson2JsonEncoder());
206+
207+
List<HttpMessageWriter<?>> writers =
208+
findCodec(clone.getWriters(), MultipartHttpMessageWriter.class).getPartWriters();
209+
210+
assertEquals(10, writers.size());
211+
}
212+
189213
private Decoder<?> getNextDecoder(List<HttpMessageReader<?>> readers) {
190214
HttpMessageReader<?> reader = readers.get(this.index.getAndIncrement());
191215
assertEquals(DecoderHttpMessageReader.class, reader.getClass());

0 commit comments

Comments
 (0)