CodecConfigurer internal refactoring
Improve how HTTP message writers are obtained for general use vs for multipart requests.
This commit is contained in:
parent
6e5273f08e
commit
9b496b1264
|
@ -134,6 +134,14 @@ public class MultipartHttpMessageWriter implements HttpMessageWriter<MultiValueM
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the configured part writers.
|
||||
* @since 5.0.7
|
||||
*/
|
||||
public List<HttpMessageWriter<?>> getPartWriters() {
|
||||
return Collections.unmodifiableList(partWriters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the character set to use for part headers such as
|
||||
* "Content-Disposition" (and its filename parameter).
|
||||
|
|
|
@ -18,7 +18,6 @@ package org.springframework.http.codec.support;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.codec.Decoder;
|
||||
|
@ -28,6 +27,7 @@ import org.springframework.http.codec.DecoderHttpMessageReader;
|
|||
import org.springframework.http.codec.EncoderHttpMessageWriter;
|
||||
import org.springframework.http.codec.HttpMessageReader;
|
||||
import org.springframework.http.codec.HttpMessageWriter;
|
||||
import org.springframework.http.codec.multipart.MultipartHttpMessageWriter;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
|
@ -85,12 +85,22 @@ class BaseCodecConfigurer implements CodecConfigurer {
|
|||
|
||||
@Override
|
||||
public List<HttpMessageWriter<?>> getWriters() {
|
||||
return getWritersInternal(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method that returns the configured writers.
|
||||
* @param forMultipart whether to returns writers for general use ("false"),
|
||||
* or for multipart requests only ("true"). Generally the two sets are the
|
||||
* same except for the multipart writer itself.
|
||||
*/
|
||||
protected List<HttpMessageWriter<?>> getWritersInternal(boolean forMultipart) {
|
||||
List<HttpMessageWriter<?>> result = new ArrayList<>();
|
||||
|
||||
result.addAll(this.defaultCodecs.getTypedWriters());
|
||||
result.addAll(this.defaultCodecs.getTypedWriters(forMultipart));
|
||||
result.addAll(this.customCodecs.getTypedWriters());
|
||||
|
||||
result.addAll(this.defaultCodecs.getObjectWriters());
|
||||
result.addAll(this.defaultCodecs.getObjectWriters(forMultipart));
|
||||
result.addAll(this.customCodecs.getObjectWriters());
|
||||
|
||||
result.addAll(this.defaultCodecs.getCatchAllWriters());
|
||||
|
@ -98,17 +108,6 @@ class BaseCodecConfigurer implements CodecConfigurer {
|
|||
}
|
||||
|
||||
|
||||
// Accessors for use in sub-classes...
|
||||
|
||||
protected Supplier<List<HttpMessageWriter<?>>> getCustomTypedWriters() {
|
||||
return () -> this.customCodecs.typedWriters;
|
||||
}
|
||||
|
||||
protected Supplier<List<HttpMessageWriter<?>>> getCustomObjectWriters() {
|
||||
return () -> this.customCodecs.objectWriters;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Default implementation of {@code CustomCodecs}.
|
||||
*/
|
||||
|
|
|
@ -95,8 +95,9 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs {
|
|||
}
|
||||
|
||||
|
||||
// Package private access to the configured readers...
|
||||
|
||||
/**
|
||||
* Return readers that support specific types.
|
||||
*/
|
||||
final List<HttpMessageReader<?>> getTypedReaders() {
|
||||
if (!this.registerDefaults) {
|
||||
return Collections.emptyList();
|
||||
|
@ -112,9 +113,15 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs {
|
|||
return readers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook for client or server specific typed readers.
|
||||
*/
|
||||
protected void extendTypedReaders(List<HttpMessageReader<?>> typedReaders) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return Object readers (JSON, XML, SSE).
|
||||
*/
|
||||
final List<HttpMessageReader<?>> getObjectReaders() {
|
||||
if (!this.registerDefaults) {
|
||||
return Collections.emptyList();
|
||||
|
@ -133,9 +140,15 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs {
|
|||
return readers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook for client or server specific Object readers.
|
||||
*/
|
||||
protected void extendObjectReaders(List<HttpMessageReader<?>> objectReaders) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return readers that need to be at the end, after all others.
|
||||
*/
|
||||
final List<HttpMessageReader<?>> getCatchAllReaders() {
|
||||
if (!this.registerDefaults) {
|
||||
return Collections.emptyList();
|
||||
|
@ -145,10 +158,13 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs {
|
|||
return result;
|
||||
}
|
||||
|
||||
|
||||
// Package private access to the configured writers...
|
||||
|
||||
final List<HttpMessageWriter<?>> getTypedWriters() {
|
||||
/**
|
||||
* Return writers that support specific types.
|
||||
* @param forMultipart whether to returns writers for general use ("false"),
|
||||
* or for multipart requests only ("true"). Generally the two sets are the
|
||||
* same except for the multipart writer itself.
|
||||
*/
|
||||
final List<HttpMessageWriter<?>> getTypedWriters(boolean forMultipart) {
|
||||
if (!this.registerDefaults) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
@ -158,14 +174,26 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs {
|
|||
writers.add(new EncoderHttpMessageWriter<>(new DataBufferEncoder()));
|
||||
writers.add(new ResourceHttpMessageWriter());
|
||||
writers.add(new EncoderHttpMessageWriter<>(CharSequenceEncoder.textPlainOnly()));
|
||||
extendTypedWriters(writers);
|
||||
// No client or server specific multipart writers currently..
|
||||
if (!forMultipart) {
|
||||
extendTypedWriters(writers);
|
||||
}
|
||||
return writers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook for client or server specific typed writers.
|
||||
*/
|
||||
protected void extendTypedWriters(List<HttpMessageWriter<?>> typedWriters) {
|
||||
}
|
||||
|
||||
final List<HttpMessageWriter<?>> getObjectWriters() {
|
||||
/**
|
||||
* Return Object writers (JSON, XML, SSE).
|
||||
* @param forMultipart whether to returns writers for general use ("false"),
|
||||
* or for multipart requests only ("true"). Generally the two sets are the
|
||||
* same except for the multipart writer itself.
|
||||
*/
|
||||
final List<HttpMessageWriter<?>> getObjectWriters(boolean forMultipart) {
|
||||
if (!this.registerDefaults) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
@ -179,13 +207,22 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs {
|
|||
if (jaxb2Present) {
|
||||
writers.add(new EncoderHttpMessageWriter<>(new Jaxb2XmlEncoder()));
|
||||
}
|
||||
extendObjectWriters(writers);
|
||||
// No client or server specific multipart writers currently..
|
||||
if (!forMultipart) {
|
||||
extendObjectWriters(writers);
|
||||
}
|
||||
return writers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook for client or server specific Object writers.
|
||||
*/
|
||||
protected void extendObjectWriters(List<HttpMessageWriter<?>> objectWriters) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return writers that need to be at the end, after all others.
|
||||
*/
|
||||
List<HttpMessageWriter<?>> getCatchAllWriters() {
|
||||
if (!this.registerDefaults) {
|
||||
return Collections.emptyList();
|
||||
|
|
|
@ -29,7 +29,6 @@ import org.springframework.http.codec.HttpMessageWriter;
|
|||
import org.springframework.http.codec.ServerSentEventHttpMessageReader;
|
||||
import org.springframework.http.codec.multipart.MultipartHttpMessageWriter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link ClientCodecConfigurer.ClientDefaultCodecs}.
|
||||
|
@ -45,18 +44,17 @@ class ClientDefaultCodecsImpl extends BaseDefaultCodecs implements ClientCodecCo
|
|||
private Decoder<?> sseDecoder;
|
||||
|
||||
@Nullable
|
||||
private Supplier<List<HttpMessageWriter<?>>> customTypedWriters;
|
||||
|
||||
@Nullable
|
||||
private Supplier<List<HttpMessageWriter<?>>> customObjectWriters;
|
||||
private Supplier<List<HttpMessageWriter<?>>> partWritersSupplier;
|
||||
|
||||
|
||||
void initCustomTypedWriters(Supplier<List<HttpMessageWriter<?>>> supplier) {
|
||||
this.customTypedWriters = supplier;
|
||||
}
|
||||
|
||||
void initCustomObjectWriters(Supplier<List<HttpMessageWriter<?>>> supplier) {
|
||||
this.customObjectWriters = supplier;
|
||||
/**
|
||||
* Set a supplier for part writers to use when
|
||||
* {@link #multipartCodecs()} are not explicitly configured.
|
||||
* That's the same set of writers as for general except for the multipart
|
||||
* writer itself.
|
||||
*/
|
||||
void setPartWritersSupplier(Supplier<List<HttpMessageWriter<?>>> supplier) {
|
||||
this.partWritersSupplier = supplier;
|
||||
}
|
||||
|
||||
|
||||
|
@ -86,36 +84,19 @@ class ClientDefaultCodecsImpl extends BaseDefaultCodecs implements ClientCodecCo
|
|||
|
||||
@Override
|
||||
protected void extendTypedWriters(List<HttpMessageWriter<?>> typedWriters) {
|
||||
|
||||
MultipartHttpMessageWriter multipartWriter = new MultipartHttpMessageWriter(
|
||||
resolvePartWriters(typedWriters, getObjectWriters()), new FormHttpMessageWriter());
|
||||
|
||||
typedWriters.add(multipartWriter);
|
||||
typedWriters.add(new MultipartHttpMessageWriter(getPartWriters(), new FormHttpMessageWriter()));
|
||||
}
|
||||
|
||||
private List<HttpMessageWriter<?>> resolvePartWriters(List<HttpMessageWriter<?>> typedWriters,
|
||||
List<HttpMessageWriter<?>> objectWriters) {
|
||||
|
||||
List<HttpMessageWriter<?>> partWriters;
|
||||
if (this.multipartCodecs != null) {
|
||||
partWriters = this.multipartCodecs.getWriters();
|
||||
}
|
||||
else {
|
||||
Assert.notNull(this.customTypedWriters, "Expected custom typed writers supplier.");
|
||||
Assert.notNull(this.customObjectWriters, "Expected custom object writers supplier.");
|
||||
|
||||
partWriters = new ArrayList<>(typedWriters);
|
||||
partWriters.addAll(this.customTypedWriters.get());
|
||||
|
||||
partWriters.addAll(objectWriters);
|
||||
partWriters.addAll(this.customObjectWriters.get());
|
||||
|
||||
partWriters.addAll(super.getCatchAllWriters());
|
||||
}
|
||||
return partWriters;
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
private List<HttpMessageWriter<?>> getPartWriters() {
|
||||
return this.multipartCodecs != null ?
|
||||
this.multipartCodecs.getWriters() : this.partWritersSupplier.get();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Default implementation of {@link ClientCodecConfigurer.MultipartCodecs}.
|
||||
*/
|
||||
private static class DefaultMultipartCodecs implements ClientCodecConfigurer.MultipartCodecs {
|
||||
|
||||
private final List<HttpMessageWriter<?>> writers = new ArrayList<>();
|
||||
|
@ -137,4 +118,5 @@ class ClientDefaultCodecsImpl extends BaseDefaultCodecs implements ClientCodecCo
|
|||
return this.writers;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -29,8 +29,7 @@ public class DefaultClientCodecConfigurer extends BaseCodecConfigurer implements
|
|||
|
||||
public DefaultClientCodecConfigurer() {
|
||||
super(new ClientDefaultCodecsImpl());
|
||||
((ClientDefaultCodecsImpl) defaultCodecs()).initCustomTypedWriters(getCustomTypedWriters());
|
||||
((ClientDefaultCodecsImpl) defaultCodecs()).initCustomObjectWriters(getCustomObjectWriters());
|
||||
((ClientDefaultCodecsImpl) defaultCodecs()).setPartWritersSupplier(() -> getWritersInternal(true));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ import org.springframework.http.MediaType;
|
|||
import org.springframework.http.codec.CodecConfigurer;
|
||||
import org.springframework.http.codec.DecoderHttpMessageReader;
|
||||
import org.springframework.http.codec.EncoderHttpMessageWriter;
|
||||
import org.springframework.http.codec.FormHttpMessageReader;
|
||||
import org.springframework.http.codec.HttpMessageReader;
|
||||
import org.springframework.http.codec.HttpMessageWriter;
|
||||
import org.springframework.http.codec.ResourceHttpMessageWriter;
|
||||
|
@ -66,12 +67,13 @@ public class CodecConfigurerTests {
|
|||
@Test
|
||||
public void defaultReaders() {
|
||||
List<HttpMessageReader<?>> readers = this.configurer.getReaders();
|
||||
assertEquals(9, readers.size());
|
||||
assertEquals(10, readers.size());
|
||||
assertEquals(ByteArrayDecoder.class, getNextDecoder(readers).getClass());
|
||||
assertEquals(ByteBufferDecoder.class, getNextDecoder(readers).getClass());
|
||||
assertEquals(DataBufferDecoder.class, getNextDecoder(readers).getClass());
|
||||
assertEquals(ResourceDecoder.class, getNextDecoder(readers).getClass());
|
||||
assertStringDecoder(getNextDecoder(readers), true);
|
||||
assertEquals(FormHttpMessageReader.class, readers.get(this.index.getAndIncrement()).getClass());
|
||||
assertEquals(Jackson2JsonDecoder.class, getNextDecoder(readers).getClass());
|
||||
assertEquals(Jackson2SmileDecoder.class, getNextDecoder(readers).getClass());
|
||||
assertEquals(Jaxb2XmlDecoder.class, getNextDecoder(readers).getClass());
|
||||
|
@ -115,12 +117,13 @@ public class CodecConfigurerTests {
|
|||
|
||||
List<HttpMessageReader<?>> readers = this.configurer.getReaders();
|
||||
|
||||
assertEquals(13, readers.size());
|
||||
assertEquals(14, readers.size());
|
||||
assertEquals(ByteArrayDecoder.class, getNextDecoder(readers).getClass());
|
||||
assertEquals(ByteBufferDecoder.class, getNextDecoder(readers).getClass());
|
||||
assertEquals(DataBufferDecoder.class, getNextDecoder(readers).getClass());
|
||||
assertEquals(ResourceDecoder.class, getNextDecoder(readers).getClass());
|
||||
assertEquals(StringDecoder.class, getNextDecoder(readers).getClass());
|
||||
assertEquals(FormHttpMessageReader.class, readers.get(this.index.getAndIncrement()).getClass());
|
||||
assertSame(customDecoder1, getNextDecoder(readers));
|
||||
assertSame(customReader1, readers.get(this.index.getAndIncrement()));
|
||||
assertEquals(Jackson2JsonDecoder.class, getNextDecoder(readers).getClass());
|
||||
|
|
Loading…
Reference in New Issue