From 9d65830133c96da18676555818f88c24a0b12753 Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Thu, 12 Dec 2019 17:01:01 +0000 Subject: [PATCH] CodecConfigurer implementation refactoring See gh-24124 --- .../http/codec/ClientCodecConfigurer.java | 2 + .../http/codec/CodecConfigurer.java | 9 +- .../http/codec/ServerCodecConfigurer.java | 3 + .../multipart/MultipartHttpMessageWriter.java | 10 ++ .../http/codec/support/BaseDefaultCodecs.java | 150 +++++++++++++----- .../support/ClientDefaultCodecsImpl.java | 19 +-- .../support/ServerDefaultCodecsImpl.java | 22 +-- .../support/ClientCodecConfigurerTests.java | 87 ++++++---- .../support/ServerCodecConfigurerTests.java | 58 +++---- 9 files changed, 232 insertions(+), 128 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/http/codec/ClientCodecConfigurer.java b/spring-web/src/main/java/org/springframework/http/codec/ClientCodecConfigurer.java index e41ec7348117..070b0610ee1f 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/ClientCodecConfigurer.java +++ b/spring-web/src/main/java/org/springframework/http/codec/ClientCodecConfigurer.java @@ -95,6 +95,8 @@ interface ClientDefaultCodecs extends DefaultCodecs { *

By default if this is not set, and Jackson is available, the * {@link #jackson2JsonDecoder} override is used instead. Use this property * if you want to further customize the SSE decoder. + *

Note that {@link #maxInMemorySize(int)}, if configured, will be + * applied to the given decoder. * @param decoder the decoder to use */ void serverSentEventDecoder(Decoder decoder); diff --git a/spring-web/src/main/java/org/springframework/http/codec/CodecConfigurer.java b/spring-web/src/main/java/org/springframework/http/codec/CodecConfigurer.java index 4caf849b1af2..8263b1242067 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/CodecConfigurer.java +++ b/spring-web/src/main/java/org/springframework/http/codec/CodecConfigurer.java @@ -109,6 +109,8 @@ interface DefaultCodecs { /** * Override the default Jackson JSON {@code Decoder}. + *

Note that {@link #maxInMemorySize(int)}, if configured, will be + * applied to the given decoder. * @param decoder the decoder instance to use * @see org.springframework.http.codec.json.Jackson2JsonDecoder */ @@ -123,6 +125,8 @@ interface DefaultCodecs { /** * Override the default Protobuf {@code Decoder}. + *

Note that {@link #maxInMemorySize(int)}, if configured, will be + * applied to the given decoder. * @param decoder the decoder instance to use * @since 5.1 * @see org.springframework.http.codec.protobuf.ProtobufDecoder @@ -140,6 +144,8 @@ interface DefaultCodecs { /** * Override the default JAXB2 {@code Decoder}. + *

Note that {@link #maxInMemorySize(int)}, if configured, will be + * applied to the given decoder. * @param decoder the decoder instance to use * @since 5.1.3 * @see org.springframework.http.codec.xml.Jaxb2XmlDecoder @@ -245,7 +251,8 @@ interface DefaultCodecConfig { * Whether to log form data at DEBUG level, and headers at TRACE level. * Both may contain sensitive information. */ - boolean isEnableLoggingRequestDetails(); + @Nullable + Boolean isEnableLoggingRequestDetails(); } } diff --git a/spring-web/src/main/java/org/springframework/http/codec/ServerCodecConfigurer.java b/spring-web/src/main/java/org/springframework/http/codec/ServerCodecConfigurer.java index 3d49092f593f..4bbefc8c939c 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/ServerCodecConfigurer.java +++ b/spring-web/src/main/java/org/springframework/http/codec/ServerCodecConfigurer.java @@ -91,6 +91,9 @@ interface ServerDefaultCodecs extends DefaultCodecs { * MultipartHttpMessageReader} created with an instance of * {@link org.springframework.http.codec.multipart.SynchronossPartHttpMessageReader * SynchronossPartHttpMessageReader}. + *

Note that {@link #maxInMemorySize(int)} and/or + * {@link #enableLoggingRequestDetails(boolean)}, if configured, will be + * applied to the given reader, if applicable. * @param reader the message reader to use for multipart requests. * @since 5.1.11 */ diff --git a/spring-web/src/main/java/org/springframework/http/codec/multipart/MultipartHttpMessageWriter.java b/spring-web/src/main/java/org/springframework/http/codec/multipart/MultipartHttpMessageWriter.java index f5245b61fa73..13a1dfdc684a 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/multipart/MultipartHttpMessageWriter.java +++ b/spring-web/src/main/java/org/springframework/http/codec/multipart/MultipartHttpMessageWriter.java @@ -149,6 +149,16 @@ public List> getPartWriters() { return Collections.unmodifiableList(this.partWriters); } + + /** + * Return the configured form writer. + * @since 5.1.13 + */ + @Nullable + public HttpMessageWriter> getFormWriter() { + return this.formWriter; + } + /** * Set the character set to use for part headers such as * "Content-Disposition" (and its filename parameter). diff --git a/spring-web/src/main/java/org/springframework/http/codec/support/BaseDefaultCodecs.java b/spring-web/src/main/java/org/springframework/http/codec/support/BaseDefaultCodecs.java index c3a7fa385912..3b9678984124 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/support/BaseDefaultCodecs.java +++ b/spring-web/src/main/java/org/springframework/http/codec/support/BaseDefaultCodecs.java @@ -36,15 +36,20 @@ import org.springframework.http.codec.DecoderHttpMessageReader; import org.springframework.http.codec.EncoderHttpMessageWriter; import org.springframework.http.codec.FormHttpMessageReader; +import org.springframework.http.codec.FormHttpMessageWriter; import org.springframework.http.codec.HttpMessageReader; import org.springframework.http.codec.HttpMessageWriter; import org.springframework.http.codec.ResourceHttpMessageReader; import org.springframework.http.codec.ResourceHttpMessageWriter; +import org.springframework.http.codec.ServerSentEventHttpMessageReader; import org.springframework.http.codec.json.AbstractJackson2Decoder; import org.springframework.http.codec.json.Jackson2JsonDecoder; import org.springframework.http.codec.json.Jackson2JsonEncoder; import org.springframework.http.codec.json.Jackson2SmileDecoder; import org.springframework.http.codec.json.Jackson2SmileEncoder; +import org.springframework.http.codec.multipart.MultipartHttpMessageReader; +import org.springframework.http.codec.multipart.MultipartHttpMessageWriter; +import org.springframework.http.codec.multipart.SynchronossPartHttpMessageReader; import org.springframework.http.codec.protobuf.ProtobufDecoder; import org.springframework.http.codec.protobuf.ProtobufEncoder; import org.springframework.http.codec.protobuf.ProtobufHttpMessageWriter; @@ -70,6 +75,8 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure private static final boolean protobufPresent; + static final boolean synchronossMultipartPresent; + static { ClassLoader classLoader = BaseCodecConfigurer.class.getClassLoader(); jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader) && @@ -77,6 +84,7 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure jackson2SmilePresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.smile.SmileFactory", classLoader); jaxb2Present = ClassUtils.isPresent("javax.xml.bind.Binder", classLoader); protobufPresent = ClassUtils.isPresent("com.google.protobuf.Message", classLoader); + synchronossMultipartPresent = ClassUtils.isPresent("org.synchronoss.cloud.nio.multipart.NioMultipartParser", classLoader); } @@ -101,7 +109,8 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure @Nullable private Integer maxInMemorySize; - private boolean enableLoggingRequestDetails = false; + @Nullable + private Boolean enableLoggingRequestDetails; private boolean registerDefaults = true; @@ -171,7 +180,8 @@ public void enableLoggingRequestDetails(boolean enable) { } @Override - public boolean isEnableLoggingRequestDetails() { + @Nullable + public Boolean isEnableLoggingRequestDetails() { return this.enableLoggingRequestDetails; } @@ -191,48 +201,107 @@ final List> getTypedReaders() { return Collections.emptyList(); } List> readers = new ArrayList<>(); - readers.add(new DecoderHttpMessageReader<>(init(new ByteArrayDecoder()))); - readers.add(new DecoderHttpMessageReader<>(init(new ByteBufferDecoder()))); - readers.add(new DecoderHttpMessageReader<>(init(new DataBufferDecoder()))); - readers.add(new ResourceHttpMessageReader(init(new ResourceDecoder()))); - readers.add(new DecoderHttpMessageReader<>(init(StringDecoder.textPlainOnly()))); + addCodec(readers, new DecoderHttpMessageReader<>(new ByteArrayDecoder())); + addCodec(readers, new DecoderHttpMessageReader<>(new ByteBufferDecoder())); + addCodec(readers, new DecoderHttpMessageReader<>(new DataBufferDecoder())); + addCodec(readers, new ResourceHttpMessageReader(new ResourceDecoder())); + addCodec(readers, new DecoderHttpMessageReader<>(StringDecoder.textPlainOnly())); if (protobufPresent) { - Decoder decoder = this.protobufDecoder != null ? this.protobufDecoder : init(new ProtobufDecoder()); - readers.add(new DecoderHttpMessageReader<>(decoder)); - } - - FormHttpMessageReader formReader = new FormHttpMessageReader(); - if (this.maxInMemorySize != null) { - formReader.setMaxInMemorySize(this.maxInMemorySize); + Decoder decoder = this.protobufDecoder != null ? this.protobufDecoder : new ProtobufDecoder(); + addCodec(readers, new DecoderHttpMessageReader<>(decoder)); } - formReader.setEnableLoggingRequestDetails(this.enableLoggingRequestDetails); - readers.add(formReader); + addCodec(readers, new FormHttpMessageReader()); + // client vs server.. extendTypedReaders(readers); return readers; } - private > T init(T decoder) { - if (this.maxInMemorySize != null) { - if (decoder instanceof AbstractDataBufferDecoder) { - ((AbstractDataBufferDecoder) decoder).setMaxInMemorySize(this.maxInMemorySize); + /** + * Initialize a codec and add it to the List. + * @since 5.1.13 + */ + protected void addCodec(List codecs, T codec) { + initCodec(codec); + codecs.add(codec); + } + + /** + * Apply {@link #maxInMemorySize()} and {@link #enableLoggingRequestDetails}, + * if configured by the application, to the given codec , including any + * codec it contains. + */ + private void initCodec(@Nullable Object codec) { + + if (codec instanceof DecoderHttpMessageReader) { + codec = ((DecoderHttpMessageReader) codec).getDecoder(); + } + else if (codec instanceof ServerSentEventHttpMessageReader) { + codec = ((ServerSentEventHttpMessageReader) codec).getDecoder(); + } + + if (codec == null) { + return; + } + + Integer size = this.maxInMemorySize; + if (size != null) { + if (codec instanceof AbstractDataBufferDecoder) { + ((AbstractDataBufferDecoder) codec).setMaxInMemorySize(size); } - if (decoder instanceof ProtobufDecoder) { - ((ProtobufDecoder) decoder).setMaxMessageSize(this.maxInMemorySize); + if (protobufPresent) { + if (codec instanceof ProtobufDecoder) { + ((ProtobufDecoder) codec).setMaxMessageSize(size); + } } if (jackson2Present) { - if (decoder instanceof AbstractJackson2Decoder) { - ((AbstractJackson2Decoder) decoder).setMaxInMemorySize(this.maxInMemorySize); + if (codec instanceof AbstractJackson2Decoder) { + ((AbstractJackson2Decoder) codec).setMaxInMemorySize(size); } } if (jaxb2Present) { - if (decoder instanceof Jaxb2XmlDecoder) { - ((Jaxb2XmlDecoder) decoder).setMaxInMemorySize(this.maxInMemorySize); + if (codec instanceof Jaxb2XmlDecoder) { + ((Jaxb2XmlDecoder) codec).setMaxInMemorySize(size); } } + if (codec instanceof FormHttpMessageReader) { + ((FormHttpMessageReader) codec).setMaxInMemorySize(size); + } + if (synchronossMultipartPresent) { + if (codec instanceof SynchronossPartHttpMessageReader) { + ((SynchronossPartHttpMessageReader) codec).setMaxInMemorySize(size); + } + } + } + + Boolean enable = this.enableLoggingRequestDetails; + if (enable != null) { + if (codec instanceof FormHttpMessageReader) { + ((FormHttpMessageReader) codec).setEnableLoggingRequestDetails(enable); + } + if (codec instanceof MultipartHttpMessageReader) { + ((MultipartHttpMessageReader) codec).setEnableLoggingRequestDetails(enable); + } + if (synchronossMultipartPresent) { + if (codec instanceof SynchronossPartHttpMessageReader) { + ((SynchronossPartHttpMessageReader) codec).setEnableLoggingRequestDetails(enable); + } + } + if (codec instanceof FormHttpMessageWriter) { + ((FormHttpMessageWriter) codec).setEnableLoggingRequestDetails(enable); + } + if (codec instanceof MultipartHttpMessageWriter) { + ((MultipartHttpMessageWriter) codec).setEnableLoggingRequestDetails(enable); + } + } + + if (codec instanceof MultipartHttpMessageReader) { + initCodec(((MultipartHttpMessageReader) codec).getPartReader()); + } + else if (codec instanceof MultipartHttpMessageWriter) { + initCodec(((MultipartHttpMessageWriter) codec).getFormWriter()); } - return decoder; } /** @@ -250,16 +319,19 @@ final List> getObjectReaders() { } List> readers = new ArrayList<>(); if (jackson2Present) { - readers.add(new DecoderHttpMessageReader<>(init(getJackson2JsonDecoder()))); + addCodec(readers, new DecoderHttpMessageReader<>(getJackson2JsonDecoder())); } if (jackson2SmilePresent) { - readers.add(new DecoderHttpMessageReader<>(init(new Jackson2SmileDecoder()))); + addCodec(readers, new DecoderHttpMessageReader<>(new Jackson2SmileDecoder())); } if (jaxb2Present) { - Decoder decoder = this.jaxb2Decoder != null ? this.jaxb2Decoder : init(new Jaxb2XmlDecoder()); - readers.add(new DecoderHttpMessageReader<>(decoder)); + Decoder decoder = this.jaxb2Decoder != null ? this.jaxb2Decoder : new Jaxb2XmlDecoder(); + addCodec(readers, new DecoderHttpMessageReader<>(decoder)); } + + // client vs server.. extendObjectReaders(readers); + return readers; } @@ -276,9 +348,9 @@ final List> getCatchAllReaders() { if (!this.registerDefaults) { return Collections.emptyList(); } - List> result = new ArrayList<>(); - result.add(new DecoderHttpMessageReader<>(init(StringDecoder.allMimeTypes()))); - return result; + List> readers = new ArrayList<>(); + addCodec(readers, new DecoderHttpMessageReader<>(StringDecoder.allMimeTypes())); + return readers; } /** @@ -365,11 +437,17 @@ List> getCatchAllWriters() { // Accessors for use in subclasses... protected Decoder getJackson2JsonDecoder() { - return (this.jackson2JsonDecoder != null ? this.jackson2JsonDecoder : new Jackson2JsonDecoder()); + if (this.jackson2JsonDecoder == null) { + this.jackson2JsonDecoder = new Jackson2JsonDecoder(); + } + return this.jackson2JsonDecoder; } protected Encoder getJackson2JsonEncoder() { - return (this.jackson2JsonEncoder != null ? this.jackson2JsonEncoder : new Jackson2JsonEncoder()); + if (this.jackson2JsonEncoder == null) { + this.jackson2JsonEncoder = new Jackson2JsonEncoder(); + } + return this.jackson2JsonEncoder; } } diff --git a/spring-web/src/main/java/org/springframework/http/codec/support/ClientDefaultCodecsImpl.java b/spring-web/src/main/java/org/springframework/http/codec/support/ClientDefaultCodecsImpl.java index e764cb969612..dae7b25704d2 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/support/ClientDefaultCodecsImpl.java +++ b/spring-web/src/main/java/org/springframework/http/codec/support/ClientDefaultCodecsImpl.java @@ -95,24 +95,17 @@ public ClientDefaultCodecsImpl clone() { @Override protected void extendObjectReaders(List> objectReaders) { - objectReaders.add(new ServerSentEventHttpMessageReader(getSseDecoder())); - } - @Nullable - private Decoder getSseDecoder() { - return (this.sseDecoder != null ? this.sseDecoder : jackson2Present ? getJackson2JsonDecoder() : null); + Decoder decoder = (this.sseDecoder != null ? + this.sseDecoder : + jackson2Present ? getJackson2JsonDecoder() : null); + + addCodec(objectReaders, new ServerSentEventHttpMessageReader(decoder)); } @Override protected void extendTypedWriters(List> typedWriters) { - - FormHttpMessageWriter formWriter = new FormHttpMessageWriter(); - formWriter.setEnableLoggingRequestDetails(isEnableLoggingRequestDetails()); - - MultipartHttpMessageWriter multipartWriter = new MultipartHttpMessageWriter(getPartWriters(), formWriter); - multipartWriter.setEnableLoggingRequestDetails(isEnableLoggingRequestDetails()); - - typedWriters.add(multipartWriter); + addCodec(typedWriters, new MultipartHttpMessageWriter(getPartWriters(), new FormHttpMessageWriter())); } private List> getPartWriters() { diff --git a/spring-web/src/main/java/org/springframework/http/codec/support/ServerDefaultCodecsImpl.java b/spring-web/src/main/java/org/springframework/http/codec/support/ServerDefaultCodecsImpl.java index 1d997c3777b1..eaab4e3237c4 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/support/ServerDefaultCodecsImpl.java +++ b/spring-web/src/main/java/org/springframework/http/codec/support/ServerDefaultCodecsImpl.java @@ -25,7 +25,6 @@ import org.springframework.http.codec.multipart.MultipartHttpMessageReader; import org.springframework.http.codec.multipart.SynchronossPartHttpMessageReader; import org.springframework.lang.Nullable; -import org.springframework.util.ClassUtils; /** * Default implementation of {@link ServerCodecConfigurer.ServerDefaultCodecs}. @@ -34,11 +33,6 @@ */ class ServerDefaultCodecsImpl extends BaseDefaultCodecs implements ServerCodecConfigurer.ServerDefaultCodecs { - private static final boolean synchronossMultipartPresent = - ClassUtils.isPresent("org.synchronoss.cloud.nio.multipart.NioMultipartParser", - DefaultServerCodecConfigurer.class.getClassLoader()); - - @Nullable private HttpMessageReader multipartReader; @@ -70,23 +64,13 @@ public void serverSentEventEncoder(Encoder encoder) { @Override protected void extendTypedReaders(List> typedReaders) { if (this.multipartReader != null) { - typedReaders.add(this.multipartReader); + addCodec(typedReaders, this.multipartReader); return; } if (synchronossMultipartPresent) { - boolean enable = isEnableLoggingRequestDetails(); - SynchronossPartHttpMessageReader partReader = new SynchronossPartHttpMessageReader(); - Integer size = maxInMemorySize(); - if (size != null) { - partReader.setMaxInMemorySize(size); - } - partReader.setEnableLoggingRequestDetails(enable); - typedReaders.add(partReader); - - MultipartHttpMessageReader reader = new MultipartHttpMessageReader(partReader); - reader.setEnableLoggingRequestDetails(enable); - typedReaders.add(reader); + addCodec(typedReaders, partReader); + addCodec(typedReaders, new MultipartHttpMessageReader(partReader)); } } diff --git a/spring-web/src/test/java/org/springframework/http/codec/support/ClientCodecConfigurerTests.java b/spring-web/src/test/java/org/springframework/http/codec/support/ClientCodecConfigurerTests.java index 5faea0c90ed2..1553916771cd 100644 --- a/spring-web/src/test/java/org/springframework/http/codec/support/ClientCodecConfigurerTests.java +++ b/spring-web/src/test/java/org/springframework/http/codec/support/ClientCodecConfigurerTests.java @@ -22,7 +22,6 @@ import java.util.Collections; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Collectors; import org.junit.jupiter.api.Test; import reactor.core.publisher.Flux; @@ -37,6 +36,7 @@ import org.springframework.core.codec.DataBufferEncoder; import org.springframework.core.codec.Decoder; import org.springframework.core.codec.Encoder; +import org.springframework.core.codec.ResourceDecoder; import org.springframework.core.codec.StringDecoder; import org.springframework.core.io.buffer.DefaultDataBufferFactory; import org.springframework.http.MediaType; @@ -44,6 +44,7 @@ import org.springframework.http.codec.DecoderHttpMessageReader; import org.springframework.http.codec.EncoderHttpMessageWriter; import org.springframework.http.codec.FormHttpMessageReader; +import org.springframework.http.codec.FormHttpMessageWriter; import org.springframework.http.codec.HttpMessageReader; import org.springframework.http.codec.HttpMessageWriter; import org.springframework.http.codec.ResourceHttpMessageReader; @@ -116,12 +117,45 @@ public void jackson2EncoderOverride() { Jackson2JsonDecoder decoder = new Jackson2JsonDecoder(); this.configurer.defaultCodecs().jackson2JsonDecoder(decoder); - assertThat(this.configurer.getReaders().stream() - .filter(reader -> ServerSentEventHttpMessageReader.class.equals(reader.getClass())) - .map(reader -> (ServerSentEventHttpMessageReader) reader) - .findFirst() - .map(ServerSentEventHttpMessageReader::getDecoder) - .filter(e -> e == decoder).orElse(null)).isSameAs(decoder); + List> readers = this.configurer.getReaders(); + assertThat(findCodec(readers, ServerSentEventHttpMessageReader.class).getDecoder()).isSameAs(decoder); + } + + @Test + public void maxInMemorySize() { + int size = 99; + this.configurer.defaultCodecs().maxInMemorySize(size); + List> readers = this.configurer.getReaders(); + assertThat(readers.size()).isEqualTo(12); + assertThat(((ByteArrayDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); + assertThat(((ByteBufferDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); + assertThat(((DataBufferDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); + assertThat(((ResourceDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); + assertThat(((StringDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); + assertThat(((ProtobufDecoder) getNextDecoder(readers)).getMaxMessageSize()).isEqualTo(size); + assertThat(((FormHttpMessageReader) nextReader(readers)).getMaxInMemorySize()).isEqualTo(size); + + assertThat(((Jackson2JsonDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); + assertThat(((Jackson2SmileDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); + assertThat(((Jaxb2XmlDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); + + ServerSentEventHttpMessageReader reader = (ServerSentEventHttpMessageReader) nextReader(readers); + assertThat(((Jackson2JsonDecoder) reader.getDecoder()).getMaxInMemorySize()).isEqualTo(size); + + assertThat(((StringDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); + } + + @Test + public void enableLoggingRequestDetails() { + this.configurer.defaultCodecs().enableLoggingRequestDetails(true); + + List> writers = this.configurer.getWriters(); + MultipartHttpMessageWriter multipartWriter = findCodec(writers, MultipartHttpMessageWriter.class); + assertThat(multipartWriter.isEnableLoggingRequestDetails()).isTrue(); + + FormHttpMessageWriter formWriter = (FormHttpMessageWriter) multipartWriter.getFormWriter(); + assertThat(formWriter).isNotNull(); + assertThat(formWriter.isEnableLoggingRequestDetails()).isTrue(); } @Test @@ -135,49 +169,42 @@ public void cloneConfigurer() { // Clone has the customizations - Decoder sseDecoder = clone.getReaders().stream() - .filter(reader -> reader instanceof ServerSentEventHttpMessageReader) - .map(reader -> ((ServerSentEventHttpMessageReader) reader).getDecoder()) - .findFirst() - .get(); - - List> multipartWriters = clone.getWriters().stream() - .filter(writer -> writer instanceof MultipartHttpMessageWriter) - .flatMap(writer -> ((MultipartHttpMessageWriter) writer).getPartWriters().stream()) - .collect(Collectors.toList()); + Decoder sseDecoder = findCodec(clone.getReaders(), ServerSentEventHttpMessageReader.class).getDecoder(); + List> writers = findCodec(clone.getWriters(), MultipartHttpMessageWriter.class).getPartWriters(); assertThat(sseDecoder).isSameAs(jackson2Decoder); - assertThat(multipartWriters).hasSize(2); + assertThat(writers).hasSize(2); // Original does not have the customizations - sseDecoder = this.configurer.getReaders().stream() - .filter(reader -> reader instanceof ServerSentEventHttpMessageReader) - .map(reader -> ((ServerSentEventHttpMessageReader) reader).getDecoder()) - .findFirst() - .get(); - - multipartWriters = this.configurer.getWriters().stream() - .filter(writer -> writer instanceof MultipartHttpMessageWriter) - .flatMap(writer -> ((MultipartHttpMessageWriter) writer).getPartWriters().stream()) - .collect(Collectors.toList()); + sseDecoder = findCodec(this.configurer.getReaders(), ServerSentEventHttpMessageReader.class).getDecoder(); + writers = findCodec(this.configurer.getWriters(), MultipartHttpMessageWriter.class).getPartWriters(); assertThat(sseDecoder).isNotSameAs(jackson2Decoder); - assertThat(multipartWriters).hasSize(10); + assertThat(writers).hasSize(10); } private Decoder getNextDecoder(List> readers) { HttpMessageReader reader = readers.get(this.index.getAndIncrement()); - assertThat(reader.getClass()).isEqualTo(DecoderHttpMessageReader.class); + assertThat(reader).isInstanceOf(DecoderHttpMessageReader.class); return ((DecoderHttpMessageReader) reader).getDecoder(); } + private HttpMessageReader nextReader(List> readers) { + return readers.get(this.index.getAndIncrement()); + } + private Encoder getNextEncoder(List> writers) { HttpMessageWriter writer = writers.get(this.index.getAndIncrement()); assertThat(writer.getClass()).isEqualTo(EncoderHttpMessageWriter.class); return ((EncoderHttpMessageWriter) writer).getEncoder(); } + @SuppressWarnings("unchecked") + private T findCodec(List codecs, Class type) { + return (T) codecs.stream().filter(type::isInstance).findFirst().get(); + } + @SuppressWarnings("unchecked") private void assertStringDecoder(Decoder decoder, boolean textOnly) { assertThat(decoder.getClass()).isEqualTo(StringDecoder.class); diff --git a/spring-web/src/test/java/org/springframework/http/codec/support/ServerCodecConfigurerTests.java b/spring-web/src/test/java/org/springframework/http/codec/support/ServerCodecConfigurerTests.java index 023ec5af9b98..0aa1bede0b31 100644 --- a/spring-web/src/test/java/org/springframework/http/codec/support/ServerCodecConfigurerTests.java +++ b/spring-web/src/test/java/org/springframework/http/codec/support/ServerCodecConfigurerTests.java @@ -134,11 +134,7 @@ public void maxInMemorySize() { assertThat(((ByteArrayDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); assertThat(((ByteBufferDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); assertThat(((DataBufferDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); - - ResourceHttpMessageReader resourceReader = (ResourceHttpMessageReader) nextReader(readers); - ResourceDecoder decoder = (ResourceDecoder) resourceReader.getDecoder(); - assertThat(decoder.getMaxInMemorySize()).isEqualTo(size); - + assertThat(((ResourceDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); assertThat(((StringDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); assertThat(((ProtobufDecoder) getNextDecoder(readers)).getMaxMessageSize()).isEqualTo(size); assertThat(((FormHttpMessageReader) nextReader(readers)).getMaxInMemorySize()).isEqualTo(size); @@ -154,6 +150,20 @@ public void maxInMemorySize() { assertThat(((StringDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); } + @Test + public void enableRequestLoggingDetails() { + this.configurer.defaultCodecs().enableLoggingRequestDetails(true); + + List> readers = this.configurer.getReaders(); + assertThat(findCodec(readers, FormHttpMessageReader.class).isEnableLoggingRequestDetails()).isTrue(); + + MultipartHttpMessageReader multipartReader = findCodec(readers, MultipartHttpMessageReader.class); + assertThat(multipartReader.isEnableLoggingRequestDetails()).isTrue(); + + SynchronossPartHttpMessageReader reader = (SynchronossPartHttpMessageReader) multipartReader.getPartReader(); + assertThat(reader.isEnableLoggingRequestDetails()).isTrue(); + } + @Test public void cloneConfigurer() { ServerCodecConfigurer clone = this.configurer.clone(); @@ -165,42 +175,27 @@ public void cloneConfigurer() { // Clone has the customizations - HttpMessageReader actualReader = clone.getReaders().stream() - .filter(r -> r instanceof MultipartHttpMessageReader) - .findFirst() - .get(); - - Encoder actualEncoder = clone.getWriters().stream() - .filter(writer -> writer instanceof ServerSentEventHttpMessageWriter) - .map(writer -> ((ServerSentEventHttpMessageWriter) writer).getEncoder()) - .findFirst() - .get(); + HttpMessageReader actualReader = + findCodec(clone.getReaders(), MultipartHttpMessageReader.class); + ServerSentEventHttpMessageWriter actualWriter = + findCodec(clone.getWriters(), ServerSentEventHttpMessageWriter.class); assertThat(actualReader).isSameAs(reader); - assertThat(actualEncoder).isSameAs(encoder); + assertThat(actualWriter.getEncoder()).isSameAs(encoder); // Original does not have the customizations - actualReader = this.configurer.getReaders().stream() - .filter(r -> r instanceof MultipartHttpMessageReader) - .findFirst() - .get(); - - actualEncoder = this.configurer.getWriters().stream() - .filter(writer -> writer instanceof ServerSentEventHttpMessageWriter) - .map(writer -> ((ServerSentEventHttpMessageWriter) writer).getEncoder()) - .findFirst() - .get(); - + actualReader = findCodec(this.configurer.getReaders(), MultipartHttpMessageReader.class); + actualWriter = findCodec(this.configurer.getWriters(), ServerSentEventHttpMessageWriter.class); assertThat(actualReader).isNotSameAs(reader); - assertThat(actualEncoder).isNotSameAs(encoder); + assertThat(actualWriter.getEncoder()).isNotSameAs(encoder); } private Decoder getNextDecoder(List> readers) { HttpMessageReader reader = nextReader(readers); - assertThat(reader.getClass()).isEqualTo(DecoderHttpMessageReader.class); + assertThat(reader).isInstanceOf(DecoderHttpMessageReader.class); return ((DecoderHttpMessageReader) reader).getDecoder(); } @@ -214,6 +209,11 @@ private Encoder getNextEncoder(List> writers) { return ((EncoderHttpMessageWriter) writer).getEncoder(); } + @SuppressWarnings("unchecked") + private T findCodec(List codecs, Class type) { + return (T) codecs.stream().filter(type::isInstance).findFirst().get(); + } + @SuppressWarnings("unchecked") private void assertStringDecoder(Decoder decoder, boolean textOnly) { assertThat(decoder.getClass()).isEqualTo(StringDecoder.class);