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