Refine kotlinx.serialization support

This commit introduces the following changes:
 - Converters/codecs are now used based on generic type info.
 - On WebMvc and WebFlux, kotlinx.serialization is enabled along
   to Jackson because it only serializes Kotlin @Serializable classes
   which is not enough for error or actuator endpoints in Boot as
   described on spring-projects/spring-boot#24238.

TODO: leverage Kotlin/kotlinx.serialization#1164 when fixed.

Closes gh-26147
This commit is contained in:
Sébastien Deleuze
2020-11-26 12:15:23 +01:00
parent 1f701d9bad
commit 43faa439ab
13 changed files with 142 additions and 35 deletions

View File

@@ -69,10 +69,38 @@ public class KotlinSerializationJsonDecoder extends AbstractDecoder<Object> {
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.
* <p>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 class KotlinSerializationJsonDecoder extends AbstractDecoder<Object> {
* 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.
* <p>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

View File

@@ -71,8 +71,14 @@ public class KotlinSerializationJsonEncoder extends AbstractEncoder<Object> {
@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 class KotlinSerializationJsonEncoder extends AbstractEncoder<Object> {
* 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.
* <p>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

View File

@@ -312,6 +312,11 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure
((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 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure
return Collections.emptyList();
}
List<HttpMessageReader<?>> 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 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure
*/
final List<HttpMessageWriter<?>> getBaseObjectWriters() {
List<HttpMessageWriter<?>> 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()));

View File

@@ -88,6 +88,28 @@ public class KotlinSerializationJsonHttpMessageConverter extends AbstractGeneric
}
}
@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 @@ public class KotlinSerializationJsonHttpMessageConverter extends AbstractGeneric
* 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.
* <p>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

View File

@@ -56,6 +56,8 @@ 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.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<HttpMessageReader<?>> 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 class ClientCodecConfigurerTests {
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 class ClientCodecConfigurerTests {
@Test
public void defaultWriters() {
List<HttpMessageWriter<?>> 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 class ClientCodecConfigurerTests {
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 class ClientCodecConfigurerTests {
int size = 99;
this.configurer.defaultCodecs().maxInMemorySize(size);
List<HttpMessageReader<?>> 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 class ClientCodecConfigurerTests {
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 class ClientCodecConfigurerTests {
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 class ClientCodecConfigurerTests {
List<HttpMessageWriter<?>> writers =
findCodec(clone.getWriters(), MultipartHttpMessageWriter.class).getPartWriters();
assertThat(writers).hasSize(11);
assertThat(writers).hasSize(12);
}
@Test
@@ -211,7 +216,7 @@ public class ClientCodecConfigurerTests {
List<HttpMessageWriter<?>> writers =
findCodec(clone.getWriters(), MultipartHttpMessageWriter.class).getPartWriters();
assertThat(writers).hasSize(11);
assertThat(writers).hasSize(12);
}
private Decoder<?> getNextDecoder(List<HttpMessageReader<?>> readers) {

View File

@@ -52,6 +52,8 @@ 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.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<HttpMessageReader<?>> 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 @@ class CodecConfigurerTests {
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 @@ class CodecConfigurerTests {
@Test
void defaultWriters() {
List<HttpMessageWriter<?>> 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 @@ 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(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 @@ class CodecConfigurerTests {
List<HttpMessageReader<?>> 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 @@ class CodecConfigurerTests {
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 @@ class CodecConfigurerTests {
List<HttpMessageWriter<?>> 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 @@ class CodecConfigurerTests {
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);

View File

@@ -56,6 +56,8 @@ 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.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<HttpMessageReader<?>> 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 class ServerCodecConfigurerTests {
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 class ServerCodecConfigurerTests {
@Test
public void defaultWriters() {
List<HttpMessageWriter<?>> 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 class ServerCodecConfigurerTests {
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 class ServerCodecConfigurerTests {
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);

View File

@@ -53,6 +53,11 @@ class KotlinSerializationJsonDecoderTests : AbstractDecoderTests<KotlinSerializa
MediaType("application", "json", StandardCharsets.US_ASCII))).isTrue()
Assertions.assertThat(decoder.canDecode(ResolvableType.forClass(Pojo::class.java),
MediaType("application", "json", StandardCharsets.ISO_8859_1))).isTrue()
Assertions.assertThat(decoder.canDecode(ResolvableType.forClassWithGenerics(List::class.java, Int::class.java), MediaType.APPLICATION_JSON)).isTrue()
Assertions.assertThat(decoder.canDecode(ResolvableType.forClassWithGenerics(List::class.java, Pojo::class.java), MediaType.APPLICATION_JSON)).isTrue()
Assertions.assertThat(decoder.canDecode(ResolvableType.forClassWithGenerics(ArrayList::class.java, Int::class.java), MediaType.APPLICATION_JSON)).isTrue()
Assertions.assertThat(decoder.canDecode(ResolvableType.forClassWithGenerics(ArrayList::class.java, Int::class.java), MediaType.APPLICATION_PDF)).isFalse()
}
@Test

View File

@@ -49,7 +49,11 @@ class KotlinSerializationJsonEncoderTests : AbstractEncoderTests<KotlinSerializa
MediaType("application", "json", StandardCharsets.UTF_8))).isTrue()
Assertions.assertThat(encoder.canEncode(ResolvableType.forClass(Pojo::class.java),
MediaType("application", "json", StandardCharsets.US_ASCII))).isTrue()
Assertions.assertThat(encoder.canEncode(ResolvableType.NONE, null)).isTrue()
Assertions.assertThat(encoder.canEncode(ResolvableType.forClassWithGenerics(List::class.java, Int::class.java), MediaType.APPLICATION_JSON)).isTrue()
Assertions.assertThat(encoder.canEncode(ResolvableType.forClassWithGenerics(List::class.java, KotlinSerializationJsonDecoderTests.Pojo::class.java), MediaType.APPLICATION_JSON)).isTrue()
Assertions.assertThat(encoder.canEncode(ResolvableType.forClassWithGenerics(ArrayList::class.java, Int::class.java), MediaType.APPLICATION_JSON)).isTrue()
Assertions.assertThat(encoder.canEncode(ResolvableType.forClassWithGenerics(ArrayList::class.java, Int::class.java), MediaType.APPLICATION_PDF)).isFalse()
}
@Test

View File

@@ -24,6 +24,8 @@ import org.springframework.http.MediaType
import org.springframework.http.MockHttpInputMessage
import org.springframework.http.MockHttpOutputMessage
import org.springframework.http.converter.HttpMessageNotReadableException
import java.lang.reflect.ParameterizedType
import java.lang.reflect.Type
import java.nio.charset.StandardCharsets
import kotlin.reflect.javaType
import kotlin.reflect.typeOf
@@ -34,6 +36,7 @@ import kotlin.reflect.typeOf
* @author Andreas Ahlenstorf
* @author Sebastien Deleuze
*/
@Suppress("UsePropertyAccessSyntax")
class KotlinSerializationJsonHttpMessageConverterTests {
private val converter = KotlinSerializationJsonHttpMessageConverter()
@@ -48,6 +51,11 @@ class KotlinSerializationJsonHttpMessageConverterTests {
assertThat(converter.canRead(Map::class.java, MediaType.APPLICATION_JSON)).isTrue()
assertThat(converter.canRead(List::class.java, MediaType.APPLICATION_JSON)).isTrue()
assertThat(converter.canRead(Set::class.java, MediaType.APPLICATION_JSON)).isTrue()
assertThat(converter.canRead(typeTokenOf<List<Int>>(), null, MediaType.APPLICATION_JSON)).isTrue()
assertThat(converter.canRead(typeTokenOf<List<SerializableBean>>(), null, MediaType.APPLICATION_JSON)).isTrue()
assertThat(converter.canRead(typeTokenOf<ArrayList<Int>>(), null, MediaType.APPLICATION_JSON)).isTrue()
assertThat(converter.canRead(typeTokenOf<List<Int>>(), 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<List<Int>>(), null, MediaType.APPLICATION_JSON)).isTrue()
assertThat(converter.canWrite(typeTokenOf<List<SerializableBean>>(), null, MediaType.APPLICATION_JSON)).isTrue()
assertThat(converter.canWrite(typeTokenOf<ArrayList<Int>>(), null, MediaType.APPLICATION_JSON)).isTrue()
assertThat(converter.canWrite(typeTokenOf<List<Int>>(), null, MediaType.APPLICATION_PDF)).isFalse()
}
@Test
@@ -296,4 +309,12 @@ class KotlinSerializationJsonHttpMessageConverterTests {
)
data class NotSerializableBean(val string: String)
open class TypeBase<T>
inline fun <reified T> typeTokenOf(): Type {
val base = object : TypeBase<T>() {}
val superType = base::class.java.genericSuperclass!!
return (superType as ParameterizedType).actualTypeArguments.first()!!
}
}