diff --git a/spring-web/src/main/java/org/springframework/http/converter/AbstractKotlinSerializationHttpMessageConverter.java b/spring-web/src/main/java/org/springframework/http/converter/AbstractKotlinSerializationHttpMessageConverter.java index fc387721a7e..21c6e868321 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/AbstractKotlinSerializationHttpMessageConverter.java +++ b/spring-web/src/main/java/org/springframework/http/converter/AbstractKotlinSerializationHttpMessageConverter.java @@ -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; 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; * Abstract base class for {@link HttpMessageConverter} implementations that * use Kotlin serialization. * - *

As of Spring Framework 7.0, - * open polymorphism - * is supported. + *

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} parameter can be used + * to customize this behavior. * * @author Andreas Ahlenstorf * @author Sebastien Deleuze @@ -58,15 +62,30 @@ public abstract class AbstractKotlinSerializationHttpMessageConverter 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 typePredicate, MediaType... supportedMediaTypes) { + super(supportedMediaTypes); + this.typePredicate = typePredicate; this.format = format; } @@ -77,27 +96,27 @@ public abstract class AbstractKotlinSerializationHttpMessageConverter 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 diff --git a/spring-web/src/main/java/org/springframework/http/converter/KotlinSerializationBinaryHttpMessageConverter.java b/spring-web/src/main/java/org/springframework/http/converter/KotlinSerializationBinaryHttpMessageConverter.java index 0f3ccc4d8fa..3b564d17232 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/KotlinSerializationBinaryHttpMessageConverter.java +++ b/spring-web/src/main/java/org/springframework/http/converter/KotlinSerializationBinaryHttpMessageConverter.java @@ -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; * Abstract base class for {@link HttpMessageConverter} implementations that * defer to Kotlin {@linkplain BinaryFormat binary serializers}. * - *

As of Spring Framework 7.0, - * open polymorphism - * is supported. + *

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} parameter can be used + * to customize this behavior. * * @author Andreas Ahlenstorf * @author Sebastien Deleuze @@ -47,12 +51,25 @@ public abstract class KotlinSerializationBinaryHttpMessageConverter { /** - * 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 typePredicate, MediaType... supportedMediaTypes) { + super(format, typePredicate, supportedMediaTypes); + } + @Override protected Object readInternal(KSerializer serializer, T format, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException { diff --git a/spring-web/src/main/java/org/springframework/http/converter/KotlinSerializationStringHttpMessageConverter.java b/spring-web/src/main/java/org/springframework/http/converter/KotlinSerializationStringHttpMessageConverter.java index d0bab0b6cbf..ba19761fc0d 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/KotlinSerializationStringHttpMessageConverter.java +++ b/spring-web/src/main/java/org/springframework/http/converter/KotlinSerializationStringHttpMessageConverter.java @@ -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; * Abstract base class for {@link HttpMessageConverter} implementations that * defer to Kotlin {@linkplain StringFormat string serializers}. * - *

As of Spring Framework 7.0, - * open polymorphism - * is supported. + *

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} parameter can be used + * to customize this behavior. * * @author Andreas Ahlenstorf * @author Sebastien Deleuze @@ -51,12 +55,25 @@ public abstract class KotlinSerializationStringHttpMessageConverter typePredicate, MediaType... supportedMediaTypes) { + super(format, typePredicate, supportedMediaTypes); + } + @Override protected Object readInternal(KSerializer serializer, T format, HttpInputMessage inputMessage) diff --git a/spring-web/src/main/java/org/springframework/http/converter/cbor/KotlinSerializationCborHttpMessageConverter.java b/spring-web/src/main/java/org/springframework/http/converter/cbor/KotlinSerializationCborHttpMessageConverter.java index 93bf9e6915d..b401ef1b2af 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/cbor/KotlinSerializationCborHttpMessageConverter.java +++ b/spring-web/src/main/java/org/springframework/http/converter/cbor/KotlinSerializationCborHttpMessageConverter.java @@ -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 * kotlinx.serialization. * It supports {@code application/cbor}. * - *

As of Spring Framework 7.0, - * open polymorphism - * is supported. + *

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. + * + *

Alternative constructors with a {@code Predicate} + * 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 { + + /** + * 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 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 typePredicate) { + super(cbor, typePredicate, MediaType.APPLICATION_CBOR); + } } 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 5535cf1a346..6fab91a7d6d 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 @@ -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 * It supports {@code application/json} and {@code application/*+json} with * various character sets, {@code UTF-8} being the default. * - *

As of Spring Framework 7.0, - * open polymorphism - * is supported. + *

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. + * + *

Alternative constructors with a {@code Predicate} + * 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 */ public class KotlinSerializationJsonHttpMessageConverter extends KotlinSerializationStringHttpMessageConverter { + 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 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 typePredicate) { + super(json, typePredicate, DEFAULT_JSON_MIME_TYPES); } } diff --git a/spring-web/src/main/java/org/springframework/http/converter/protobuf/KotlinSerializationProtobufHttpMessageConverter.java b/spring-web/src/main/java/org/springframework/http/converter/protobuf/KotlinSerializationProtobufHttpMessageConverter.java index 1fa4bb31bbd..d13c26bd236 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/protobuf/KotlinSerializationProtobufHttpMessageConverter.java +++ b/spring-web/src/main/java/org/springframework/http/converter/protobuf/KotlinSerializationProtobufHttpMessageConverter.java @@ -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 * kotlinx.serialization. * It supports {@code application/x-protobuf}, {@code application/octet-stream}, and {@code application/vnd.google.protobuf}. * - *

