Align multipart codecs on client and server

This commit ensures that the same multipart codecs are registered on
both client and server. Previously, only the client enabled only sending
 multipart, and the server only receiving.

Closes gh-29630
This commit is contained in:
Arjen Poutsma 2022-12-07 13:06:39 +01:00
parent 46fc28fd1a
commit c79ae0c842
13 changed files with 216 additions and 205 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -17,7 +17,6 @@
package org.springframework.http.codec;
import org.springframework.core.codec.Decoder;
import org.springframework.core.codec.Encoder;
/**
* Extension of {@link CodecConfigurer} for HTTP message reader and writer
@ -83,13 +82,6 @@ public interface ClientCodecConfigurer extends CodecConfigurer {
*/
interface ClientDefaultCodecs extends DefaultCodecs {
/**
* Configure encoders or writers for use with
* {@link org.springframework.http.codec.multipart.MultipartHttpMessageWriter
* MultipartHttpMessageWriter}.
*/
MultipartCodecs multipartCodecs();
/**
* Configure the {@code Decoder} to use for Server-Sent Events.
* <p>By default if this is not set, and Jackson is available, the
@ -102,26 +94,4 @@ public interface ClientCodecConfigurer extends CodecConfigurer {
void serverSentEventDecoder(Decoder<?> decoder);
}
/**
* Registry and container for multipart HTTP message writers.
*/
interface MultipartCodecs {
/**
* Add a Part {@code Encoder}, internally wrapped with
* {@link EncoderHttpMessageWriter}.
* @param encoder the encoder to add
*/
MultipartCodecs encoder(Encoder<?> encoder);
/**
* Add a Part {@link HttpMessageWriter}. For writers of type
* {@link EncoderHttpMessageWriter} consider using the shortcut
* {@link #encoder(Encoder)} instead.
* @param writer the writer to add
*/
MultipartCodecs writer(HttpMessageWriter<?> writer);
}
}

View File

