diff --git a/spring-messaging/src/main/java/org/springframework/messaging/converter/KotlinSerializationJsonMessageConverter.java b/spring-messaging/src/main/java/org/springframework/messaging/converter/KotlinSerializationJsonMessageConverter.java
index 213e424edfec..475a1f50008c 100644
--- a/spring-messaging/src/main/java/org/springframework/messaging/converter/KotlinSerializationJsonMessageConverter.java
+++ b/spring-messaging/src/main/java/org/springframework/messaging/converter/KotlinSerializationJsonMessageConverter.java
@@ -94,6 +94,7 @@ protected String toJson(Object payload, Type resolvedType) {
* Tries to find a serializer that can marshall or unmarshall instances of the given type
* using kotlinx.serialization. If no serializer can be found, an exception is thrown.
*
Resolved serializers are cached and cached results are returned on successive calls.
+ * TODO Avoid relying on throwing exception when https://github.com/Kotlin/kotlinx.serialization/pull/1164 is fixed
* @param type the type to find a serializer for
* @return a resolved serializer for the given type
* @throws RuntimeException if no serializer supporting the given type can be found
diff --git a/spring-web/src/main/java/org/springframework/http/codec/json/KotlinSerializationJsonDecoder.java b/spring-web/src/main/java/org/springframework/http/codec/json/KotlinSerializationJsonDecoder.java
index 0d71367f7dc1..58f582bb1e88 100644
--- a/spring-web/src/main/java/org/springframework/http/codec/json/KotlinSerializationJsonDecoder.java
+++ b/spring-web/src/main/java/org/springframework/http/codec/json/KotlinSerializationJsonDecoder.java
@@ -69,10 +69,38 @@ public KotlinSerializationJsonDecoder(Json json) {
this.json = json;
}
+ /**
+ * Configure a limit on the number of bytes that can be buffered whenever
+ * the input stream needs to be aggregated. This can be a result of
+ * decoding to a single {@code DataBuffer},
+ * {@link java.nio.ByteBuffer ByteBuffer}, {@code byte[]},
+ * {@link org.springframework.core.io.Resource Resource}, {@code String}, etc.
+ * It can also occur when splitting the input stream, e.g. delimited text,
+ * in which case the limit applies to data buffered between delimiters.
+ *
By default this is set to 256K.
+ * @param byteCount the max number of bytes to buffer, or -1 for unlimited
+ */
+ public void setMaxInMemorySize(int byteCount) {
+ this.stringDecoder.setMaxInMemorySize(byteCount);
+ }
+
+ /**
+ * Return the {@link #setMaxInMemorySize configured} byte count limit.
+ */
+ public int getMaxInMemorySize() {
+ return this.stringDecoder.getMaxInMemorySize();
+ }
+
@Override
public boolean canDecode(ResolvableType elementType, @Nullable MimeType mimeType) {
- return (super.canDecode(elementType, mimeType) && !CharSequence.class.isAssignableFrom(elementType.toClass()));
+ try {
+ serializer(elementType.getType());
+ return (super.canDecode(elementType, mimeType) && !CharSequence.class.isAssignableFrom(elementType.toClass()));
+ }
+ catch (Exception ex) {
+ return false;
+ }
}
@Override
@@ -95,6 +123,7 @@ public Mono decodeToMono(Publisher inputStream, ResolvableTy
* Tries to find a serializer that can marshall or unmarshall instances of the given type
* using kotlinx.serialization. If no serializer can be found, an exception is thrown.
* Resolved serializers are cached and cached results are returned on successive calls.
+ * TODO Avoid relying on throwing exception when https://github.com/Kotlin/kotlinx.serialization/pull/1164 is fixed
* @param type the type to find a serializer for
* @return a resolved serializer for the given type
* @throws RuntimeException if no serializer supporting the given type can be found
diff --git a/spring-web/src/main/java/org/springframework/http/codec/json/KotlinSerializationJsonEncoder.java b/spring-web/src/main/java/org/springframework/http/codec/json/KotlinSerializationJsonEncoder.java
index f2a619734c61..cd577d4c8280 100644
--- a/spring-web/src/main/java/org/springframework/http/codec/json/KotlinSerializationJsonEncoder.java
+++ b/spring-web/src/main/java/org/springframework/http/codec/json/KotlinSerializationJsonEncoder.java
@@ -71,8 +71,14 @@ public KotlinSerializationJsonEncoder(Json json) {
@Override
public boolean canEncode(ResolvableType elementType, @Nullable MimeType mimeType) {
- return (super.canEncode(elementType, mimeType) && !String.class.isAssignableFrom(elementType.toClass()) &&
- !ServerSentEvent.class.isAssignableFrom(elementType.toClass()));
+ try {
+ serializer(elementType.getType());
+ return (super.canEncode(elementType, mimeType) && !String.class.isAssignableFrom(elementType.toClass()) &&
+ !ServerSentEvent.class.isAssignableFrom(elementType.toClass()));
+ }
+ catch (Exception ex) {
+ return false;
+ }
}
@Override
@@ -105,6 +111,7 @@ public DataBuffer encodeValue(Object value, DataBufferFactory bufferFactory,
* Tries to find a serializer that can marshall or unmarshall instances of the given type
* using kotlinx.serialization. If no serializer can be found, an exception is thrown.
*
Resolved serializers are cached and cached results are returned on successive calls.
+ * TODO Avoid relying on throwing exception when https://github.com/Kotlin/kotlinx.serialization/pull/1164 is fixed
* @param type the type to find a serializer for
* @return a resolved serializer for the given type
* @throws RuntimeException if no serializer supporting the given type can be found
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 0f40420298e2..00bc8887fae8 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
@@ -312,6 +312,11 @@ private void initCodec(@Nullable Object codec) {
((ProtobufDecoder) codec).setMaxMessageSize(size);
}
}
+ if (kotlinSerializationJsonPresent) {
+ if (codec instanceof KotlinSerializationJsonDecoder) {
+ ((KotlinSerializationJsonDecoder) codec).setMaxInMemorySize(size);
+ }
+ }
if (jackson2Present) {
if (codec instanceof AbstractJackson2Decoder) {
((AbstractJackson2Decoder) codec).setMaxInMemorySize(size);
@@ -385,12 +390,12 @@ final List> getObjectReaders() {
return Collections.emptyList();
}
List> readers = new ArrayList<>();
+ if (kotlinSerializationJsonPresent) {
+ addCodec(readers, new DecoderHttpMessageReader<>(getKotlinSerializationJsonDecoder()));
+ }
if (jackson2Present) {
addCodec(readers, new DecoderHttpMessageReader<>(getJackson2JsonDecoder()));
}
- else if (kotlinSerializationJsonPresent) {
- addCodec(readers, new DecoderHttpMessageReader<>(getKotlinSerializationJsonDecoder()));
- }
if (jackson2SmilePresent) {
addCodec(readers, new DecoderHttpMessageReader<>(this.jackson2SmileDecoder != null ?
(Jackson2SmileDecoder) this.jackson2SmileDecoder : new Jackson2SmileDecoder()));
@@ -484,12 +489,12 @@ final List> getObjectWriters() {
*/
final List> getBaseObjectWriters() {
List> writers = new ArrayList<>();
+ if (kotlinSerializationJsonPresent) {
+ writers.add(new EncoderHttpMessageWriter<>(getKotlinSerializationJsonEncoder()));
+ }
if (jackson2Present) {
writers.add(new EncoderHttpMessageWriter<>(getJackson2JsonEncoder()));
}
- else if (kotlinSerializationJsonPresent) {
- writers.add(new EncoderHttpMessageWriter<>(getKotlinSerializationJsonEncoder()));
- }
if (jackson2SmilePresent) {
writers.add(new EncoderHttpMessageWriter<>(this.jackson2SmileEncoder != null ?
(Jackson2SmileEncoder) this.jackson2SmileEncoder : new Jackson2SmileEncoder()));
diff --git a/spring-web/src/main/java/org/springframework/http/converter/json/KotlinSerializationJsonHttpMessageConverter.java b/spring-web/src/main/java/org/springframework/http/converter/json/KotlinSerializationJsonHttpMessageConverter.java
index 9190f21cd7ba..7fe280a770c0 100644
--- a/spring-web/src/main/java/org/springframework/http/converter/json/KotlinSerializationJsonHttpMessageConverter.java
+++ b/spring-web/src/main/java/org/springframework/http/converter/json/KotlinSerializationJsonHttpMessageConverter.java
@@ -88,6 +88,28 @@ protected boolean supports(Class> clazz) {
}
}
+ @Override
+ public boolean canRead(Type type, @Nullable Class> contextClass, @Nullable MediaType mediaType) {
+ try {
+ serializer(GenericTypeResolver.resolveType(type, contextClass));
+ return canRead(mediaType);
+ }
+ catch (Exception ex) {
+ return false;
+ }
+ }
+
+ @Override
+ public boolean canWrite(@Nullable Type type, @Nullable Class> clazz, @Nullable MediaType mediaType) {
+ try {
+ serializer(GenericTypeResolver.resolveType(type, clazz));
+ return canWrite(mediaType);
+ }
+ catch (Exception ex) {
+ return false;
+ }
+ }
+
@Override
public final Object read(Type type, @Nullable Class> contextClass, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {
@@ -151,6 +173,7 @@ private Charset getCharsetToUse(@Nullable MediaType contentType) {
* Tries to find a serializer that can marshall or unmarshall instances of the given type
* using kotlinx.serialization. If no serializer can be found, an exception is thrown.
* Resolved serializers are cached and cached results are returned on successive calls.
+ * TODO Avoid relying on throwing exception when https://github.com/Kotlin/kotlinx.serialization/pull/1164 is fixed
* @param type the type to find a serializer for
* @return a resolved serializer for the given type
* @throws RuntimeException if no serializer supporting the given type can be found
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 1c40633785a9..60bec60fb6b6 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
@@ -56,6 +56,8 @@
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.json.KotlinSerializationJsonDecoder;
+import org.springframework.http.codec.json.KotlinSerializationJsonEncoder;
import org.springframework.http.codec.multipart.MultipartHttpMessageWriter;
import org.springframework.http.codec.protobuf.ProtobufDecoder;
import org.springframework.http.codec.protobuf.ProtobufHttpMessageWriter;
@@ -81,7 +83,7 @@ public class ClientCodecConfigurerTests {
@Test
public void defaultReaders() {
List> readers = this.configurer.getReaders();
- assertThat(readers.size()).isEqualTo(13);
+ assertThat(readers.size()).isEqualTo(14);
assertThat(getNextDecoder(readers).getClass()).isEqualTo(ByteArrayDecoder.class);
assertThat(getNextDecoder(readers).getClass()).isEqualTo(ByteBufferDecoder.class);
assertThat(getNextDecoder(readers).getClass()).isEqualTo(DataBufferDecoder.class);
@@ -91,6 +93,7 @@ public void defaultReaders() {
assertThat(getNextDecoder(readers).getClass()).isEqualTo(ProtobufDecoder.class);
// SPR-16804
assertThat(readers.get(this.index.getAndIncrement()).getClass()).isEqualTo(FormHttpMessageReader.class);
+ assertThat(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationJsonDecoder.class);
assertThat(getNextDecoder(readers).getClass()).isEqualTo(Jackson2JsonDecoder.class);
assertThat(getNextDecoder(readers).getClass()).isEqualTo(Jackson2SmileDecoder.class);
assertThat(getNextDecoder(readers).getClass()).isEqualTo(Jaxb2XmlDecoder.class);
@@ -101,7 +104,7 @@ public void defaultReaders() {
@Test
public void defaultWriters() {
List> writers = this.configurer.getWriters();
- assertThat(writers.size()).isEqualTo(12);
+ assertThat(writers.size()).isEqualTo(13);
assertThat(getNextEncoder(writers).getClass()).isEqualTo(ByteArrayEncoder.class);
assertThat(getNextEncoder(writers).getClass()).isEqualTo(ByteBufferEncoder.class);
assertThat(getNextEncoder(writers).getClass()).isEqualTo(DataBufferEncoder.class);
@@ -110,6 +113,7 @@ public void defaultWriters() {
assertStringEncoder(getNextEncoder(writers), true);
assertThat(writers.get(index.getAndIncrement()).getClass()).isEqualTo(ProtobufHttpMessageWriter.class);
assertThat(writers.get(this.index.getAndIncrement()).getClass()).isEqualTo(MultipartHttpMessageWriter.class);
+ assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationJsonEncoder.class);
assertThat(getNextEncoder(writers).getClass()).isEqualTo(Jackson2JsonEncoder.class);
assertThat(getNextEncoder(writers).getClass()).isEqualTo(Jackson2SmileEncoder.class);
assertThat(getNextEncoder(writers).getClass()).isEqualTo(Jaxb2XmlEncoder.class);
@@ -130,7 +134,7 @@ public void maxInMemorySize() {
int size = 99;
this.configurer.defaultCodecs().maxInMemorySize(size);
List> readers = this.configurer.getReaders();
- assertThat(readers.size()).isEqualTo(13);
+ assertThat(readers.size()).isEqualTo(14);
assertThat(((ByteArrayDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size);
assertThat(((ByteBufferDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size);
assertThat(((DataBufferDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size);
@@ -140,6 +144,7 @@ public void maxInMemorySize() {
assertThat(((ProtobufDecoder) getNextDecoder(readers)).getMaxMessageSize()).isEqualTo(size);
assertThat(((FormHttpMessageReader) nextReader(readers)).getMaxInMemorySize()).isEqualTo(size);
+ assertThat(((KotlinSerializationJsonDecoder) getNextDecoder(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);
@@ -187,7 +192,7 @@ public void clonedConfigurer() {
writers = findCodec(this.configurer.getWriters(), MultipartHttpMessageWriter.class).getPartWriters();
assertThat(sseDecoder).isNotSameAs(jackson2Decoder);
- assertThat(writers).hasSize(11);
+ assertThat(writers).hasSize(12);
}
@Test // gh-24194
@@ -197,7 +202,7 @@ public void cloneShouldNotDropMultipartCodecs() {
List> writers =
findCodec(clone.getWriters(), MultipartHttpMessageWriter.class).getPartWriters();
- assertThat(writers).hasSize(11);
+ assertThat(writers).hasSize(12);
}
@Test
@@ -211,7 +216,7 @@ public void cloneShouldNotBeImpactedByChangesToOriginal() {
List> writers =
findCodec(clone.getWriters(), MultipartHttpMessageWriter.class).getPartWriters();
- assertThat(writers).hasSize(11);
+ assertThat(writers).hasSize(12);
}
private Decoder> getNextDecoder(List> readers) {
diff --git a/spring-web/src/test/java/org/springframework/http/codec/support/CodecConfigurerTests.java b/spring-web/src/test/java/org/springframework/http/codec/support/CodecConfigurerTests.java
index 26cb40fd2212..003646099fdd 100644
--- a/spring-web/src/test/java/org/springframework/http/codec/support/CodecConfigurerTests.java
+++ b/spring-web/src/test/java/org/springframework/http/codec/support/CodecConfigurerTests.java
@@ -52,6 +52,8 @@
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.json.KotlinSerializationJsonDecoder;
+import org.springframework.http.codec.json.KotlinSerializationJsonEncoder;
import org.springframework.http.codec.protobuf.ProtobufDecoder;
import org.springframework.http.codec.protobuf.ProtobufEncoder;
import org.springframework.http.codec.protobuf.ProtobufHttpMessageWriter;
@@ -79,7 +81,7 @@ class CodecConfigurerTests {
@Test
void defaultReaders() {
List> readers = this.configurer.getReaders();
- assertThat(readers.size()).isEqualTo(12);
+ assertThat(readers.size()).isEqualTo(13);
assertThat(getNextDecoder(readers).getClass()).isEqualTo(ByteArrayDecoder.class);
assertThat(getNextDecoder(readers).getClass()).isEqualTo(ByteBufferDecoder.class);
assertThat(getNextDecoder(readers).getClass()).isEqualTo(DataBufferDecoder.class);
@@ -88,6 +90,7 @@ void defaultReaders() {
assertStringDecoder(getNextDecoder(readers), true);
assertThat(getNextDecoder(readers).getClass()).isEqualTo(ProtobufDecoder.class);
assertThat(readers.get(this.index.getAndIncrement()).getClass()).isEqualTo(FormHttpMessageReader.class);
+ assertThat(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationJsonDecoder.class);
assertThat(getNextDecoder(readers).getClass()).isEqualTo(Jackson2JsonDecoder.class);
assertThat(getNextDecoder(readers).getClass()).isEqualTo(Jackson2SmileDecoder.class);
assertThat(getNextDecoder(readers).getClass()).isEqualTo(Jaxb2XmlDecoder.class);
@@ -97,7 +100,7 @@ void defaultReaders() {
@Test
void defaultWriters() {
List> writers = this.configurer.getWriters();
- assertThat(writers.size()).isEqualTo(11);
+ assertThat(writers.size()).isEqualTo(12);
assertThat(getNextEncoder(writers).getClass()).isEqualTo(ByteArrayEncoder.class);
assertThat(getNextEncoder(writers).getClass()).isEqualTo(ByteBufferEncoder.class);
assertThat(getNextEncoder(writers).getClass()).isEqualTo(DataBufferEncoder.class);
@@ -105,6 +108,7 @@ void defaultWriters() {
assertThat(writers.get(index.getAndIncrement()).getClass()).isEqualTo(ResourceHttpMessageWriter.class);
assertStringEncoder(getNextEncoder(writers), true);
assertThat(writers.get(index.getAndIncrement()).getClass()).isEqualTo(ProtobufHttpMessageWriter.class);
+ assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationJsonEncoder.class);
assertThat(getNextEncoder(writers).getClass()).isEqualTo(Jackson2JsonEncoder.class);
assertThat(getNextEncoder(writers).getClass()).isEqualTo(Jackson2SmileEncoder.class);
assertThat(getNextEncoder(writers).getClass()).isEqualTo(Jaxb2XmlEncoder.class);
@@ -133,7 +137,7 @@ void defaultAndCustomReaders() {
List> readers = this.configurer.getReaders();
- assertThat(readers.size()).isEqualTo(16);
+ assertThat(readers.size()).isEqualTo(17);
assertThat(getNextDecoder(readers)).isSameAs(customDecoder1);
assertThat(readers.get(this.index.getAndIncrement())).isSameAs(customReader1);
assertThat(getNextDecoder(readers).getClass()).isEqualTo(ByteArrayDecoder.class);
@@ -146,6 +150,7 @@ void defaultAndCustomReaders() {
assertThat(readers.get(this.index.getAndIncrement()).getClass()).isEqualTo(FormHttpMessageReader.class);
assertThat(getNextDecoder(readers)).isSameAs(customDecoder2);
assertThat(readers.get(this.index.getAndIncrement())).isSameAs(customReader2);
+ assertThat(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationJsonDecoder.class);
assertThat(getNextDecoder(readers).getClass()).isEqualTo(Jackson2JsonDecoder.class);
assertThat(getNextDecoder(readers).getClass()).isEqualTo(Jackson2SmileDecoder.class);
assertThat(getNextDecoder(readers).getClass()).isEqualTo(Jaxb2XmlDecoder.class);
@@ -174,7 +179,7 @@ void defaultAndCustomWriters() {
List> writers = this.configurer.getWriters();
- assertThat(writers.size()).isEqualTo(15);
+ assertThat(writers.size()).isEqualTo(16);
assertThat(getNextEncoder(writers)).isSameAs(customEncoder1);
assertThat(writers.get(this.index.getAndIncrement())).isSameAs(customWriter1);
assertThat(getNextEncoder(writers).getClass()).isEqualTo(ByteArrayEncoder.class);
@@ -186,6 +191,7 @@ void defaultAndCustomWriters() {
assertThat(writers.get(index.getAndIncrement()).getClass()).isEqualTo(ProtobufHttpMessageWriter.class);
assertThat(getNextEncoder(writers)).isSameAs(customEncoder2);
assertThat(writers.get(this.index.getAndIncrement())).isSameAs(customWriter2);
+ assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationJsonEncoder.class);
assertThat(getNextEncoder(writers).getClass()).isEqualTo(Jackson2JsonEncoder.class);
assertThat(getNextEncoder(writers).getClass()).isEqualTo(Jackson2SmileEncoder.class);
assertThat(getNextEncoder(writers).getClass()).isEqualTo(Jaxb2XmlEncoder.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 3e24238068ad..0e458925b03c 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
@@ -56,6 +56,8 @@
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.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.PartHttpMessageWriter;
@@ -83,7 +85,7 @@ public class ServerCodecConfigurerTests {
@Test
public void defaultReaders() {
List> readers = this.configurer.getReaders();
- assertThat(readers.size()).isEqualTo(14);
+ assertThat(readers.size()).isEqualTo(15);
assertThat(getNextDecoder(readers).getClass()).isEqualTo(ByteArrayDecoder.class);
assertThat(getNextDecoder(readers).getClass()).isEqualTo(ByteBufferDecoder.class);
assertThat(getNextDecoder(readers).getClass()).isEqualTo(DataBufferDecoder.class);
@@ -94,6 +96,7 @@ public void defaultReaders() {
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(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationJsonDecoder.class);
assertThat(getNextDecoder(readers).getClass()).isEqualTo(Jackson2JsonDecoder.class);
assertThat(getNextDecoder(readers).getClass()).isEqualTo(Jackson2SmileDecoder.class);
assertThat(getNextDecoder(readers).getClass()).isEqualTo(Jaxb2XmlDecoder.class);
@@ -103,7 +106,7 @@ public void defaultReaders() {
@Test
public void defaultWriters() {
List> writers = this.configurer.getWriters();
- assertThat(writers.size()).isEqualTo(13);
+ assertThat(writers.size()).isEqualTo(14);
assertThat(getNextEncoder(writers).getClass()).isEqualTo(ByteArrayEncoder.class);
assertThat(getNextEncoder(writers).getClass()).isEqualTo(ByteBufferEncoder.class);
assertThat(getNextEncoder(writers).getClass()).isEqualTo(DataBufferEncoder.class);
@@ -112,6 +115,7 @@ public void defaultWriters() {
assertStringEncoder(getNextEncoder(writers), true);
assertThat(writers.get(index.getAndIncrement()).getClass()).isEqualTo(ProtobufHttpMessageWriter.class);
assertThat(writers.get(this.index.getAndIncrement()).getClass()).isEqualTo(PartHttpMessageWriter.class);
+ assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationJsonEncoder.class);
assertThat(getNextEncoder(writers).getClass()).isEqualTo(Jackson2JsonEncoder.class);
assertThat(getNextEncoder(writers).getClass()).isEqualTo(Jackson2SmileEncoder.class);
assertThat(getNextEncoder(writers).getClass()).isEqualTo(Jaxb2XmlEncoder.class);
@@ -152,6 +156,7 @@ public void maxInMemorySize() {
DefaultPartHttpMessageReader reader = (DefaultPartHttpMessageReader) multipartReader.getPartReader();
assertThat((reader).getMaxInMemorySize()).isEqualTo(size);
+ assertThat(((KotlinSerializationJsonDecoder) getNextDecoder(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);
diff --git a/spring-web/src/test/kotlin/org/springframework/http/codec/json/KotlinSerializationJsonDecoderTests.kt b/spring-web/src/test/kotlin/org/springframework/http/codec/json/KotlinSerializationJsonDecoderTests.kt
index 6be5d1981cd6..2dedc390e33e 100644
--- a/spring-web/src/test/kotlin/org/springframework/http/codec/json/KotlinSerializationJsonDecoderTests.kt
+++ b/spring-web/src/test/kotlin/org/springframework/http/codec/json/KotlinSerializationJsonDecoderTests.kt
@@ -53,6 +53,11 @@ class KotlinSerializationJsonDecoderTests : AbstractDecoderTests>(), null, MediaType.APPLICATION_JSON)).isTrue()
+ assertThat(converter.canRead(typeTokenOf>(), null, MediaType.APPLICATION_JSON)).isTrue()
+ assertThat(converter.canRead(typeTokenOf>(), null, MediaType.APPLICATION_JSON)).isTrue()
+ assertThat(converter.canRead(typeTokenOf>(), null, MediaType.APPLICATION_PDF)).isFalse()
}
@Test
@@ -60,6 +68,11 @@ class KotlinSerializationJsonHttpMessageConverterTests {
assertThat(converter.canWrite(Map::class.java, MediaType.APPLICATION_JSON)).isTrue()
assertThat(converter.canWrite(List::class.java, MediaType.APPLICATION_JSON)).isTrue()
assertThat(converter.canWrite(Set::class.java, MediaType.APPLICATION_JSON)).isTrue()
+
+ assertThat(converter.canWrite(typeTokenOf>(), null, MediaType.APPLICATION_JSON)).isTrue()
+ assertThat(converter.canWrite(typeTokenOf>(), null, MediaType.APPLICATION_JSON)).isTrue()
+ assertThat(converter.canWrite(typeTokenOf>(), null, MediaType.APPLICATION_JSON)).isTrue()
+ assertThat(converter.canWrite(typeTokenOf>(), null, MediaType.APPLICATION_PDF)).isFalse()
}
@Test
@@ -296,4 +309,12 @@ class KotlinSerializationJsonHttpMessageConverterTests {
)
data class NotSerializableBean(val string: String)
+
+ open class TypeBase
+
+ inline fun typeTokenOf(): Type {
+ val base = object : TypeBase() {}
+ val superType = base::class.java.genericSuperclass!!
+ return (superType as ParameterizedType).actualTypeArguments.first()!!
+ }
}
diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java
index ae40c3dc9ffe..4995b3f28ff4 100644
--- a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java
+++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java
@@ -906,6 +906,9 @@ else if (jaxb2Present) {
}
}
+ if (kotlinSerializationJsonPresent) {
+ messageConverters.add(new KotlinSerializationJsonHttpMessageConverter());
+ }
if (jackson2Present) {
Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.json();
if (this.applicationContext != null) {
@@ -919,9 +922,6 @@ else if (gsonPresent) {
else if (jsonbPresent) {
messageConverters.add(new JsonbHttpMessageConverter());
}
- else if (kotlinSerializationJsonPresent) {
- messageConverters.add(new KotlinSerializationJsonHttpMessageConverter());
- }
if (jackson2SmilePresent) {
Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.smile();
diff --git a/src/docs/asciidoc/languages/kotlin.adoc b/src/docs/asciidoc/languages/kotlin.adoc
index 76355eabf2f2..f5cdfe5bcb26 100644
--- a/src/docs/asciidoc/languages/kotlin.adoc
+++ b/src/docs/asciidoc/languages/kotlin.adoc
@@ -389,17 +389,13 @@ project for more details.
=== Kotlin multiplatform serialization
As of Spring Framework 5.3, https://github.com/Kotlin/kotlinx.serialization[Kotlin multiplatform serialization] is
-supported in Spring MVC, Spring WebFlux and Spring Messaging. The builtin support currently only targets JSON format.
-
-To enable it, follow https://github.com/Kotlin/kotlinx.serialization#setup[those instructions] and make sure neither
-Jackson, GSON or JSONB are in the classpath.
-
-NOTE: For a typical Spring Boot web application, that can be achieved by excluding `spring-boot-starter-json` dependency.
-
-In Spring MVC, if you need Jackson, GSON or JSONB for other purposes, you can keep them on the classpath and
-<> to remove `MappingJackson2HttpMessageConverter` and add
-`KotlinSerializationJsonHttpMessageConverter`.
+supported in Spring MVC, Spring WebFlux and Spring Messaging (RSocket). The builtin support currently only targets JSON format.
+To enable it, follow https://github.com/Kotlin/kotlinx.serialization#setup[those instructions] to add the related dependency and plugin.
+With Spring MVC and WebFlux, both Kotlin serialization and Jackson will be configured by default if they are in the classpath since
+Kotlin serialization is designed to serialize only Kotlin classes annotated with `@Serializable`.
+With Spring Messaging (RSocket), make sure that neither Jackson, GSON or JSONB are in the classpath if you want automatic configuration,
+if Jackson is needed configure `KotlinSerializationJsonMessageConverter` manually.
== Coroutines