Browse Source

Prevent Kotlin Serialization converters side effects

This commit updates Kotlin serialization converters to perform
an additional check invoking
KotlinDetector#hasSerializableAnnotation to decide if the
related type should be processed or not.

The goal is to prevent in the default arrangement conflicts
between general purpose converters like Jackson and
Kotlin serialization when both are used.

New constructors allowing to specify a custom predicate
are also introduced.

See gh-35761
pull/34993/merge
Sébastien Deleuze 1 month ago
parent
commit
d64edc01c0
  1. 51
      spring-web/src/main/java/org/springframework/http/converter/AbstractKotlinSerializationHttpMessageConverter.java
  2. 25
      spring-web/src/main/java/org/springframework/http/converter/KotlinSerializationBinaryHttpMessageConverter.java
  3. 25
      spring-web/src/main/java/org/springframework/http/converter/KotlinSerializationStringHttpMessageConverter.java
  4. 45
      spring-web/src/main/java/org/springframework/http/converter/cbor/KotlinSerializationCborHttpMessageConverter.java
  5. 47
      spring-web/src/main/java/org/springframework/http/converter/json/KotlinSerializationJsonHttpMessageConverter.java
  6. 45
      spring-web/src/main/java/org/springframework/http/converter/protobuf/KotlinSerializationProtobufHttpMessageConverter.java
  7. 85
      spring-web/src/test/kotlin/org/springframework/http/converter/cbor/KotlinSerializationCborHttpMessageConverterTests.kt
  8. 93
      spring-web/src/test/kotlin/org/springframework/http/converter/json/KotlinSerializationJsonHttpMessageConverterTests.kt
  9. 91
      spring-web/src/test/kotlin/org/springframework/http/converter/protobuf/KotlinSerializationProtobufHttpMessageConverterTests.kt
  10. 4
      spring-webmvc/src/test/kotlin/org/springframework/web/servlet/mvc/method/annotation/RequestResponseBodyMethodProcessorKotlinTests.kt

51
spring-web/src/main/java/org/springframework/http/converter/AbstractKotlinSerializationHttpMessageConverter.java