@ -258,6 +258,24 @@ public interface CodecConfigurer {
* @since 5.1
*/
void enableLoggingRequestDetails(boolean enable);
/**
* Configure encoders or writers for use with
* {@link org.springframework.http.codec.multipart.MultipartHttpMessageWriter
* MultipartHttpMessageWriter}.
* @since 6.0.3
*/
MultipartCodecs multipartCodecs();
/**
* Configure the {@code HttpMessageReader} to use for multipart requests.
* <p>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 6.0.3
*/
void multipartReader(HttpMessageReader<?> reader);
}
@ -389,4 +407,27 @@ public interface CodecConfigurer {
Boolean isEnableLoggingRequestDetails();
}
/**
* Registry and container for multipart HTTP message writers.
* @since 6.0.3
*/
interface MultipartCodecs {
/**
* Add a Part {@code Encoder}, internally wrapped with
* {@link EncoderHttpMessageWriter}.
* @param encoder the encoder to add
*/
MultipartCodecs encoder(Encoder<?> encoder);
/**
* Add a Part {@link HttpMessageWriter}. For writers of type
* {@link EncoderHttpMessageWriter} consider using the shortcut
* {@link #encoder(Encoder)} instead.
* @param writer the writer to add
*/
MultipartCodecs writer(HttpMessageWriter<?> writer);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -82,16 +82,6 @@ public interface ServerCodecConfigurer extends CodecConfigurer {
*/
interface ServerDefaultCodecs extends DefaultCodecs {
/**
* Configure the {@code HttpMessageReader} to use for multipart requests.
* <p>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
*/
void multipartReader(HttpMessageReader<?> reader);
/**
* Configure the {@code Encoder} to use for Server-Sent Events.
* <p>By default if this is not set, and Jackson is available, the

View File

@ -79,7 +79,7 @@ public class MultipartHttpMessageWriter extends MultipartWriterSupport
private static final Map<String, Object> DEFAULT_HINTS = Hints.from(Hints.SUPPRESS_LOGGING_HINT, true);
private final List<HttpMessageWriter<?>> partWriters;
private final Supplier<List<HttpMessageWriter<?>>> partWritersSupplier;
@Nullable
private final HttpMessageWriter<MultiValueMap<String, String>> formWriter;
@ -112,8 +112,23 @@ public class MultipartHttpMessageWriter extends MultipartWriterSupport
public MultipartHttpMessageWriter(List<HttpMessageWriter<?>> partWriters,
@Nullable HttpMessageWriter<MultiValueMap<String, String>> formWriter) {
this(() -> partWriters, formWriter);
}
/**
* Constructor with a supplier for an explicit list of writers for
* serializing parts and a writer for plain form data to fall back when
* no media type is specified and the actual map consists of String
* values only.
* @param partWritersSupplier the supplier for writers for serializing parts
* @param formWriter the fallback writer for form data, {@code null} by default
* @since 6.0.3
*/
public MultipartHttpMessageWriter(Supplier<List<HttpMessageWriter<?>>> partWritersSupplier,
@Nullable HttpMessageWriter<MultiValueMap<String, String>> formWriter) {
super(initMediaTypes(formWriter));
this.partWriters = partWriters;
this.partWritersSupplier = partWritersSupplier;
this.formWriter = formWriter;
}
@ -131,7 +146,7 @@ public class MultipartHttpMessageWriter extends MultipartWriterSupport
* @since 5.0.7
*/
public List<HttpMessageWriter<?>> getPartWriters() {
return Collections.unmodifiableList(this.partWriters);
return Collections.unmodifiableList(this.partWritersSupplier.get());
}
@ -264,8 +279,8 @@ public class MultipartHttpMessageWriter extends MultipartWriterSupport
MediaType contentType = headers.getContentType();
final ResolvableType finalBodyType = resolvableType;
Optional<HttpMessageWriter<?>> writer = this.partWriters.stream()
ResolvableType finalBodyType = resolvableType;
Optional<HttpMessageWriter<?>> writer = this.partWritersSupplier.get().stream()
.filter(partWriter -> partWriter.canWrite(finalBodyType, contentType))
.findFirst();

View File

@ -55,6 +55,7 @@ abstract class BaseCodecConfigurer implements CodecConfigurer {
Assert.notNull(defaultCodecs, "'defaultCodecs' is required");
this.defaultCodecs = defaultCodecs;
this.customCodecs = new DefaultCustomCodecs();
this.defaultCodecs.setPartWritersSupplier(this::getWriters);
}
/**
@ -64,6 +65,7 @@ abstract class BaseCodecConfigurer implements CodecConfigurer {
protected BaseCodecConfigurer(BaseCodecConfigurer other) {
this.defaultCodecs = other.cloneDefaultCodecs();
this.customCodecs = new DefaultCustomCodecs(other.customCodecs);
this.defaultCodecs.setPartWritersSupplier(this::getWriters);
}
/**

View File

@ -21,6 +21,7 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Supplier;
import org.springframework.core.codec.AbstractDataBufferDecoder;
import org.springframework.core.codec.ByteArrayDecoder;
@ -62,6 +63,8 @@ import org.springframework.http.codec.multipart.DefaultPartHttpMessageReader;
import org.springframework.http.codec.multipart.MultipartHttpMessageReader;
import org.springframework.http.codec.multipart.MultipartHttpMessageWriter;
import org.springframework.http.codec.multipart.PartEventHttpMessageReader;
import org.springframework.http.codec.multipart.PartEventHttpMessageWriter;
import org.springframework.http.codec.multipart.PartHttpMessageWriter;
import org.springframework.http.codec.protobuf.KotlinSerializationProtobufDecoder;
import org.springframework.http.codec.protobuf.KotlinSerializationProtobufEncoder;
import org.springframework.http.codec.protobuf.ProtobufDecoder;
@ -160,6 +163,15 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure
@Nullable
private Encoder<?> kotlinSerializationProtobufEncoder;
@Nullable
private DefaultMultipartCodecs multipartCodecs;
@Nullable
private Supplier<List<HttpMessageWriter<?>>> partWritersSupplier;
@Nullable
private HttpMessageReader<?> multipartReader;
@Nullable
private Consumer<Object> codecConsumer;
@ -224,6 +236,9 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure
this.kotlinSerializationJsonEncoder = other.kotlinSerializationJsonEncoder;
this.kotlinSerializationProtobufDecoder = other.kotlinSerializationProtobufDecoder;
this.kotlinSerializationProtobufEncoder = other.kotlinSerializationProtobufEncoder;
this.multipartCodecs = other.multipartCodecs != null ?
new DefaultMultipartCodecs(other.multipartCodecs) : null;
this.multipartReader = other.multipartReader;
this.codecConsumer = other.codecConsumer;
this.maxInMemorySize = other.maxInMemorySize;
this.enableLoggingRequestDetails = other.enableLoggingRequestDetails;
@ -351,6 +366,31 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure
}
}
@Override
public CodecConfigurer.MultipartCodecs multipartCodecs() {
if (this.multipartCodecs == null) {
this.multipartCodecs = new DefaultMultipartCodecs();
}
return this.multipartCodecs;
}
@Override
public void multipartReader(HttpMessageReader<?> multipartReader) {
this.multipartReader = multipartReader;
initTypedReaders();
}
/**
* 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;
initTypedWriters();
}
@Override
@Nullable
public Boolean isEnableLoggingRequestDetails() {
@ -405,6 +445,15 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure
(KotlinSerializationProtobufDecoder) this.kotlinSerializationProtobufDecoder : new KotlinSerializationProtobufDecoder()));
}
addCodec(this.typedReaders, new FormHttpMessageReader());
if (this.multipartReader != null) {
addCodec(this.typedReaders, this.multipartReader);
}
else {
DefaultPartHttpMessageReader partReader = new DefaultPartHttpMessageReader();
addCodec(this.typedReaders, partReader);
addCodec(this.typedReaders, new MultipartHttpMessageReader(partReader));
}
addCodec(this.typedReaders, new PartEventHttpMessageReader());
// client vs server..
extendTypedReaders(this.typedReaders);
@ -641,9 +690,25 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure
addCodec(writers, new ProtobufHttpMessageWriter(this.protobufEncoder != null ?
(ProtobufEncoder) this.protobufEncoder : new ProtobufEncoder()));
}
addCodec(writers, new MultipartHttpMessageWriter(this::getPartWriters, new FormHttpMessageWriter()));
addCodec(writers, new PartEventHttpMessageWriter());
addCodec(writers, new PartHttpMessageWriter());
return writers;
}
private List<HttpMessageWriter<?>> getPartWriters() {
if (this.multipartCodecs != null) {
return this.multipartCodecs.getWriters();
}
else if (this.partWritersSupplier != null) {
return this.partWritersSupplier.get();
}
else {
return Collections.emptyList();
}
}
/**
* Hook for client or server specific typed writers.
*/
@ -766,4 +831,41 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure
return this.kotlinSerializationJsonEncoder;
}
/**
* Default implementation of {@link CodecConfigurer.MultipartCodecs}.
*/
protected class DefaultMultipartCodecs implements CodecConfigurer.MultipartCodecs {
private final List<HttpMessageWriter<?>> writers = new ArrayList<>();
DefaultMultipartCodecs() {
}
DefaultMultipartCodecs(DefaultMultipartCodecs other) {
this.writers.addAll(other.writers);
}
@Override
public CodecConfigurer.MultipartCodecs encoder(Encoder<?> encoder) {
writer(new EncoderHttpMessageWriter<>(encoder));
initTypedWriters();
return this;
}
@Override
public CodecConfigurer.MultipartCodecs writer(HttpMessageWriter<?> writer) {
this.writers.add(writer);
initTypedWriters();
return this;
}
List<HttpMessageWriter<?>> getWriters() {
return this.writers;
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,21 +16,12 @@
package org.springframework.http.codec.support;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Supplier;
import org.springframework.core.codec.Decoder;
import org.springframework.core.codec.Encoder;
import org.springframework.http.codec.ClientCodecConfigurer;
import org.springframework.http.codec.EncoderHttpMessageWriter;
import org.springframework.http.codec.FormHttpMessageWriter;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.codec.HttpMessageWriter;
import org.springframework.http.codec.ServerSentEventHttpMessageReader;
import org.springframework.http.codec.multipart.MultipartHttpMessageWriter;
import org.springframework.http.codec.multipart.PartEventHttpMessageWriter;
import org.springframework.lang.Nullable;
/**
@ -40,47 +31,18 @@ import org.springframework.lang.Nullable;
*/
class ClientDefaultCodecsImpl extends BaseDefaultCodecs implements ClientCodecConfigurer.ClientDefaultCodecs {
@Nullable
private DefaultMultipartCodecs multipartCodecs;
@Nullable
private Decoder<?> sseDecoder;
@Nullable
private Supplier<List<HttpMessageWriter<?>>> partWritersSupplier;
ClientDefaultCodecsImpl() {
}
ClientDefaultCodecsImpl(ClientDefaultCodecsImpl other) {
super(other);
this.multipartCodecs = (other.multipartCodecs != null ?
new DefaultMultipartCodecs(other.multipartCodecs) : null);
this.sseDecoder = other.sseDecoder;
}
/**
* 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;
initTypedWriters();
}
@Override
public ClientCodecConfigurer.MultipartCodecs multipartCodecs() {
if (this.multipartCodecs == null) {
this.multipartCodecs = new DefaultMultipartCodecs();
}
return this.multipartCodecs;
}
@Override
public void serverSentEventDecoder(Decoder<?> decoder) {
this.sseDecoder = decoder;
@ -98,58 +60,4 @@ class ClientDefaultCodecsImpl extends BaseDefaultCodecs implements ClientCodecCo
addCodec(objectReaders, new ServerSentEventHttpMessageReader(decoder));
}
@Override
protected void extendTypedWriters(List<HttpMessageWriter<?>> typedWriters) {
addCodec(typedWriters, new MultipartHttpMessageWriter(getPartWriters(), new FormHttpMessageWriter()));
addCodec(typedWriters, new PartEventHttpMessageWriter());
}
private List<HttpMessageWriter<?>> getPartWriters() {
if (this.multipartCodecs != null) {
return this.multipartCodecs.getWriters();
}
else if (this.partWritersSupplier != null) {
return this.partWritersSupplier.get();
}
else {
return Collections.emptyList();
}
}
/**
* Default implementation of {@link ClientCodecConfigurer.MultipartCodecs}.
*/
private class DefaultMultipartCodecs implements ClientCodecConfigurer.MultipartCodecs {
private final List<HttpMessageWriter<?>> writers = new ArrayList<>();
DefaultMultipartCodecs() {
}
DefaultMultipartCodecs(DefaultMultipartCodecs other) {
this.writers.addAll(other.writers);
}
@Override
public ClientCodecConfigurer.MultipartCodecs encoder(Encoder<?> encoder) {
writer(new EncoderHttpMessageWriter<>(encoder));
initTypedWriters();
return this;
}
@Override
public ClientCodecConfigurer.MultipartCodecs writer(HttpMessageWriter<?> writer) {
this.writers.add(writer);
initTypedWriters();
return this;
}
List<HttpMessageWriter<?>> getWriters() {
return this.writers;
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,11 +16,7 @@
package org.springframework.http.codec.support;
import java.util.ArrayList;
import java.util.List;
import org.springframework.http.codec.ClientCodecConfigurer;
import org.springframework.http.codec.HttpMessageWriter;
/**
* Default implementation of {@link ClientCodecConfigurer}.
@ -33,12 +29,10 @@ public class DefaultClientCodecConfigurer extends BaseCodecConfigurer implements
public DefaultClientCodecConfigurer() {
super(new ClientDefaultCodecsImpl());
((ClientDefaultCodecsImpl) defaultCodecs()).setPartWritersSupplier(this::getPartWriters);
}
private DefaultClientCodecConfigurer(DefaultClientCodecConfigurer other) {
super(other);
((ClientDefaultCodecsImpl) defaultCodecs()).setPartWritersSupplier(this::getPartWriters);
}
@ -57,14 +51,5 @@ public class DefaultClientCodecConfigurer extends BaseCodecConfigurer implements
return new ClientDefaultCodecsImpl((ClientDefaultCodecsImpl) defaultCodecs());
}
private List<HttpMessageWriter<?>> getPartWriters() {
List<HttpMessageWriter<?>> result = new ArrayList<>();
result.addAll(this.customCodecs.getTypedWriters().keySet());
result.addAll(this.defaultCodecs.getBaseTypedWriters());
result.addAll(this.customCodecs.getObjectWriters().keySet());
result.addAll(this.defaultCodecs.getBaseObjectWriters());
result.addAll(this.defaultCodecs.getCatchAllWriters());
return result;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -19,14 +19,9 @@ package org.springframework.http.codec.support;
import java.util.List;
import org.springframework.core.codec.Encoder;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.codec.HttpMessageWriter;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.http.codec.ServerSentEventHttpMessageWriter;
import org.springframework.http.codec.multipart.DefaultPartHttpMessageReader;
import org.springframework.http.codec.multipart.MultipartHttpMessageReader;
import org.springframework.http.codec.multipart.PartEventHttpMessageReader;
import org.springframework.http.codec.multipart.PartHttpMessageWriter;
import org.springframework.lang.Nullable;
/**
@ -36,9 +31,6 @@ import org.springframework.lang.Nullable;
*/
class ServerDefaultCodecsImpl extends BaseDefaultCodecs implements ServerCodecConfigurer.ServerDefaultCodecs {
@Nullable
private HttpMessageReader<?> multipartReader;
@Nullable
private Encoder<?> sseEncoder;
@ -48,42 +40,16 @@ class ServerDefaultCodecsImpl extends BaseDefaultCodecs implements ServerCodecCo
ServerDefaultCodecsImpl(ServerDefaultCodecsImpl other) {
super(other);
this.multipartReader = other.multipartReader;
this.sseEncoder = other.sseEncoder;
}
@Override
public void multipartReader(HttpMessageReader<?> reader) {
this.multipartReader = reader;
initTypedReaders();
}
@Override
public void serverSentEventEncoder(Encoder<?> encoder) {
this.sseEncoder = encoder;
initObjectWriters();
}
@Override
protected void extendTypedReaders(List<HttpMessageReader<?>> typedReaders) {
if (this.multipartReader != null) {
addCodec(typedReaders, this.multipartReader);
}
else {
DefaultPartHttpMessageReader partReader = new DefaultPartHttpMessageReader();
addCodec(typedReaders, partReader);
addCodec(typedReaders, new MultipartHttpMessageReader(partReader));
}
addCodec(typedReaders, new PartEventHttpMessageReader());
}
@Override
protected void extendTypedWriters(List<HttpMessageWriter<?>> typedWriters) {
addCodec(typedWriters, new PartHttpMessageWriter());
}
@Override
protected void extendObjectWriters(List<HttpMessageWriter<?>> objectWriters) {
objectWriters.add(new ServerSentEventHttpMessageWriter(getSseEncoder()));

View File

@ -64,8 +64,12 @@ import org.springframework.http.codec.json.Jackson2SmileDecoder;
import org.springframework.http.codec.json.Jackson2SmileEncoder;
import org.springframework.http.codec.json.KotlinSerializationJsonDecoder;
import org.springframework.http.codec.json.KotlinSerializationJsonEncoder;
import org.springframework.http.codec.multipart.DefaultPartHttpMessageReader;
import org.springframework.http.codec.multipart.MultipartHttpMessageReader;
import org.springframework.http.codec.multipart.MultipartHttpMessageWriter;
import org.springframework.http.codec.multipart.PartEventHttpMessageReader;
import org.springframework.http.codec.multipart.PartEventHttpMessageWriter;
import org.springframework.http.codec.multipart.PartHttpMessageWriter;
import org.springframework.http.codec.protobuf.KotlinSerializationProtobufDecoder;
import org.springframework.http.codec.protobuf.KotlinSerializationProtobufEncoder;
import org.springframework.http.codec.protobuf.ProtobufDecoder;
@ -92,7 +96,7 @@ public class ClientCodecConfigurerTests {
@Test
public void defaultReaders() {
List<HttpMessageReader<?>> readers = this.configurer.getReaders();
assertThat(readers).hasSize(17);
assertThat(readers).hasSize(20);
assertThat(getNextDecoder(readers).getClass()).isEqualTo(ByteArrayDecoder.class);
assertThat(getNextDecoder(readers).getClass()).isEqualTo(ByteBufferDecoder.class);
assertThat(getNextDecoder(readers).getClass()).isEqualTo(DataBufferDecoder.class);
@ -103,6 +107,9 @@ public class ClientCodecConfigurerTests {
assertThat(getNextDecoder(readers).getClass()).isEqualTo(ProtobufDecoder.class);
// SPR-16804
assertThat(readers.get(this.index.getAndIncrement()).getClass()).isEqualTo(FormHttpMessageReader.class);
assertThat(readers.get(this.index.getAndIncrement()).getClass()).isEqualTo(DefaultPartHttpMessageReader.class);
assertThat(readers.get(this.index.getAndIncrement()).getClass()).isEqualTo(MultipartHttpMessageReader.class);
assertThat(readers.get(this.index.getAndIncrement()).getClass()).isEqualTo(PartEventHttpMessageReader.class);
assertThat(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationCborDecoder.class);
assertThat(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationJsonDecoder.class);
assertThat(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationProtobufDecoder.class);
@ -116,7 +123,7 @@ public class ClientCodecConfigurerTests {
@Test
public void defaultWriters() {
List<HttpMessageWriter<?>> writers = this.configurer.getWriters();
assertThat(writers).hasSize(17);
assertThat(writers).hasSize(18);
assertThat(getNextEncoder(writers).getClass()).isEqualTo(ByteArrayEncoder.class);
assertThat(getNextEncoder(writers).getClass()).isEqualTo(ByteBufferEncoder.class);
assertThat(getNextEncoder(writers).getClass()).isEqualTo(DataBufferEncoder.class);
@ -127,6 +134,7 @@ public class ClientCodecConfigurerTests {
assertThat(writers.get(index.getAndIncrement()).getClass()).isEqualTo(ProtobufHttpMessageWriter.class);
assertThat(writers.get(this.index.getAndIncrement()).getClass()).isEqualTo(MultipartHttpMessageWriter.class);
assertThat(writers.get(this.index.getAndIncrement()).getClass()).isEqualTo(PartEventHttpMessageWriter.class);
assertThat(writers.get(this.index.getAndIncrement()).getClass()).isEqualTo(PartHttpMessageWriter.class);
assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationCborEncoder.class);
assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationJsonEncoder.class);
assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationProtobufEncoder.class);
@ -184,7 +192,7 @@ public class ClientCodecConfigurerTests {
int size = 99;
this.configurer.defaultCodecs().maxInMemorySize(size);
List<HttpMessageReader<?>> readers = this.configurer.getReaders();
assertThat(readers).hasSize(17);
assertThat(readers).hasSize(20);
assertThat(((ByteArrayDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size);
assertThat(((ByteBufferDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size);
assertThat(((DataBufferDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size);
@ -194,7 +202,9 @@ public class ClientCodecConfigurerTests {
assertThat(((StringDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size);
assertThat(((ProtobufDecoder) getNextDecoder(readers)).getMaxMessageSize()).isEqualTo(size);
assertThat(((FormHttpMessageReader) nextReader(readers)).getMaxInMemorySize()).isEqualTo(size);
assertThat(((DefaultPartHttpMessageReader) nextReader(readers)).getMaxInMemorySize()).isEqualTo(size);
nextReader(readers);
assertThat(((PartEventHttpMessageReader) nextReader(readers)).getMaxInMemorySize()).isEqualTo(size);
assertThat(((KotlinSerializationCborDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size);
assertThat(((KotlinSerializationJsonDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size);
assertThat(((KotlinSerializationProtobufDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size);
@ -245,7 +255,7 @@ public class ClientCodecConfigurerTests {
writers = findCodec(this.configurer.getWriters(), MultipartHttpMessageWriter.class).getPartWriters();
assertThat(sseDecoder).isNotSameAs(jackson2Decoder);
assertThat(writers).hasSize(15);
assertThat(writers).hasSize(18);
}
@Test // gh-24194
@ -255,7 +265,7 @@ public class ClientCodecConfigurerTests {
List<HttpMessageWriter<?>> writers =
findCodec(clone.getWriters(), MultipartHttpMessageWriter.class).getPartWriters();
assertThat(writers).hasSize(15);
assertThat(writers).hasSize(18);
}
@Test
@ -269,7 +279,7 @@ public class ClientCodecConfigurerTests {
List<HttpMessageWriter<?>> writers =
findCodec(clone.getWriters(), MultipartHttpMessageWriter.class).getPartWriters();
assertThat(writers).hasSize(15);
assertThat(writers).hasSize(18);
}
private Decoder<?> getNextDecoder(List<HttpMessageReader<?>> readers) {

View File

@ -58,6 +58,12 @@ import org.springframework.http.codec.json.Jackson2SmileDecoder;
import org.springframework.http.codec.json.Jackson2SmileEncoder;
import org.springframework.http.codec.json.KotlinSerializationJsonDecoder;
import org.springframework.http.codec.json.KotlinSerializationJsonEncoder;
import org.springframework.http.codec.multipart.DefaultPartHttpMessageReader;
import org.springframework.http.codec.multipart.MultipartHttpMessageReader;
import org.springframework.http.codec.multipart.MultipartHttpMessageWriter;
import org.springframework.http.codec.multipart.PartEventHttpMessageReader;
import org.springframework.http.codec.multipart.PartEventHttpMessageWriter;
import org.springframework.http.codec.multipart.PartHttpMessageWriter;
import org.springframework.http.codec.protobuf.KotlinSerializationProtobufDecoder;
import org.springframework.http.codec.protobuf.KotlinSerializationProtobufEncoder;
import org.springframework.http.codec.protobuf.ProtobufDecoder;
@ -87,7 +93,7 @@ class CodecConfigurerTests {
@Test
void defaultReaders() {
List<HttpMessageReader<?>> readers = this.configurer.getReaders();
assertThat(readers).hasSize(16);
assertThat(readers).hasSize(19);
assertThat(getNextDecoder(readers).getClass()).isEqualTo(ByteArrayDecoder.class);
assertThat(getNextDecoder(readers).getClass()).isEqualTo(ByteBufferDecoder.class);
assertThat(getNextDecoder(readers).getClass()).isEqualTo(DataBufferDecoder.class);
@ -97,6 +103,9 @@ class CodecConfigurerTests {
assertStringDecoder(getNextDecoder(readers), true);
assertThat(getNextDecoder(readers).getClass()).isEqualTo(ProtobufDecoder.class);
assertThat(readers.get(this.index.getAndIncrement()).getClass()).isEqualTo(FormHttpMessageReader.class);
assertThat(readers.get(this.index.getAndIncrement()).getClass()).isEqualTo(DefaultPartHttpMessageReader.class);
assertThat(readers.get(this.index.getAndIncrement()).getClass()).isEqualTo(MultipartHttpMessageReader.class);
assertThat(readers.get(this.index.getAndIncrement()).getClass()).isEqualTo(PartEventHttpMessageReader.class);
assertThat(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationCborDecoder.class);
assertThat(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationJsonDecoder.class);
assertThat(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationProtobufDecoder.class);
@ -109,7 +118,7 @@ class CodecConfigurerTests {
@Test
void defaultWriters() {
List<HttpMessageWriter<?>> writers = this.configurer.getWriters();
assertThat(writers).hasSize(15);
assertThat(writers).hasSize(18);
assertThat(getNextEncoder(writers).getClass()).isEqualTo(ByteArrayEncoder.class);
assertThat(getNextEncoder(writers).getClass()).isEqualTo(ByteBufferEncoder.class);
assertThat(getNextEncoder(writers).getClass()).isEqualTo(DataBufferEncoder.class);
@ -118,6 +127,9 @@ class CodecConfigurerTests {
assertThat(writers.get(index.getAndIncrement()).getClass()).isEqualTo(ResourceHttpMessageWriter.class);
assertStringEncoder(getNextEncoder(writers), true);
assertThat(writers.get(index.getAndIncrement()).getClass()).isEqualTo(ProtobufHttpMessageWriter.class);
assertThat(writers.get(index.getAndIncrement()).getClass()).isEqualTo(MultipartHttpMessageWriter.class);
assertThat(writers.get(index.getAndIncrement()).getClass()).isEqualTo(PartEventHttpMessageWriter.class);
assertThat(writers.get(index.getAndIncrement()).getClass()).isEqualTo(PartHttpMessageWriter.class);
assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationCborEncoder.class);
assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationJsonEncoder.class);
assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationProtobufEncoder.class);
@ -149,7 +161,7 @@ class CodecConfigurerTests {
List<HttpMessageReader<?>> readers = this.configurer.getReaders();
assertThat(readers).hasSize(20);
assertThat(readers).hasSize(23);
assertThat(getNextDecoder(readers)).isSameAs(customDecoder1);
assertThat(readers.get(this.index.getAndIncrement())).isSameAs(customReader1);
assertThat(getNextDecoder(readers).getClass()).isEqualTo(ByteArrayDecoder.class);
@ -161,6 +173,9 @@ class CodecConfigurerTests {
assertThat(getNextDecoder(readers).getClass()).isEqualTo(StringDecoder.class);
assertThat(getNextDecoder(readers).getClass()).isEqualTo(ProtobufDecoder.class);
assertThat(readers.get(this.index.getAndIncrement()).getClass()).isEqualTo(FormHttpMessageReader.class);
assertThat(readers.get(this.index.getAndIncrement()).getClass()).isEqualTo(DefaultPartHttpMessageReader.class);
assertThat(readers.get(this.index.getAndIncrement()).getClass()).isEqualTo(MultipartHttpMessageReader.class);
assertThat(readers.get(this.index.getAndIncrement()).getClass()).isEqualTo(PartEventHttpMessageReader.class);
assertThat(getNextDecoder(readers)).isSameAs(customDecoder2);
assertThat(readers.get(this.index.getAndIncrement())).isSameAs(customReader2);
assertThat(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationCborDecoder.class);
@ -194,7 +209,7 @@ class CodecConfigurerTests {
List<HttpMessageWriter<?>> writers = this.configurer.getWriters();
assertThat(writers).hasSize(19);
assertThat(writers).hasSize(22);
assertThat(getNextEncoder(writers)).isSameAs(customEncoder1);
assertThat(writers.get(this.index.getAndIncrement())).isSameAs(customWriter1);
assertThat(getNextEncoder(writers).getClass()).isEqualTo(ByteArrayEncoder.class);
@ -205,6 +220,9 @@ class CodecConfigurerTests {
assertThat(writers.get(index.getAndIncrement()).getClass()).isEqualTo(ResourceHttpMessageWriter.class);
assertThat(getNextEncoder(writers).getClass()).isEqualTo(CharSequenceEncoder.class);
assertThat(writers.get(index.getAndIncrement()).getClass()).isEqualTo(ProtobufHttpMessageWriter.class);
assertThat(writers.get(index.getAndIncrement()).getClass()).isEqualTo(MultipartHttpMessageWriter.class);
assertThat(writers.get(index.getAndIncrement()).getClass()).isEqualTo(PartEventHttpMessageWriter.class);
assertThat(writers.get(index.getAndIncrement()).getClass()).isEqualTo(PartHttpMessageWriter.class);
assertThat(getNextEncoder(writers)).isSameAs(customEncoder2);
assertThat(writers.get(this.index.getAndIncrement())).isSameAs(customWriter2);
assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationCborEncoder.class);

View File

@ -64,7 +64,9 @@ import org.springframework.http.codec.json.KotlinSerializationJsonDecoder;
import org.springframework.http.codec.json.KotlinSerializationJsonEncoder;
import org.springframework.http.codec.multipart.DefaultPartHttpMessageReader;
import org.springframework.http.codec.multipart.MultipartHttpMessageReader;
import org.springframework.http.codec.multipart.MultipartHttpMessageWriter;
import org.springframework.http.codec.multipart.PartEventHttpMessageReader;
import org.springframework.http.codec.multipart.PartEventHttpMessageWriter;
import org.springframework.http.codec.multipart.PartHttpMessageWriter;
import org.springframework.http.codec.protobuf.KotlinSerializationProtobufDecoder;
import org.springframework.http.codec.protobuf.KotlinSerializationProtobufEncoder;
@ -117,7 +119,7 @@ public class ServerCodecConfigurerTests {
@Test
public void defaultWriters() {
List<HttpMessageWriter<?>> writers = this.configurer.getWriters();
assertThat(writers).hasSize(17);
assertThat(writers).hasSize(19);
assertThat(getNextEncoder(writers).getClass()).isEqualTo(ByteArrayEncoder.class);
assertThat(getNextEncoder(writers).getClass()).isEqualTo(ByteBufferEncoder.class);
assertThat(getNextEncoder(writers).getClass()).isEqualTo(DataBufferEncoder.class);
@ -126,6 +128,8 @@ public class ServerCodecConfigurerTests {
assertThat(writers.get(index.getAndIncrement()).getClass()).isEqualTo(ResourceHttpMessageWriter.class);
assertStringEncoder(getNextEncoder(writers), true);
assertThat(writers.get(index.getAndIncrement()).getClass()).isEqualTo(ProtobufHttpMessageWriter.class);
assertThat(writers.get(this.index.getAndIncrement()).getClass()).isEqualTo(MultipartHttpMessageWriter.class);
assertThat(writers.get(this.index.getAndIncrement()).getClass()).isEqualTo(PartEventHttpMessageWriter.class);
assertThat(writers.get(this.index.getAndIncrement()).getClass()).isEqualTo(PartHttpMessageWriter.class);
assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationCborEncoder.class);
assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationJsonEncoder.class);

View File

@ -200,7 +200,7 @@ public class WebFluxConfigurationSupportTests {
assertThat(handler.getOrder()).isEqualTo(0);
List<HttpMessageWriter<?>> writers = handler.getMessageWriters();
assertThat(writers).hasSize(14);
assertThat(writers).hasSize(16);
assertHasMessageWriter(writers, forClass(byte[].class), APPLICATION_OCTET_STREAM);
assertHasMessageWriter(writers, forClass(ByteBuffer.class), APPLICATION_OCTET_STREAM);
@ -228,7 +228,7 @@ public class WebFluxConfigurationSupportTests {
assertThat(handler.getOrder()).isEqualTo(100);
List<HttpMessageWriter<?>> writers = handler.getMessageWriters();
assertThat(writers).hasSize(14);
assertThat(writers).hasSize(16);
assertHasMessageWriter(writers, forClass(byte[].class), APPLICATION_OCTET_STREAM);
assertHasMessageWriter(writers, forClass(ByteBuffer.class), APPLICATION_OCTET_STREAM);