As of Spring Framework 7.0, - * open polymorphism - * is supported. + *

As of Spring Framework 7.0, by default it only converts types annotated with + * {@link kotlinx.serialization.Serializable @Serializable} at type or generics + * level. + * + *

Alternative constructors with a {@code Predicate} + * 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 { + /** + * 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 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 typePredicate) { + super(protobuf, typePredicate, MediaType.APPLICATION_PROTOBUF, MediaType.APPLICATION_OCTET_STREAM, + new MediaType("application", "vnd.google.protobuf")); + } + } diff --git a/spring-web/src/test/kotlin/org/springframework/http/converter/cbor/KotlinSerializationCborHttpMessageConverterTests.kt b/spring-web/src/test/kotlin/org/springframework/http/converter/cbor/KotlinSerializationCborHttpMessageConverterTests.kt index 14e7a54c26e..8821357eb41 100644 --- a/spring-web/src/test/kotlin/org/springframework/http/converter/cbor/KotlinSerializationCborHttpMessageConverterTests.kt +++ b/spring-web/src/test/kotlin/org/springframework/http/converter/cbor/KotlinSerializationCborHttpMessageConverterTests.kt @@ -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 { 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>(), 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>(), 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>(), MediaType.APPLICATION_CBOR)).isTrue() - assertThat(converter.canRead(resolvableTypeOf>(), MediaType.APPLICATION_CBOR)).isTrue() - assertThat(converter.canRead(resolvableTypeOf>(), MediaType.APPLICATION_CBOR)).isTrue() + assertThat(converter.canRead(resolvableTypeOf>(), MediaType.APPLICATION_CBOR)).isFalse() + assertThat(converter.canRead(resolvableTypeOf>(), MediaType.APPLICATION_CBOR)).isFalse() assertThat(converter.canRead(resolvableTypeOf>(), MediaType.APPLICATION_JSON)).isFalse() - assertThat(converter.canRead(resolvableTypeOf(), MediaType.APPLICATION_CBOR)).isTrue() - assertThat(converter.canRead(resolvableTypeOf>(), MediaType.APPLICATION_CBOR)).isTrue() + assertThat(converter.canRead(resolvableTypeOf(), MediaType.APPLICATION_CBOR)).isFalse() + assertThat(converter.canRead(resolvableTypeOf>(), MediaType.APPLICATION_CBOR)).isFalse() assertThat(converter.canRead(resolvableTypeOf(), MediaType.APPLICATION_CBOR)).isFalse() assertThat(converter.canRead(resolvableTypeOf>(), 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>(), MediaType.APPLICATION_CBOR)).isTrue() + assertThat(converterWithAllTypes.canRead(List::class.java, MediaType.APPLICATION_CBOR)).isTrue() + assertThat(converterWithAllTypes.canRead(resolvableTypeOf>(), MediaType.APPLICATION_CBOR)).isTrue() + assertThat(converterWithAllTypes.canRead(Set::class.java, MediaType.APPLICATION_CBOR)).isTrue() + assertThat(converterWithAllTypes.canRead(resolvableTypeOf>(), MediaType.APPLICATION_CBOR)).isTrue() + + assertThat(converterWithAllTypes.canRead(resolvableTypeOf>(), MediaType.APPLICATION_CBOR)).isTrue() + assertThat(converterWithAllTypes.canRead(resolvableTypeOf>(), MediaType.APPLICATION_CBOR)).isTrue() + assertThat(converterWithAllTypes.canRead(resolvableTypeOf>(), MediaType.APPLICATION_JSON)).isFalse() + + assertThat(converterWithAllTypes.canRead(resolvableTypeOf(), MediaType.APPLICATION_CBOR)).isTrue() + assertThat(converterWithAllTypes.canRead(resolvableTypeOf>(), MediaType.APPLICATION_CBOR)).isTrue() + assertThat(converterWithAllTypes.canRead(resolvableTypeOf(), MediaType.APPLICATION_CBOR)).isFalse() + assertThat(converterWithAllTypes.canRead(resolvableTypeOf>(), 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::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::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::class.java, MediaType.APPLICATION_CBOR)).isTrue() - assertThat(converter.canWrite(resolvableTypeOf>(), List::class.java, MediaType.APPLICATION_CBOR)).isTrue() - assertThat(converter.canWrite(resolvableTypeOf>(), List::class.java, MediaType.APPLICATION_CBOR)).isTrue() + assertThat(converter.canWrite(resolvableTypeOf>(), List::class.java, MediaType.APPLICATION_CBOR)).isFalse() + assertThat(converter.canWrite(resolvableTypeOf>(), List::class.java, MediaType.APPLICATION_CBOR)).isFalse() assertThat(converter.canWrite(resolvableTypeOf>(), List::class.java, MediaType.APPLICATION_JSON)).isFalse() - assertThat(converter.canWrite(resolvableTypeOf(), Ordered::class.java, MediaType.APPLICATION_CBOR)).isTrue() + assertThat(converter.canWrite(resolvableTypeOf(), Ordered::class.java, MediaType.APPLICATION_CBOR)).isFalse() assertThat(converter.canWrite(resolvableTypeOf(), 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::class.java, MediaType.APPLICATION_CBOR)).isTrue() + assertThat(converterWithAllTypes.canWrite(List::class.java, MediaType.APPLICATION_CBOR)).isTrue() + assertThat(converterWithAllTypes.canWrite(resolvableTypeOf>(), List::class.java, MediaType.APPLICATION_CBOR)).isTrue() + assertThat(converterWithAllTypes.canWrite(Set::class.java, MediaType.APPLICATION_CBOR)).isTrue() + assertThat(converterWithAllTypes.canWrite(resolvableTypeOf>(), Set::class.java, MediaType.APPLICATION_CBOR)).isTrue() + + assertThat(converterWithAllTypes.canWrite(resolvableTypeOf>(), List::class.java, MediaType.APPLICATION_CBOR)).isTrue() + assertThat(converterWithAllTypes.canWrite(resolvableTypeOf>(), List::class.java, MediaType.APPLICATION_CBOR)).isTrue() + assertThat(converterWithAllTypes.canWrite(resolvableTypeOf>(), List::class.java, MediaType.APPLICATION_JSON)).isFalse() + + assertThat(converterWithAllTypes.canWrite(resolvableTypeOf(), Ordered::class.java, MediaType.APPLICATION_CBOR)).isTrue() + assertThat(converterWithAllTypes.canWrite(resolvableTypeOf(), 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 diff --git a/spring-web/src/test/kotlin/org/springframework/http/converter/json/KotlinSerializationJsonHttpMessageConverterTests.kt b/spring-web/src/test/kotlin/org/springframework/http/converter/json/KotlinSerializationJsonHttpMessageConverterTests.kt index 5be5c7fb3c8..6d1cde38991 100644 --- a/spring-web/src/test/kotlin/org/springframework/http/converter/json/KotlinSerializationJsonHttpMessageConverterTests.kt +++ b/spring-web/src/test/kotlin/org/springframework/http/converter/json/KotlinSerializationJsonHttpMessageConverterTests.kt @@ -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 { 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>(), 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>(), 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>(), MediaType.APPLICATION_JSON)).isTrue() - assertThat(converter.canRead(resolvableTypeOf>(), MediaType.APPLICATION_JSON)).isTrue() - assertThat(converter.canRead(resolvableTypeOf>(), MediaType.APPLICATION_JSON)).isTrue() + assertThat(converter.canRead(resolvableTypeOf>(), MediaType.APPLICATION_JSON)).isFalse() + assertThat(converter.canRead(resolvableTypeOf>(), MediaType.APPLICATION_JSON)).isFalse() assertThat(converter.canRead(resolvableTypeOf>(), MediaType.APPLICATION_PDF)).isFalse() - assertThat(converter.canRead(resolvableTypeOf(), MediaType.APPLICATION_JSON)).isTrue() - assertThat(converter.canRead(resolvableTypeOf>(), MediaType.APPLICATION_JSON)).isTrue() + assertThat(converter.canRead(resolvableTypeOf(), MediaType.APPLICATION_JSON)).isFalse() + assertThat(converter.canRead(resolvableTypeOf>(), MediaType.APPLICATION_JSON)).isFalse() assertThat(converter.canRead(resolvableTypeOf(), MediaType.APPLICATION_JSON)).isFalse() assertThat(converter.canRead(resolvableTypeOf>(), MediaType.APPLICATION_JSON)).isFalse() @@ -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>(), MediaType.APPLICATION_JSON)).isTrue() + assertThat(converterWithAllTypes.canRead(List::class.java, MediaType.APPLICATION_JSON)).isTrue() + assertThat(converterWithAllTypes.canRead(resolvableTypeOf>(), MediaType.APPLICATION_JSON)).isTrue() + assertThat(converterWithAllTypes.canRead(Set::class.java, MediaType.APPLICATION_JSON)).isTrue() + assertThat(converterWithAllTypes.canRead(resolvableTypeOf>(), MediaType.APPLICATION_JSON)).isTrue() + + assertThat(converterWithAllTypes.canRead(resolvableTypeOf>(), MediaType.APPLICATION_JSON)).isTrue() + assertThat(converterWithAllTypes.canRead(resolvableTypeOf>(), MediaType.APPLICATION_JSON)).isTrue() + assertThat(converterWithAllTypes.canRead(resolvableTypeOf>(), MediaType.APPLICATION_PDF)).isFalse() + + assertThat(converterWithAllTypes.canRead(resolvableTypeOf(), MediaType.APPLICATION_JSON)).isTrue() + assertThat(converterWithAllTypes.canRead(resolvableTypeOf>(), MediaType.APPLICATION_JSON)).isTrue() + assertThat(converterWithAllTypes.canRead(resolvableTypeOf(), MediaType.APPLICATION_JSON)).isFalse() + assertThat(converterWithAllTypes.canRead(resolvableTypeOf>(), 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::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::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::class.java, MediaType.APPLICATION_JSON)).isTrue() - assertThat(converter.canWrite(resolvableTypeOf>(), List::class.java, MediaType.APPLICATION_JSON)).isTrue() - assertThat(converter.canWrite(resolvableTypeOf>(), List::class.java, MediaType.APPLICATION_JSON)).isTrue() + assertThat(converter.canWrite(resolvableTypeOf>(), List::class.java, MediaType.APPLICATION_JSON)).isFalse() + assertThat(converter.canWrite(resolvableTypeOf>(), List::class.java, MediaType.APPLICATION_JSON)).isFalse() assertThat(converter.canWrite(resolvableTypeOf>(), List::class.java, MediaType.APPLICATION_PDF)).isFalse() - assertThat(converter.canWrite(resolvableTypeOf(), Ordered::class.java, MediaType.APPLICATION_JSON)).isTrue() + assertThat(converter.canWrite(resolvableTypeOf(), Ordered::class.java, MediaType.APPLICATION_JSON)).isFalse() assertThat(converter.canWrite(resolvableTypeOf(), 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 { 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::class.java, MediaType.APPLICATION_JSON)).isTrue() + assertThat(converterWithAllTypes.canWrite(List::class.java, MediaType.APPLICATION_JSON)).isTrue() + assertThat(converterWithAllTypes.canWrite(resolvableTypeOf>(), List::class.java, MediaType.APPLICATION_JSON)).isTrue() + assertThat(converterWithAllTypes.canWrite(Set::class.java, MediaType.APPLICATION_JSON)).isTrue() + assertThat(converterWithAllTypes.canWrite(resolvableTypeOf>(), Set::class.java, MediaType.APPLICATION_JSON)).isTrue() + + assertThat(converterWithAllTypes.canWrite(resolvableTypeOf>(), List::class.java, MediaType.APPLICATION_JSON)).isTrue() + assertThat(converterWithAllTypes.canWrite(resolvableTypeOf>(), List::class.java, MediaType.APPLICATION_JSON)).isTrue() + assertThat(converterWithAllTypes.canWrite(resolvableTypeOf>(), List::class.java, MediaType.APPLICATION_PDF)).isFalse() + + assertThat(converterWithAllTypes.canWrite(resolvableTypeOf(), Ordered::class.java, MediaType.APPLICATION_JSON)).isTrue() + assertThat(converterWithAllTypes.canWrite(resolvableTypeOf(), 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 { @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() } diff --git a/spring-web/src/test/kotlin/org/springframework/http/converter/protobuf/KotlinSerializationProtobufHttpMessageConverterTests.kt b/spring-web/src/test/kotlin/org/springframework/http/converter/protobuf/KotlinSerializationProtobufHttpMessageConverterTests.kt index c01eed6e6c2..cf3c0cd424d 100644 --- a/spring-web/src/test/kotlin/org/springframework/http/converter/protobuf/KotlinSerializationProtobufHttpMessageConverterTests.kt +++ b/spring-web/src/test/kotlin/org/springframework/http/converter/protobuf/KotlinSerializationProtobufHttpMessageConverterTests.kt @@ -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 { 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>(), mimeType)).isTrue() - assertThat(converter.canRead(List::class.java, mimeType)).isTrue() + assertThat(converter.canRead(List::class.java, mimeType)).isFalse() assertThat(converter.canRead(resolvableTypeOf>(), mimeType)).isTrue() - assertThat(converter.canRead(Set::class.java, mimeType)).isTrue() + assertThat(converter.canRead(Set::class.java, mimeType)).isFalse() assertThat(converter.canRead(resolvableTypeOf>(), mimeType)).isTrue() - assertThat(converter.canRead(resolvableTypeOf>(), mimeType)).isTrue() - assertThat(converter.canRead(resolvableTypeOf>(),mimeType)).isTrue() + assertThat(converter.canRead(resolvableTypeOf>(), mimeType)).isFalse() + assertThat(converter.canRead(resolvableTypeOf>(),mimeType)).isFalse() - assertThat(converter.canRead(resolvableTypeOf(), mimeType)).isTrue() - assertThat(converter.canRead(resolvableTypeOf>(), mimeType)).isTrue() + assertThat(converter.canRead(resolvableTypeOf(), mimeType)).isFalse() + assertThat(converter.canRead(resolvableTypeOf>(), mimeType)).isFalse() assertThat(converter.canRead(resolvableTypeOf(), mimeType)).isFalse() assertThat(converter.canRead(resolvableTypeOf>(), mimeType)).isFalse() } @@ -86,31 +88,86 @@ class KotlinSerializationProtobufHttpMessageConverterTests { assertThat(converter.canRead(resolvableTypeOf>(), 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>(), mimeType)).isTrue() + assertThat(converterWithAllTypes.canRead(List::class.java, mimeType)).isTrue() + assertThat(converterWithAllTypes.canRead(resolvableTypeOf>(), mimeType)).isTrue() + assertThat(converterWithAllTypes.canRead(Set::class.java, mimeType)).isTrue() + assertThat(converterWithAllTypes.canRead(resolvableTypeOf>(), mimeType)).isTrue() + + assertThat(converterWithAllTypes.canRead(resolvableTypeOf>(), mimeType)).isTrue() + assertThat(converterWithAllTypes.canRead(resolvableTypeOf>(),mimeType)).isTrue() + + assertThat(converterWithAllTypes.canRead(resolvableTypeOf(), mimeType)).isTrue() + assertThat(converterWithAllTypes.canRead(resolvableTypeOf>(), mimeType)).isTrue() + assertThat(converterWithAllTypes.canRead(resolvableTypeOf(), mimeType)).isFalse() + assertThat(converterWithAllTypes.canRead(resolvableTypeOf>(), mimeType)).isFalse() + } + assertThat(converterWithAllTypes.canRead(SerializableBean::class.java, MediaType.APPLICATION_JSON)).isFalse() + assertThat(converterWithAllTypes.canRead(resolvableTypeOf>(), 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::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::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::class.java, mimeType)).isTrue() - assertThat(converter.canWrite(resolvableTypeOf>(), List::class.java, mimeType)).isTrue() - assertThat(converter.canWrite(resolvableTypeOf>(), List::class.java, mimeType)).isTrue() + assertThat(converter.canWrite(resolvableTypeOf>(), List::class.java, mimeType)).isFalse() + assertThat(converter.canWrite(resolvableTypeOf>(), List::class.java, mimeType)).isFalse() - assertThat(converter.canWrite(resolvableTypeOf(), Ordered::class.java, mimeType)).isTrue() - assertThat(converter.canWrite(resolvableTypeOf(), OrderedImpl::class.java, mimeType)).isTrue() + assertThat(converter.canWrite(resolvableTypeOf(), Ordered::class.java, mimeType)).isFalse() + assertThat(converter.canWrite(resolvableTypeOf(), OrderedImpl::class.java, mimeType)).isFalse() } assertThat(converter.canWrite(SerializableBean::class.java, MediaType.APPLICATION_JSON)).isFalse() assertThat(converter.canWrite(resolvableTypeOf>(), 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::class.java, mimeType)).isTrue() + assertThat(converterWithAllTypes.canWrite(List::class.java, mimeType)).isTrue() + assertThat(converterWithAllTypes.canWrite(resolvableTypeOf>(), List::class.java, mimeType)).isTrue() + assertThat(converterWithAllTypes.canWrite(Set::class.java, mimeType)).isTrue() + assertThat(converterWithAllTypes.canWrite(resolvableTypeOf>(), Set::class.java, mimeType)).isTrue() + + assertThat(converterWithAllTypes.canWrite(resolvableTypeOf>(), List::class.java, mimeType)).isTrue() + assertThat(converterWithAllTypes.canWrite(resolvableTypeOf>(), List::class.java, mimeType)).isTrue() + + assertThat(converterWithAllTypes.canWrite(resolvableTypeOf(), Ordered::class.java, mimeType)).isTrue() + assertThat(converterWithAllTypes.canWrite(resolvableTypeOf(), OrderedImpl::class.java, mimeType)).isTrue() + } + + assertThat(converterWithAllTypes.canWrite(SerializableBean::class.java, MediaType.APPLICATION_JSON)).isFalse() + assertThat(converterWithAllTypes.canWrite(resolvableTypeOf>(), List::class.java, MediaType.APPLICATION_JSON)).isFalse() + } + @Test fun readObject() { val serializableBeanBody = ProtoBuf.Default.encodeToByteArray(serializableBean) diff --git a/spring-webmvc/src/test/kotlin/org/springframework/web/servlet/mvc/method/annotation/RequestResponseBodyMethodProcessorKotlinTests.kt b/spring-webmvc/src/test/kotlin/org/springframework/web/servlet/mvc/method/annotation/RequestResponseBodyMethodProcessorKotlinTests.kt index d81e97844ba..3891e9cf41e 100644 --- a/spring-webmvc/src/test/kotlin/org/springframework/web/servlet/mvc/method/annotation/RequestResponseBodyMethodProcessorKotlinTests.kt +++ b/spring-webmvc/src/test/kotlin/org/springframework/web/servlet/mvc/method/annotation/RequestResponseBodyMethodProcessorKotlinTests.kt @@ -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 { 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()!!