@ -20,6 +20,7 @@ import java.io.IOException; @@ -20,6 +20,7 @@ import java.io.IOException;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import kotlin.reflect.KType;
import kotlinx.serialization.KSerializer;
@ -27,6 +28,7 @@ import kotlinx.serialization.SerialFormat; @@ -27,6 +28,7 @@ import kotlinx.serialization.SerialFormat;
import kotlinx.serialization.SerializersKt;
import org.jspecify.annotations.Nullable;
import org.springframework.core.KotlinDetector;
import org.springframework.core.ResolvableType;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
@ -38,9 +40,11 @@ import org.springframework.util.ConcurrentReferenceHashMap; @@ -38,9 +40,11 @@ import org.springframework.util.ConcurrentReferenceHashMap;
* Abstract base class for {@link HttpMessageConverter} implementations that
* use Kotlin serialization.
*
* <p>As of Spring Framework 7.0,
* <a href="https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/polymorphism.md#open-polymorphism">open polymorphism</a>
* is supported.
* <p>As of Spring Framework 7.0, by default it only encodes types annotated with
* {@link kotlinx.serialization.Serializable @Serializable} at type or generics level
* since it allows combined usage with other general purpose converters without conflicts.
* Alternative constructors with a {@code Predicate<ResolvableType>} parameter can be used
* to customize this behavior.
*
* @author Andreas Ahlenstorf
* @author Sebastien Deleuze
@ -58,15 +62,30 @@ public abstract class AbstractKotlinSerializationHttpMessageConverter<T extends @@ -58,15 +62,30 @@ public abstract class AbstractKotlinSerializationHttpMessageConverter<T extends
private final T format;
private final Predicate<ResolvableType> typePredicate;
/**
* Construct an {@code AbstractKotlinSerializationHttpMessageConverter} with multiple supported media type and
* format.
* @param format the format
* @param supportedMediaTypes the supported media types
* Creates a new instance with the given format and supported mime types
* which only converters types annotated with
* {@link kotlinx.serialization.Serializable @Serializable} at type or
* generics level.
*/
protected AbstractKotlinSerializationHttpMessageConverter(T format, MediaType... supportedMediaTypes) {
super(supportedMediaTypes);
this.typePredicate = KotlinDetector::hasSerializableAnnotation;
this.format = format;
}
/**
* Creates a new instance with the given format and supported mime types
* which only converts types for which the specified predicate returns
* {@code true}.
* @since 7.0
*/
protected AbstractKotlinSerializationHttpMessageConverter(T format, Predicate<ResolvableType> typePredicate, MediaType... supportedMediaTypes) {
super(supportedMediaTypes);
this.typePredicate = typePredicate;
this.format = format;
}
@ -77,27 +96,27 @@ public abstract class AbstractKotlinSerializationHttpMessageConverter<T extends @@ -77,27 +96,27 @@ public abstract class AbstractKotlinSerializationHttpMessageConverter<T extends
@Override
protected boolean supports(Class<?> clazz) {
return serializer(ResolvableType.forClass(clazz), null) != null;
ResolvableType type = ResolvableType.forClass(clazz);
if (!this.typePredicate.test(type)) {
return false;
}
return serializer(type, null) != null;
}
@Override
public boolean canRead(ResolvableType type, @Nullable MediaType mediaType) {
if (!ResolvableType.NONE.equals(type) && serializer(type, null) != null) {
return canRead(mediaType);
}
else {
if (!this.typePredicate.test(type) || ResolvableType.NONE.equals(type)) {
return false;
}
return serializer(type, null) != null && canRead(mediaType);
}
@Override
public boolean canWrite(ResolvableType type, Class<?> clazz, @Nullable MediaType mediaType) {
if (!ResolvableType.NONE.equals(type) && serializer(type, null) != null) {
return canWrite(mediaType);
}
else {
if (!this.typePredicate.test(type) || ResolvableType.NONE.equals(type)) {
return false;
}
return serializer(type, null) != null && canWrite(mediaType);
}
@Override

25
spring-web/src/main/java/org/springframework/http/converter/KotlinSerializationBinaryHttpMessageConverter.java

@ -17,11 +17,13 @@ @@ -17,11 +17,13 @@
package org.springframework.http.converter;
import java.io.IOException;
import java.util.function.Predicate;
import kotlinx.serialization.BinaryFormat;
import kotlinx.serialization.KSerializer;
import kotlinx.serialization.SerializationException;
import org.springframework.core.ResolvableType;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
@ -31,9 +33,11 @@ import org.springframework.util.StreamUtils; @@ -31,9 +33,11 @@ import org.springframework.util.StreamUtils;
* Abstract base class for {@link HttpMessageConverter} implementations that
* defer to Kotlin {@linkplain BinaryFormat binary serializers}.
*
* <p>As of Spring Framework 7.0,
* <a href="https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/polymorphism.md#open-polymorphism">open polymorphism</a>
* is supported.
* <p>As of Spring Framework 7.0, by default it only encodes types annotated with
* {@link kotlinx.serialization.Serializable @Serializable} at type or generics level
* since it allows combined usage with other general purpose converters without conflicts.
* Alternative constructors with a {@code Predicate<ResolvableType>} parameter can be used
* to customize this behavior.
*
* @author Andreas Ahlenstorf
* @author Sebastien Deleuze
@ -47,12 +51,25 @@ public abstract class KotlinSerializationBinaryHttpMessageConverter<T extends Bi @@ -47,12 +51,25 @@ public abstract class KotlinSerializationBinaryHttpMessageConverter<T extends Bi
extends AbstractKotlinSerializationHttpMessageConverter<T> {
/**
* Construct an {@code KotlinSerializationBinaryHttpMessageConverter} with format and supported media types.
* Creates a new instance with the given format and supported mime types
* which only converters types annotated with
* {@link kotlinx.serialization.Serializable @Serializable} at type or
* generics level.
*/
protected KotlinSerializationBinaryHttpMessageConverter(T format, MediaType... supportedMediaTypes) {
super(format, supportedMediaTypes);
}
/**
* Creates a new instance with the given format and supported mime types
* which only converts types for which the specified predicate returns
* {@code true}.
* @since 7.0
*/
protected KotlinSerializationBinaryHttpMessageConverter(T format, Predicate<ResolvableType> typePredicate, MediaType... supportedMediaTypes) {
super(format, typePredicate, supportedMediaTypes);
}
@Override
protected Object readInternal(KSerializer<Object> serializer, T format, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {

25
spring-web/src/main/java/org/springframework/http/converter/KotlinSerializationStringHttpMessageConverter.java

@ -19,12 +19,14 @@ package org.springframework.http.converter; @@ -19,12 +19,14 @@ package org.springframework.http.converter;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.function.Predicate;
import kotlinx.serialization.KSerializer;
import kotlinx.serialization.SerializationException;
import kotlinx.serialization.StringFormat;
import org.jspecify.annotations.Nullable;
import org.springframework.core.ResolvableType;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
@ -34,9 +36,11 @@ import org.springframework.util.StreamUtils; @@ -34,9 +36,11 @@ import org.springframework.util.StreamUtils;
* Abstract base class for {@link HttpMessageConverter} implementations that
* defer to Kotlin {@linkplain StringFormat string serializers}.
*
* <p>As of Spring Framework 7.0,
* <a href="https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/polymorphism.md#open-polymorphism">open polymorphism</a>
* is supported.
* <p>As of Spring Framework 7.0, by default it only encodes types annotated with
* {@link kotlinx.serialization.Serializable @Serializable} at type or generics level
* since it allows combined usage with other general purpose converters without conflicts.
* Alternative constructors with a {@code Predicate<ResolvableType>} parameter can be used
* to customize this behavior.
*
* @author Andreas Ahlenstorf
* @author Sebastien Deleuze
@ -51,12 +55,25 @@ public abstract class KotlinSerializationStringHttpMessageConverter<T extends St @@ -51,12 +55,25 @@ public abstract class KotlinSerializationStringHttpMessageConverter<T extends St
/**
* Construct an {@code KotlinSerializationStringHttpMessageConverter} with format and supported media types.
* Creates a new instance with the given format and supported mime types
* which only converters types annotated with
* {@link kotlinx.serialization.Serializable @Serializable} at type or
* generics level.
*/
protected KotlinSerializationStringHttpMessageConverter(T format, MediaType... supportedMediaTypes) {
super(format, supportedMediaTypes);
}
/**
* Creates a new instance with the given format and supported mime types
* which only converts types for which the specified predicate returns
* {@code true}.
* @since 7.0
*/
protected KotlinSerializationStringHttpMessageConverter(T format, Predicate<ResolvableType> typePredicate, MediaType... supportedMediaTypes) {
super(format, typePredicate, supportedMediaTypes);
}
@Override
protected Object readInternal(KSerializer<Object> serializer, T format, HttpInputMessage inputMessage)

45
spring-web/src/main/java/org/springframework/http/converter/cbor/KotlinSerializationCborHttpMessageConverter.java

@ -16,8 +16,11 @@ @@ -16,8 +16,11 @@
package org.springframework.http.converter.cbor;
import java.util.function.Predicate;
import kotlinx.serialization.cbor.Cbor;
import org.springframework.core.ResolvableType;
import org.springframework.http.MediaType;
import org.springframework.http.converter.KotlinSerializationBinaryHttpMessageConverter;
@ -27,20 +30,56 @@ import org.springframework.http.converter.KotlinSerializationBinaryHttpMessageCo @@ -27,20 +30,56 @@ import org.springframework.http.converter.KotlinSerializationBinaryHttpMessageCo
* <a href="https://github.com/Kotlin/kotlinx.serialization">kotlinx.serialization</a>.
* It supports {@code application/cbor}.
*
* <p>As of Spring Framework 7.0,
* <a href="https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/polymorphism.md#open-polymorphism">open polymorphism</a>
* is supported.
* <p>As of Spring Framework 7.0, by default it only types annotated with
* {@link kotlinx.serialization.Serializable @Serializable} at type or generics
* level since it allows combined usage with other general purpose JSON decoders
* like {@link JacksonCborHttpMessageConverter} without conflicts.
*
* <p>Alternative constructors with a {@code Predicate<ResolvableType>}
* parameter can be used to customize this behavior. For example,
* {@code new KotlinSerializationCborHttpMessageConverter(type -> true)} will decode all types
* supported by Kotlin Serialization, including unannotated Kotlin enumerations,
* numbers, characters, booleans and strings.
*
* @author Iain Henderson
* @author Sebastien Deleuze
* @since 6.0
*/
public class KotlinSerializationCborHttpMessageConverter extends KotlinSerializationBinaryHttpMessageConverter<Cbor> {
/**
* Construct a new converter using {@link Cbor.Default} instance which
* only converts types annotated with {@link kotlinx.serialization.Serializable @Serializable}
* at type or generics level.
*/
public KotlinSerializationCborHttpMessageConverter() {
this(Cbor.Default);
}
/**
* Construct a new converter using {@link Cbor.Default} instance which
* only converts types for which the specified predicate returns {@code true}.
* @since 7.0
*/
public KotlinSerializationCborHttpMessageConverter(Predicate<ResolvableType> typePredicate) {
this(Cbor.Default, typePredicate);
}
/**
* Construct a new converter using the provided {@link Cbor} instance which
* only converts types annotated with {@link kotlinx.serialization.Serializable @Serializable}
* at type or generics level.
*/
public KotlinSerializationCborHttpMessageConverter(Cbor cbor) {
super(cbor, MediaType.APPLICATION_CBOR);
}
/**
* Construct a new converter using the provided {@link Cbor} instance which
* only converts types for which the specified predicate returns {@code true}.
* @since 7.0
*/
public KotlinSerializationCborHttpMessageConverter(Cbor cbor, Predicate<ResolvableType> typePredicate) {
super(cbor, typePredicate, MediaType.APPLICATION_CBOR);
}
}

47
spring-web/src/main/java/org/springframework/http/converter/json/KotlinSerializationJsonHttpMessageConverter.java

@ -16,8 +16,11 @@ @@ -16,8 +16,11 @@
package org.springframework.http.converter.json;
import java.util.function.Predicate;
import kotlinx.serialization.json.Json;
import org.springframework.core.ResolvableType;
import org.springframework.http.MediaType;
import org.springframework.http.converter.KotlinSerializationStringHttpMessageConverter;
@ -28,9 +31,16 @@ import org.springframework.http.converter.KotlinSerializationStringHttpMessageCo @@ -28,9 +31,16 @@ import org.springframework.http.converter.KotlinSerializationStringHttpMessageCo
* It supports {@code application/json} and {@code application/*+json} with
* various character sets, {@code UTF-8} being the default.
*
* <p>As of Spring Framework 7.0,
* <a href="https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/polymorphism.md#open-polymorphism">open polymorphism</a>
* is supported.
* <p>As of Spring Framework 7.0, by default it only types annotated with
* {@link kotlinx.serialization.Serializable @Serializable} at type or generics
* level since it allows combined usage with other general purpose JSON decoders
* like {@link JacksonJsonHttpMessageConverter} without conflicts.
*
* <p>Alternative constructors with a {@code Predicate<ResolvableType>}
* parameter can be used to customize this behavior. For example,
* {@code new KotlinSerializationJsonHttpMessageConverter(type -> true)} will decode all types
* supported by Kotlin Serialization, including unannotated Kotlin enumerations,
* numbers, characters, booleans and strings.
*
* @author Andreas Ahlenstorf
* @author Sebastien Deleuze
@ -40,17 +50,42 @@ import org.springframework.http.converter.KotlinSerializationStringHttpMessageCo @@ -40,17 +50,42 @@ import org.springframework.http.converter.KotlinSerializationStringHttpMessageCo
*/
public class KotlinSerializationJsonHttpMessageConverter extends KotlinSerializationStringHttpMessageConverter<Json> {
private static final MediaType[] DEFAULT_JSON_MIME_TYPES = new MediaType[] {
MediaType.APPLICATION_JSON, new MediaType("application", "*+json") };
/**
* Construct a new {@code KotlinSerializationJsonHttpMessageConverter} with the default configuration.
* Construct a new converter using {@link Json.Default} instance which
* only converts types annotated with {@link kotlinx.serialization.Serializable @Serializable}
* at type or generics level.
*/
public KotlinSerializationJsonHttpMessageConverter() {
this(Json.Default);
}
/**
* Construct a new {@code KotlinSerializationJsonHttpMessageConverter} with a custom configuration.
* Construct a new converter using {@link Json.Default} instance which
* only converts types for which the specified predicate returns {@code true}.
* @since 7.0
*/
public KotlinSerializationJsonHttpMessageConverter(Predicate<ResolvableType> typePredicate) {
this(Json.Default, typePredicate);
}
/**
* Construct a new converter using the provided {@link Json} instance which
* only converts types annotated with {@link kotlinx.serialization.Serializable @Serializable}
* at type or generics level.
*/
public KotlinSerializationJsonHttpMessageConverter(Json json) {
super(json, MediaType.APPLICATION_JSON, new MediaType("application", "*+json"));
super(json, DEFAULT_JSON_MIME_TYPES);
}
/**
* Construct a new converter using the provided {@link Json} instance which
* only converts types for which the specified predicate returns {@code true}.
* @since 7.0
*/
public KotlinSerializationJsonHttpMessageConverter(Json json, Predicate<ResolvableType> typePredicate) {
super(json, typePredicate, DEFAULT_JSON_MIME_TYPES);
}
}

45
spring-web/src/main/java/org/springframework/http/converter/protobuf/KotlinSerializationProtobufHttpMessageConverter.java

@ -16,8 +16,11 @@ @@ -16,8 +16,11 @@
package org.springframework.http.converter.protobuf;
import java.util.function.Predicate;
import kotlinx.serialization.protobuf.ProtoBuf;
import org.springframework.core.ResolvableType;
import org.springframework.http.MediaType;
import org.springframework.http.converter.KotlinSerializationBinaryHttpMessageConverter;
@ -27,23 +30,59 @@ import org.springframework.http.converter.KotlinSerializationBinaryHttpMessageCo @@ -27,23 +30,59 @@ import org.springframework.http.converter.KotlinSerializationBinaryHttpMessageCo
* <a href="https://github.com/Kotlin/kotlinx.serialization">kotlinx.serialization</a>.
* It supports {@code application/x-protobuf}, {@code application/octet-stream}, and {@code application/vnd.google.protobuf}.
*
* <p>As of Spring Framework 7.0,
* <a href="https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/polymorphism.md#open-polymorphism">open polymorphism</a>
* is supported.
* <p>As of Spring Framework 7.0, by default it only converts types annotated with
* {@link kotlinx.serialization.Serializable @Serializable} at type or generics
* level.
*
* <p>Alternative constructors with a {@code Predicate<ResolvableType>}
* parameter can be used to customize this behavior. For example,
* {@code new KotlinSerializationProtobufHttpMessageConverter(type -> true)} will convert all types
* supported by Kotlin Serialization, including unannotated Kotlin enumerations,
* numbers, characters, booleans and strings.
*
* @author Iain Henderson
* @author Sebstien Deleuze
* @since 6.0
*/
public class KotlinSerializationProtobufHttpMessageConverter extends
KotlinSerializationBinaryHttpMessageConverter<ProtoBuf> {
/**
* Construct a new converter using {@link ProtoBuf.Default} instance which
* only converts types annotated with {@link kotlinx.serialization.Serializable @Serializable}
* at type or generics level.
*/
public KotlinSerializationProtobufHttpMessageConverter() {
this(ProtoBuf.Default);
}
/**
* Construct a new converter using {@link ProtoBuf.Default} instance which
* only converts types for which the specified predicate returns {@code true}.
* @since 7.0
*/
public KotlinSerializationProtobufHttpMessageConverter(Predicate<ResolvableType> typePredicate) {
this(ProtoBuf.Default, typePredicate);
}
/**
* Construct a new converter using the provided {@link ProtoBuf} instance which
* only converts types annotated with {@link kotlinx.serialization.Serializable @Serializable}
* at type or generics level.
*/
public KotlinSerializationProtobufHttpMessageConverter(ProtoBuf protobuf) {
super(protobuf, MediaType.APPLICATION_PROTOBUF, MediaType.APPLICATION_OCTET_STREAM,
new MediaType("application", "vnd.google.protobuf"));
}
/**
* Construct a new converter using the provided {@link ProtoBuf} instance which
* only converts types for which the specified predicate returns {@code true}.
* @since 7.0
*/
public KotlinSerializationProtobufHttpMessageConverter(ProtoBuf protobuf, Predicate<ResolvableType> typePredicate) {
super(protobuf, typePredicate, MediaType.APPLICATION_PROTOBUF, MediaType.APPLICATION_OCTET_STREAM,
new MediaType("application", "vnd.google.protobuf"));
}
}

85
spring-web/src/test/kotlin/org/springframework/http/converter/cbor/KotlinSerializationCborHttpMessageConverterTests.kt

@ -33,6 +33,7 @@ import org.springframework.core.Ordered @@ -33,6 +33,7 @@ import org.springframework.core.Ordered
import org.springframework.core.ResolvableType
import org.springframework.http.MediaType
import org.springframework.http.converter.HttpMessageNotReadableException
import org.springframework.http.converter.json.KotlinSerializationJsonHttpMessageConverter
import org.springframework.web.testfixture.http.MockHttpInputMessage
import org.springframework.web.testfixture.http.MockHttpOutputMessage
@ -56,57 +57,107 @@ class KotlinSerializationCborHttpMessageConverterTests { @@ -56,57 +57,107 @@ class KotlinSerializationCborHttpMessageConverterTests {
fraction = 42f
)
private val serializableBeanArray = arrayOf(serializableBean)
private val serializableBeanArrayBody = Cbor.Default.encodeToByteArray(serializableBeanArray)
private val serializableBeanArrayBody = Cbor.encodeToByteArray(serializableBeanArray)
@Test
fun canReadCbor() {
assertThat(converter.canRead(SerializableBean::class.java, MediaType.APPLICATION_CBOR)).isTrue()
assertThat(converter.canRead(SerializableBean::class.java, MediaType.APPLICATION_JSON)).isFalse()
assertThat(converter.canRead(String::class.java, MediaType.APPLICATION_CBOR)).isTrue()
assertThat(converter.canRead(String::class.java, MediaType.APPLICATION_CBOR)).isFalse()
assertThat(converter.canRead(NotSerializableBean::class.java, MediaType.APPLICATION_CBOR)).isFalse()
assertThat(converter.canRead(Map::class.java, MediaType.APPLICATION_CBOR)).isTrue()
assertThat(converter.canRead(Map::class.java, MediaType.APPLICATION_CBOR)).isFalse()
assertThat(converter.canRead(resolvableTypeOf<Map<String, SerializableBean>>(), MediaType.APPLICATION_CBOR)).isTrue()
assertThat(converter.canRead(List::class.java, MediaType.APPLICATION_CBOR)).isTrue()
assertThat(converter.canRead(List::class.java, MediaType.APPLICATION_CBOR)).isFalse()
assertThat(converter.canRead(resolvableTypeOf<List<SerializableBean>>(), MediaType.APPLICATION_CBOR)).isTrue()
assertThat(converter.canRead(Set::class.java, MediaType.APPLICATION_CBOR)).isTrue()
assertThat(converter.canRead(Set::class.java, MediaType.APPLICATION_CBOR)).isFalse()
assertThat(converter.canRead(resolvableTypeOf<Set<SerializableBean>>(), MediaType.APPLICATION_CBOR)).isTrue()
assertThat(converter.canRead(resolvableTypeOf<List<Int>>(), MediaType.APPLICATION_CBOR)).isTrue()
assertThat(converter.canRead(resolvableTypeOf<ArrayList<Int>>(), MediaType.APPLICATION_CBOR)).isTrue()
assertThat(converter.canRead(resolvableTypeOf<List<Int>>(), MediaType.APPLICATION_CBOR)).isFalse()
assertThat(converter.canRead(resolvableTypeOf<ArrayList<Int>>(), MediaType.APPLICATION_CBOR)).isFalse()
assertThat(converter.canRead(resolvableTypeOf<List<Int>>(), MediaType.APPLICATION_JSON)).isFalse()
assertThat(converter.canRead(resolvableTypeOf<Ordered>(), MediaType.APPLICATION_CBOR)).isTrue()
assertThat(converter.canRead(resolvableTypeOf<List<Ordered>>(), MediaType.APPLICATION_CBOR)).isTrue()
assertThat(converter.canRead(resolvableTypeOf<Ordered>(), MediaType.APPLICATION_CBOR)).isFalse()
assertThat(converter.canRead(resolvableTypeOf<List<Ordered>>(), MediaType.APPLICATION_CBOR)).isFalse()
assertThat(converter.canRead(resolvableTypeOf<OrderedImpl>(), MediaType.APPLICATION_CBOR)).isFalse()
assertThat(converter.canRead(resolvableTypeOf<List<OrderedImpl>>(), MediaType.APPLICATION_CBOR)).isFalse()
}
@Test
fun canReadCborWithAllTypes() {
val converterWithAllTypes = KotlinSerializationCborHttpMessageConverter { true }
assertThat(converterWithAllTypes.canRead(SerializableBean::class.java, MediaType.APPLICATION_CBOR)).isTrue()
assertThat(converterWithAllTypes.canRead(SerializableBean::class.java, MediaType.APPLICATION_JSON)).isFalse()
assertThat(converterWithAllTypes.canRead(String::class.java, MediaType.APPLICATION_CBOR)).isTrue()
assertThat(converterWithAllTypes.canRead(NotSerializableBean::class.java, MediaType.APPLICATION_CBOR)).isFalse()
assertThat(converterWithAllTypes.canRead(Map::class.java, MediaType.APPLICATION_CBOR)).isTrue()
assertThat(converterWithAllTypes.canRead(resolvableTypeOf<Map<String, SerializableBean>>(), MediaType.APPLICATION_CBOR)).isTrue()
assertThat(converterWithAllTypes.canRead(List::class.java, MediaType.APPLICATION_CBOR)).isTrue()
assertThat(converterWithAllTypes.canRead(resolvableTypeOf<List<SerializableBean>>(), MediaType.APPLICATION_CBOR)).isTrue()
assertThat(converterWithAllTypes.canRead(Set::class.java, MediaType.APPLICATION_CBOR)).isTrue()
assertThat(converterWithAllTypes.canRead(resolvableTypeOf<Set<SerializableBean>>(), MediaType.APPLICATION_CBOR)).isTrue()
assertThat(converterWithAllTypes.canRead(resolvableTypeOf<List<Int>>(), MediaType.APPLICATION_CBOR)).isTrue()
assertThat(converterWithAllTypes.canRead(resolvableTypeOf<ArrayList<Int>>(), MediaType.APPLICATION_CBOR)).isTrue()
assertThat(converterWithAllTypes.canRead(resolvableTypeOf<List<Int>>(), MediaType.APPLICATION_JSON)).isFalse()
assertThat(converterWithAllTypes.canRead(resolvableTypeOf<Ordered>(), MediaType.APPLICATION_CBOR)).isTrue()
assertThat(converterWithAllTypes.canRead(resolvableTypeOf<List<Ordered>>(), MediaType.APPLICATION_CBOR)).isTrue()
assertThat(converterWithAllTypes.canRead(resolvableTypeOf<OrderedImpl>(), MediaType.APPLICATION_CBOR)).isFalse()
assertThat(converterWithAllTypes.canRead(resolvableTypeOf<List<OrderedImpl>>(), MediaType.APPLICATION_CBOR)).isFalse()
}
@Test
fun canWriteCbor() {
assertThat(converter.canWrite(SerializableBean::class.java, MediaType.APPLICATION_CBOR)).isTrue()
assertThat(converter.canWrite(SerializableBean::class.java, MediaType.APPLICATION_JSON)).isFalse()
assertThat(converter.canWrite(String::class.java, MediaType.APPLICATION_CBOR)).isTrue()
assertThat(converter.canWrite(String::class.java, MediaType.APPLICATION_CBOR)).isFalse()
assertThat(converter.canWrite(NotSerializableBean::class.java, MediaType.APPLICATION_CBOR)).isFalse()
assertThat(converter.canWrite(Map::class.java, MediaType.APPLICATION_CBOR)).isTrue()
assertThat(converter.canWrite(Map::class.java, MediaType.APPLICATION_CBOR)).isFalse()
assertThat(converter.canWrite(resolvableTypeOf<Map<String, SerializableBean>>(), Map::class.java, MediaType.APPLICATION_CBOR)).isTrue()
assertThat(converter.canWrite(List::class.java, MediaType.APPLICATION_CBOR)).isTrue()
assertThat(converter.canWrite(List::class.java, MediaType.APPLICATION_CBOR)).isFalse()
assertThat(converter.canWrite(resolvableTypeOf<List<SerializableBean>>(), List::class.java, MediaType.APPLICATION_CBOR)).isTrue()
assertThat(converter.canWrite(Set::class.java, MediaType.APPLICATION_CBOR)).isTrue()
assertThat(converter.canWrite(Set::class.java, MediaType.APPLICATION_CBOR)).isFalse()
assertThat(converter.canWrite(resolvableTypeOf<Set<SerializableBean>>(), Set::class.java, MediaType.APPLICATION_CBOR)).isTrue()
assertThat(converter.canWrite(resolvableTypeOf<List<Int>>(), List::class.java, MediaType.APPLICATION_CBOR)).isTrue()
assertThat(converter.canWrite(resolvableTypeOf<ArrayList<Int>>(), List::class.java, MediaType.APPLICATION_CBOR)).isTrue()
assertThat(converter.canWrite(resolvableTypeOf<List<Int>>(), List::class.java, MediaType.APPLICATION_CBOR)).isFalse()
assertThat(converter.canWrite(resolvableTypeOf<ArrayList<Int>>(), List::class.java, MediaType.APPLICATION_CBOR)).isFalse()
assertThat(converter.canWrite(resolvableTypeOf<List<Int>>(), List::class.java, MediaType.APPLICATION_JSON)).isFalse()
assertThat(converter.canWrite(resolvableTypeOf<Ordered>(), Ordered::class.java, MediaType.APPLICATION_CBOR)).isTrue()
assertThat(converter.canWrite(resolvableTypeOf<Ordered>(), Ordered::class.java, MediaType.APPLICATION_CBOR)).isFalse()
assertThat(converter.canWrite(resolvableTypeOf<OrderedImpl>(), Ordered::class.java, MediaType.APPLICATION_CBOR)).isFalse()
}
@Test
fun canWriteCborWithAllTypes() {
val converterWithAllTypes = KotlinSerializationCborHttpMessageConverter { true }
assertThat(converterWithAllTypes.canWrite(SerializableBean::class.java, MediaType.APPLICATION_CBOR)).isTrue()
assertThat(converterWithAllTypes.canWrite(SerializableBean::class.java, MediaType.APPLICATION_JSON)).isFalse()
assertThat(converterWithAllTypes.canWrite(String::class.java, MediaType.APPLICATION_CBOR)).isTrue()
assertThat(converterWithAllTypes.canWrite(NotSerializableBean::class.java, MediaType.APPLICATION_CBOR)).isFalse()
assertThat(converterWithAllTypes.canWrite(Map::class.java, MediaType.APPLICATION_CBOR)).isTrue()
assertThat(converterWithAllTypes.canWrite(resolvableTypeOf<Map<String, SerializableBean>>(), Map::class.java, MediaType.APPLICATION_CBOR)).isTrue()
assertThat(converterWithAllTypes.canWrite(List::class.java, MediaType.APPLICATION_CBOR)).isTrue()
assertThat(converterWithAllTypes.canWrite(resolvableTypeOf<List<SerializableBean>>(), List::class.java, MediaType.APPLICATION_CBOR)).isTrue()
assertThat(converterWithAllTypes.canWrite(Set::class.java, MediaType.APPLICATION_CBOR)).isTrue()
assertThat(converterWithAllTypes.canWrite(resolvableTypeOf<Set<SerializableBean>>(), Set::class.java, MediaType.APPLICATION_CBOR)).isTrue()
assertThat(converterWithAllTypes.canWrite(resolvableTypeOf<List<Int>>(), List::class.java, MediaType.APPLICATION_CBOR)).isTrue()
assertThat(converterWithAllTypes.canWrite(resolvableTypeOf<ArrayList<Int>>(), List::class.java, MediaType.APPLICATION_CBOR)).isTrue()
assertThat(converterWithAllTypes.canWrite(resolvableTypeOf<List<Int>>(), List::class.java, MediaType.APPLICATION_JSON)).isFalse()
assertThat(converterWithAllTypes.canWrite(resolvableTypeOf<Ordered>(), Ordered::class.java, MediaType.APPLICATION_CBOR)).isTrue()
assertThat(converterWithAllTypes.canWrite(resolvableTypeOf<OrderedImpl>(), Ordered::class.java, MediaType.APPLICATION_CBOR)).isFalse()
}
@Test
fun readObject() {
val serializableBeanBody = Cbor.Default.encodeToByteArray(serializableBean)
val serializableBeanBody = Cbor.encodeToByteArray(serializableBean)
val inputMessage = MockHttpInputMessage(serializableBeanBody)
inputMessage.headers.contentType = MediaType.APPLICATION_CBOR
val result = converter.read(SerializableBean::class.java, inputMessage) as SerializableBean

93
spring-web/src/test/kotlin/org/springframework/http/converter/json/KotlinSerializationJsonHttpMessageConverterTests.kt

@ -45,7 +45,6 @@ import kotlin.reflect.typeOf @@ -45,7 +45,6 @@ import kotlin.reflect.typeOf
* @author Andreas Ahlenstorf
* @author Sebastien Deleuze
*/
@Suppress("UsePropertyAccessSyntax")
class KotlinSerializationJsonHttpMessageConverterTests {
private val converter = KotlinSerializationJsonHttpMessageConverter()
@ -54,22 +53,22 @@ class KotlinSerializationJsonHttpMessageConverterTests { @@ -54,22 +53,22 @@ class KotlinSerializationJsonHttpMessageConverterTests {
fun canReadJson() {
assertThat(converter.canRead(SerializableBean::class.java, MediaType.APPLICATION_JSON)).isTrue()
assertThat(converter.canRead(SerializableBean::class.java, MediaType.APPLICATION_PDF)).isFalse()
assertThat(converter.canRead(String::class.java, MediaType.APPLICATION_JSON)).isTrue()
assertThat(converter.canRead(String::class.java, MediaType.APPLICATION_JSON)).isFalse()
assertThat(converter.canRead(NotSerializableBean::class.java, MediaType.APPLICATION_JSON)).isFalse()
assertThat(converter.canRead(Map::class.java, MediaType.APPLICATION_JSON)).isTrue()
assertThat(converter.canRead(Map::class.java, MediaType.APPLICATION_JSON)).isFalse()
assertThat(converter.canRead(resolvableTypeOf<Map<String, SerializableBean>>(), MediaType.APPLICATION_JSON)).isTrue()
assertThat(converter.canRead(List::class.java, MediaType.APPLICATION_JSON)).isTrue()
assertThat(converter.canRead(List::class.java, MediaType.APPLICATION_JSON)).isFalse()
assertThat(converter.canRead(resolvableTypeOf<List<SerializableBean>>(), MediaType.APPLICATION_JSON)).isTrue()
assertThat(converter.canRead(Set::class.java, MediaType.APPLICATION_JSON)).isTrue()
assertThat(converter.canRead(Set::class.java, MediaType.APPLICATION_JSON)).isFalse()
assertThat(converter.canRead(resolvableTypeOf<Set<SerializableBean>>(), MediaType.APPLICATION_JSON)).isTrue()
assertThat(converter.canRead(resolvableTypeOf<List<Int>>(), MediaType.APPLICATION_JSON)).isTrue()
assertThat(converter.canRead(resolvableTypeOf<ArrayList<Int>>(), MediaType.APPLICATION_JSON)).isTrue()
assertThat(converter.canRead(resolvableTypeOf<List<Int>>(), MediaType.APPLICATION_JSON)).isFalse()
assertThat(converter.canRead(resolvableTypeOf<ArrayList<Int>>(), MediaType.APPLICATION_JSON)).isFalse()
assertThat(converter.canRead(resolvableTypeOf<List<Int>>(), MediaType.APPLICATION_PDF)).isFalse()
assertThat(converter.canRead(resolvableTypeOf<Ordered>(), MediaType.APPLICATION_JSON)).isTrue()
assertThat(converter.canRead(resolvableTypeOf<List<Ordered>>(), MediaType.APPLICATION_JSON)).isTrue()
assertThat(converter.canRead(resolvableTypeOf<Ordered>(), MediaType.APPLICATION_JSON)).isFalse()
assertThat(converter.canRead(resolvableTypeOf<List<Ordered>>(), MediaType.APPLICATION_JSON)).isFalse()
assertThat(converter.canRead(resolvableTypeOf<OrderedImpl>(), MediaType.APPLICATION_JSON)).isFalse()
assertThat(converter.canRead(resolvableTypeOf<List<OrderedImpl>>(), MediaType.APPLICATION_JSON)).isFalse()
@ -78,25 +77,55 @@ class KotlinSerializationJsonHttpMessageConverterTests { @@ -78,25 +77,55 @@ class KotlinSerializationJsonHttpMessageConverterTests {
assertThat(converter.canRead(ResolvableType.forType(BigDecimal::class.java), MediaType.APPLICATION_JSON)).isFalse()
}
@Test
fun canReadJsonWithAllTypes() {
val converterWithAllTypes = KotlinSerializationJsonHttpMessageConverter { true }
assertThat(converterWithAllTypes.canRead(SerializableBean::class.java, MediaType.APPLICATION_JSON)).isTrue()
assertThat(converterWithAllTypes.canRead(SerializableBean::class.java, MediaType.APPLICATION_PDF)).isFalse()
assertThat(converterWithAllTypes.canRead(String::class.java, MediaType.APPLICATION_JSON)).isTrue()
assertThat(converterWithAllTypes.canRead(NotSerializableBean::class.java, MediaType.APPLICATION_JSON)).isFalse()
assertThat(converterWithAllTypes.canRead(Map::class.java, MediaType.APPLICATION_JSON)).isTrue()
assertThat(converterWithAllTypes.canRead(resolvableTypeOf<Map<String, SerializableBean>>(), MediaType.APPLICATION_JSON)).isTrue()
assertThat(converterWithAllTypes.canRead(List::class.java, MediaType.APPLICATION_JSON)).isTrue()
assertThat(converterWithAllTypes.canRead(resolvableTypeOf<List<SerializableBean>>(), MediaType.APPLICATION_JSON)).isTrue()
assertThat(converterWithAllTypes.canRead(Set::class.java, MediaType.APPLICATION_JSON)).isTrue()
assertThat(converterWithAllTypes.canRead(resolvableTypeOf<Set<SerializableBean>>(), MediaType.APPLICATION_JSON)).isTrue()
assertThat(converterWithAllTypes.canRead(resolvableTypeOf<List<Int>>(), MediaType.APPLICATION_JSON)).isTrue()
assertThat(converterWithAllTypes.canRead(resolvableTypeOf<ArrayList<Int>>(), MediaType.APPLICATION_JSON)).isTrue()
assertThat(converterWithAllTypes.canRead(resolvableTypeOf<List<Int>>(), MediaType.APPLICATION_PDF)).isFalse()
assertThat(converterWithAllTypes.canRead(resolvableTypeOf<Ordered>(), MediaType.APPLICATION_JSON)).isTrue()
assertThat(converterWithAllTypes.canRead(resolvableTypeOf<List<Ordered>>(), MediaType.APPLICATION_JSON)).isTrue()
assertThat(converterWithAllTypes.canRead(resolvableTypeOf<OrderedImpl>(), MediaType.APPLICATION_JSON)).isFalse()
assertThat(converterWithAllTypes.canRead(resolvableTypeOf<List<OrderedImpl>>(), MediaType.APPLICATION_JSON)).isFalse()
assertThat(converterWithAllTypes.canRead(ResolvableType.forType(ResolvableType.NONE.type), MediaType.APPLICATION_JSON)).isFalse()
assertThat(converterWithAllTypes.canRead(ResolvableType.forType(BigDecimal::class.java), MediaType.APPLICATION_JSON)).isFalse()
}
@Test
fun canWriteJson() {
assertThat(converter.canWrite(SerializableBean::class.java, MediaType.APPLICATION_JSON)).isTrue()
assertThat(converter.canWrite(SerializableBean::class.java, MediaType.APPLICATION_PDF)).isFalse()
assertThat(converter.canWrite(String::class.java, MediaType.APPLICATION_JSON)).isTrue()
assertThat(converter.canWrite(String::class.java, MediaType.APPLICATION_JSON)).isFalse()
assertThat(converter.canWrite(NotSerializableBean::class.java, MediaType.APPLICATION_JSON)).isFalse()
assertThat(converter.canWrite(Map::class.java, MediaType.APPLICATION_JSON)).isTrue()
assertThat(converter.canWrite(Map::class.java, MediaType.APPLICATION_JSON)).isFalse()
assertThat(converter.canWrite(resolvableTypeOf<Map<String, SerializableBean>>(), Map::class.java, MediaType.APPLICATION_JSON)).isTrue()
assertThat(converter.canWrite(List::class.java, MediaType.APPLICATION_JSON)).isTrue()
assertThat(converter.canWrite(List::class.java, MediaType.APPLICATION_JSON)).isFalse()
assertThat(converter.canWrite(resolvableTypeOf<List<SerializableBean>>(), List::class.java, MediaType.APPLICATION_JSON)).isTrue()
assertThat(converter.canWrite(Set::class.java, MediaType.APPLICATION_JSON)).isTrue()
assertThat(converter.canWrite(Set::class.java, MediaType.APPLICATION_JSON)).isFalse()
assertThat(converter.canWrite(resolvableTypeOf<Set<SerializableBean>>(), Set::class.java, MediaType.APPLICATION_JSON)).isTrue()
assertThat(converter.canWrite(resolvableTypeOf<List<Int>>(), List::class.java, MediaType.APPLICATION_JSON)).isTrue()
assertThat(converter.canWrite(resolvableTypeOf<ArrayList<Int>>(), List::class.java, MediaType.APPLICATION_JSON)).isTrue()
assertThat(converter.canWrite(resolvableTypeOf<List<Int>>(), List::class.java, MediaType.APPLICATION_JSON)).isFalse()
assertThat(converter.canWrite(resolvableTypeOf<ArrayList<Int>>(), List::class.java, MediaType.APPLICATION_JSON)).isFalse()
assertThat(converter.canWrite(resolvableTypeOf<List<Int>>(), List::class.java, MediaType.APPLICATION_PDF)).isFalse()
assertThat(converter.canWrite(resolvableTypeOf<Ordered>(), Ordered::class.java, MediaType.APPLICATION_JSON)).isTrue()
assertThat(converter.canWrite(resolvableTypeOf<Ordered>(), Ordered::class.java, MediaType.APPLICATION_JSON)).isFalse()
assertThat(converter.canWrite(resolvableTypeOf<OrderedImpl>(), OrderedImpl::class.java, MediaType.APPLICATION_JSON)).isFalse()
assertThat(converter.canWrite(ResolvableType.NONE, SerializableBean::class.java, MediaType.APPLICATION_JSON)).isFalse()
@ -104,6 +133,34 @@ class KotlinSerializationJsonHttpMessageConverterTests { @@ -104,6 +133,34 @@ class KotlinSerializationJsonHttpMessageConverterTests {
assertThat(converter.canWrite(ResolvableType.forType(BigDecimal::class.java), BigDecimal::class.java, MediaType.APPLICATION_JSON)).isFalse()
}
@Test
fun canWriteJsonWithAllTypes() {
val converterWithAllTypes = KotlinSerializationJsonHttpMessageConverter { true }
assertThat(converterWithAllTypes.canWrite(SerializableBean::class.java, MediaType.APPLICATION_JSON)).isTrue()
assertThat(converterWithAllTypes.canWrite(SerializableBean::class.java, MediaType.APPLICATION_PDF)).isFalse()
assertThat(converterWithAllTypes.canWrite(String::class.java, MediaType.APPLICATION_JSON)).isTrue()
assertThat(converterWithAllTypes.canWrite(NotSerializableBean::class.java, MediaType.APPLICATION_JSON)).isFalse()
assertThat(converterWithAllTypes.canWrite(Map::class.java, MediaType.APPLICATION_JSON)).isTrue()
assertThat(converterWithAllTypes.canWrite(resolvableTypeOf<Map<String, SerializableBean>>(), Map::class.java, MediaType.APPLICATION_JSON)).isTrue()
assertThat(converterWithAllTypes.canWrite(List::class.java, MediaType.APPLICATION_JSON)).isTrue()
assertThat(converterWithAllTypes.canWrite(resolvableTypeOf<List<SerializableBean>>(), List::class.java, MediaType.APPLICATION_JSON)).isTrue()
assertThat(converterWithAllTypes.canWrite(Set::class.java, MediaType.APPLICATION_JSON)).isTrue()
assertThat(converterWithAllTypes.canWrite(resolvableTypeOf<Set<SerializableBean>>(), Set::class.java, MediaType.APPLICATION_JSON)).isTrue()
assertThat(converterWithAllTypes.canWrite(resolvableTypeOf<List<Int>>(), List::class.java, MediaType.APPLICATION_JSON)).isTrue()
assertThat(converterWithAllTypes.canWrite(resolvableTypeOf<ArrayList<Int>>(), List::class.java, MediaType.APPLICATION_JSON)).isTrue()
assertThat(converterWithAllTypes.canWrite(resolvableTypeOf<List<Int>>(), List::class.java, MediaType.APPLICATION_PDF)).isFalse()
assertThat(converterWithAllTypes.canWrite(resolvableTypeOf<Ordered>(), Ordered::class.java, MediaType.APPLICATION_JSON)).isTrue()
assertThat(converterWithAllTypes.canWrite(resolvableTypeOf<OrderedImpl>(), OrderedImpl::class.java, MediaType.APPLICATION_JSON)).isFalse()
assertThat(converterWithAllTypes.canWrite(ResolvableType.NONE, SerializableBean::class.java, MediaType.APPLICATION_JSON)).isFalse()
assertThat(converterWithAllTypes.canWrite(ResolvableType.forType(BigDecimal::class.java), BigDecimal::class.java, MediaType.APPLICATION_JSON)).isFalse()
}
@Test
fun canReadMicroformats() {
val jsonSubtype = MediaType("application", "vnd.test-micro-type+json")
@ -364,13 +421,13 @@ class KotlinSerializationJsonHttpMessageConverterTests { @@ -364,13 +421,13 @@ class KotlinSerializationJsonHttpMessageConverterTests {
@Test
fun canReadBigDecimalWithSerializerModule() {
val customConverter = KotlinSerializationJsonHttpMessageConverter(customJson)
val customConverter = KotlinSerializationJsonHttpMessageConverter(customJson) { true }
assertThat(customConverter.canRead(BigDecimal::class.java, MediaType.APPLICATION_JSON)).isTrue()
}
@Test
fun canWriteBigDecimalWithSerializerModule() {
val customConverter = KotlinSerializationJsonHttpMessageConverter(customJson)
val customConverter = KotlinSerializationJsonHttpMessageConverter(customJson) { true }
assertThat(customConverter.canWrite(BigDecimal::class.java, MediaType.APPLICATION_JSON)).isTrue()
}

91
spring-web/src/test/kotlin/org/springframework/http/converter/protobuf/KotlinSerializationProtobufHttpMessageConverterTests.kt

@ -27,6 +27,7 @@ import org.springframework.core.Ordered @@ -27,6 +27,7 @@ import org.springframework.core.Ordered
import org.springframework.core.ResolvableType
import org.springframework.http.MediaType
import org.springframework.http.converter.HttpMessageNotReadableException
import org.springframework.http.converter.cbor.KotlinSerializationCborHttpMessageConverter
import org.springframework.web.testfixture.http.MockHttpInputMessage
import org.springframework.web.testfixture.http.MockHttpOutputMessage
import java.lang.reflect.ParameterizedType
@ -59,26 +60,27 @@ class KotlinSerializationProtobufHttpMessageConverterTests { @@ -59,26 +60,27 @@ class KotlinSerializationProtobufHttpMessageConverterTests {
fraction = 42f
)
private val serializableBeanArray = arrayOf(serializableBean)
private val serializableBeanArrayBody = ProtoBuf.Default.encodeToByteArray(serializableBeanArray)
private val serializableBeanArrayBody = ProtoBuf.encodeToByteArray(serializableBeanArray)
@Test
fun canReadProtobuf() {
for (mimeType in mediaTypes) {
assertThat(converter.canRead(SerializableBean::class.java, mimeType)).isTrue()
assertThat(converter.canRead(String::class.java, mimeType)).isTrue()
assertThat(converter.canRead(String::class.java, mimeType)).isFalse()
assertThat(converter.canRead(NotSerializableBean::class.java, mimeType)).isFalse()
assertThat(converter.canRead(Map::class.java, mimeType)).isTrue()
assertThat(converter.canRead(Map::class.java, mimeType)).isFalse()
assertThat(converter.canRead(resolvableTypeOf<Map<String, SerializableBean>>(), mimeType)).isTrue()
assertThat(converter.canRead(List::class.java, mimeType)).isTrue()
assertThat(converter.canRead(List::class.java, mimeType)).isFalse()
assertThat(converter.canRead(resolvableTypeOf<List<SerializableBean>>(), mimeType)).isTrue()
assertThat(converter.canRead(Set::class.java, mimeType)).isTrue()
assertThat(converter.canRead(Set::class.java, mimeType)).isFalse()
assertThat(converter.canRead(resolvableTypeOf<Set<SerializableBean>>(), mimeType)).isTrue()
assertThat(converter.canRead(resolvableTypeOf<List<Int>>(), mimeType)).isTrue()
assertThat(converter.canRead(resolvableTypeOf<ArrayList<Int>>(),mimeType)).isTrue()
assertThat(converter.canRead(resolvableTypeOf<List<Int>>(), mimeType)).isFalse()
assertThat(converter.canRead(resolvableTypeOf<ArrayList<Int>>(),mimeType)).isFalse()
assertThat(converter.canRead(resolvableTypeOf<Ordered>(), mimeType)).isTrue()
assertThat(converter.canRead(resolvableTypeOf<List<Ordered>>(), mimeType)).isTrue()
assertThat(converter.canRead(resolvableTypeOf<Ordered>(), mimeType)).isFalse()
assertThat(converter.canRead(resolvableTypeOf<List<Ordered>>(), mimeType)).isFalse()
assertThat(converter.canRead(resolvableTypeOf<OrderedImpl>(), mimeType)).isFalse()
assertThat(converter.canRead(resolvableTypeOf<List<OrderedImpl>>(), mimeType)).isFalse()
}
@ -86,31 +88,86 @@ class KotlinSerializationProtobufHttpMessageConverterTests { @@ -86,31 +88,86 @@ class KotlinSerializationProtobufHttpMessageConverterTests {
assertThat(converter.canRead(resolvableTypeOf<List<Int>>(), MediaType.APPLICATION_JSON)).isFalse()
}
@Test
fun canReadProtobufForAllTypes() {
val converterWithAllTypes = KotlinSerializationProtobufHttpMessageConverter { true }
for (mimeType in mediaTypes) {
assertThat(converterWithAllTypes.canRead(SerializableBean::class.java, mimeType)).isTrue()
assertThat(converterWithAllTypes.canRead(String::class.java, mimeType)).isTrue()
assertThat(converterWithAllTypes.canRead(NotSerializableBean::class.java, mimeType)).isFalse()
assertThat(converterWithAllTypes.canRead(Map::class.java, mimeType)).isTrue()
assertThat(converterWithAllTypes.canRead(resolvableTypeOf<Map<String, SerializableBean>>(), mimeType)).isTrue()
assertThat(converterWithAllTypes.canRead(List::class.java, mimeType)).isTrue()
assertThat(converterWithAllTypes.canRead(resolvableTypeOf<List<SerializableBean>>(), mimeType)).isTrue()
assertThat(converterWithAllTypes.canRead(Set::class.java, mimeType)).isTrue()
assertThat(converterWithAllTypes.canRead(resolvableTypeOf<Set<SerializableBean>>(), mimeType)).isTrue()
assertThat(converterWithAllTypes.canRead(resolvableTypeOf<List<Int>>(), mimeType)).isTrue()
assertThat(converterWithAllTypes.canRead(resolvableTypeOf<ArrayList<Int>>(),mimeType)).isTrue()
assertThat(converterWithAllTypes.canRead(resolvableTypeOf<Ordered>(), mimeType)).isTrue()
assertThat(converterWithAllTypes.canRead(resolvableTypeOf<List<Ordered>>(), mimeType)).isTrue()
assertThat(converterWithAllTypes.canRead(resolvableTypeOf<OrderedImpl>(), mimeType)).isFalse()
assertThat(converterWithAllTypes.canRead(resolvableTypeOf<List<OrderedImpl>>(), mimeType)).isFalse()
}
assertThat(converterWithAllTypes.canRead(SerializableBean::class.java, MediaType.APPLICATION_JSON)).isFalse()
assertThat(converterWithAllTypes.canRead(resolvableTypeOf<List<Int>>(), MediaType.APPLICATION_JSON)).isFalse()
}
@Test
fun canWriteProtobuf() {
for (mimeType in mediaTypes) {
assertThat(converter.canWrite(SerializableBean::class.java, mimeType)).isTrue()
assertThat(converter.canWrite(String::class.java, mimeType)).isTrue()
assertThat(converter.canWrite(String::class.java, mimeType)).isFalse()
assertThat(converter.canWrite(NotSerializableBean::class.java, mimeType)).isFalse()
assertThat(converter.canWrite(Map::class.java, mimeType)).isTrue()
assertThat(converter.canWrite(Map::class.java, mimeType)).isFalse()
assertThat(converter.canWrite(resolvableTypeOf<Map<String, SerializableBean>>(), Map::class.java, mimeType)).isTrue()
assertThat(converter.canWrite(List::class.java, mimeType)).isTrue()
assertThat(converter.canWrite(List::class.java, mimeType)).isFalse()
assertThat(converter.canWrite(resolvableTypeOf<List<SerializableBean>>(), List::class.java, mimeType)).isTrue()
assertThat(converter.canWrite(Set::class.java, mimeType)).isTrue()
assertThat(converter.canWrite(Set::class.java, mimeType)).isFalse()
assertThat(converter.canWrite(resolvableTypeOf<Set<SerializableBean>>(), Set::class.java, mimeType)).isTrue()
assertThat(converter.canWrite(resolvableTypeOf<List<Int>>(), List::class.java, mimeType)).isTrue()
assertThat(converter.canWrite(resolvableTypeOf<ArrayList<Int>>(), List::class.java, mimeType)).isTrue()
assertThat(converter.canWrite(resolvableTypeOf<List<Int>>(), List::class.java, mimeType)).isFalse()
assertThat(converter.canWrite(resolvableTypeOf<ArrayList<Int>>(), List::class.java, mimeType)).isFalse()
assertThat(converter.canWrite(resolvableTypeOf<Ordered>(), Ordered::class.java, mimeType)).isTrue()
assertThat(converter.canWrite(resolvableTypeOf<Ordered>(), OrderedImpl::class.java, mimeType)).isTrue()
assertThat(converter.canWrite(resolvableTypeOf<Ordered>(), Ordered::class.java, mimeType)).isFalse()
assertThat(converter.canWrite(resolvableTypeOf<Ordered>(), OrderedImpl::class.java, mimeType)).isFalse()
}
assertThat(converter.canWrite(SerializableBean::class.java, MediaType.APPLICATION_JSON)).isFalse()
assertThat(converter.canWrite(resolvableTypeOf<List<Int>>(), List::class.java, MediaType.APPLICATION_JSON)).isFalse()
}
@Test
fun canWriteProtobufForAllTypes() {
val converterWithAllTypes = KotlinSerializationProtobufHttpMessageConverter { true }
for (mimeType in mediaTypes) {
assertThat(converterWithAllTypes.canWrite(SerializableBean::class.java, mimeType)).isTrue()
assertThat(converterWithAllTypes.canWrite(String::class.java, mimeType)).isTrue()
assertThat(converterWithAllTypes.canWrite(NotSerializableBean::class.java, mimeType)).isFalse()
assertThat(converterWithAllTypes.canWrite(Map::class.java, mimeType)).isTrue()
assertThat(converterWithAllTypes.canWrite(resolvableTypeOf<Map<String, SerializableBean>>(), Map::class.java, mimeType)).isTrue()
assertThat(converterWithAllTypes.canWrite(List::class.java, mimeType)).isTrue()
assertThat(converterWithAllTypes.canWrite(resolvableTypeOf<List<SerializableBean>>(), List::class.java, mimeType)).isTrue()
assertThat(converterWithAllTypes.canWrite(Set::class.java, mimeType)).isTrue()
assertThat(converterWithAllTypes.canWrite(resolvableTypeOf<Set<SerializableBean>>(), Set::class.java, mimeType)).isTrue()
assertThat(converterWithAllTypes.canWrite(resolvableTypeOf<List<Int>>(), List::class.java, mimeType)).isTrue()
assertThat(converterWithAllTypes.canWrite(resolvableTypeOf<ArrayList<Int>>(), List::class.java, mimeType)).isTrue()
assertThat(converterWithAllTypes.canWrite(resolvableTypeOf<Ordered>(), Ordered::class.java, mimeType)).isTrue()
assertThat(converterWithAllTypes.canWrite(resolvableTypeOf<Ordered>(), OrderedImpl::class.java, mimeType)).isTrue()
}
assertThat(converterWithAllTypes.canWrite(SerializableBean::class.java, MediaType.APPLICATION_JSON)).isFalse()
assertThat(converterWithAllTypes.canWrite(resolvableTypeOf<List<Int>>(), List::class.java, MediaType.APPLICATION_JSON)).isFalse()
}
@Test
fun readObject() {
val serializableBeanBody = ProtoBuf.Default.encodeToByteArray(serializableBean)

4
spring-webmvc/src/test/kotlin/org/springframework/web/servlet/mvc/method/annotation/RequestResponseBodyMethodProcessorKotlinTests.kt

@ -109,7 +109,7 @@ class RequestResponseBodyMethodProcessorKotlinTests { @@ -109,7 +109,7 @@ class RequestResponseBodyMethodProcessorKotlinTests {
val handlerMethod = HandlerMethod(SampleController(), method)
val methodReturnType = handlerMethod.returnType
val converters = listOf(KotlinSerializationJsonHttpMessageConverter())
val converters = listOf(KotlinSerializationJsonHttpMessageConverter { true })
val processor = RequestResponseBodyMethodProcessor(converters, null, listOf(KotlinResponseBodyAdvice()))
val returnValue: Any = SampleController().writeNullableMap()
@ -179,7 +179,7 @@ class RequestResponseBodyMethodProcessorKotlinTests { @@ -179,7 +179,7 @@ class RequestResponseBodyMethodProcessorKotlinTests {
this.servletRequest.setContent(content.toByteArray(StandardCharsets.UTF_8))
this.servletRequest.setContentType("application/json")
val converters = listOf(StringHttpMessageConverter(), KotlinSerializationJsonHttpMessageConverter())
val converters = listOf(StringHttpMessageConverter(), KotlinSerializationJsonHttpMessageConverter { true })
val processor = RequestResponseBodyMethodProcessor(converters, null, listOf(KotlinRequestBodyAdvice()))
val method = SampleController::readNullableMap::javaMethod.get()!!

Loading…
Cancel
Save