Refine kotlinx.serialization support
This commit introduces the following changes: - Converters/codecs are now used based on generic type info. - On WebMvc and WebFlux, kotlinx.serialization is enabled along to Jackson because it only serializes Kotlin @Serializable classes which is not enough for error or actuator endpoints in Boot as described on spring-projects/spring-boot#24238. TODO: leverage Kotlin/kotlinx.serialization#1164 when fixed. Closes gh-26147
This commit is contained in:
@@ -69,10 +69,38 @@ public class KotlinSerializationJsonDecoder extends AbstractDecoder<Object> {
|
||||
this.json = json;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure a limit on the number of bytes that can be buffered whenever
|
||||
* the input stream needs to be aggregated. This can be a result of
|
||||
* decoding to a single {@code DataBuffer},
|
||||
* {@link java.nio.ByteBuffer ByteBuffer}, {@code byte[]},
|
||||
* {@link org.springframework.core.io.Resource Resource}, {@code String}, etc.
|
||||
* It can also occur when splitting the input stream, e.g. delimited text,
|
||||
* in which case the limit applies to data buffered between delimiters.
|
||||
* <p>By default this is set to 256K.
|
||||
* @param byteCount the max number of bytes to buffer, or -1 for unlimited
|
||||
*/
|
||||
public void setMaxInMemorySize(int byteCount) {
|
||||
this.stringDecoder.setMaxInMemorySize(byteCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link #setMaxInMemorySize configured} byte count limit.
|
||||
*/
|
||||
public int getMaxInMemorySize() {
|
||||
return this.stringDecoder.getMaxInMemorySize();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean canDecode(ResolvableType elementType, @Nullable MimeType mimeType) {
|
||||
return (super.canDecode(elementType, mimeType) && !CharSequence.class.isAssignableFrom(elementType.toClass()));
|
||||
try {
|
||||
serializer(elementType.getType());
|
||||
return (super.canDecode(elementType, mimeType) && !CharSequence.class.isAssignableFrom(elementType.toClass()));
|
||||
}
|
||||
catch (Exception ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -95,6 +123,7 @@ public class KotlinSerializationJsonDecoder extends AbstractDecoder<Object> {
|
||||
* Tries to find a serializer that can marshall or unmarshall instances of the given type
|
||||
* using kotlinx.serialization. If no serializer can be found, an exception is thrown.
|
||||
* <p>Resolved serializers are cached and cached results are returned on successive calls.
|
||||
* TODO Avoid relying on throwing exception when https://github.com/Kotlin/kotlinx.serialization/pull/1164 is fixed
|
||||
* @param type the type to find a serializer for
|
||||
* @return a resolved serializer for the given type
|
||||
* @throws RuntimeException if no serializer supporting the given type can be found
|
||||
|
||||
@@ -71,8 +71,14 @@ public class KotlinSerializationJsonEncoder extends AbstractEncoder<Object> {
|
||||
|
||||
@Override
|
||||
public boolean canEncode(ResolvableType elementType, @Nullable MimeType mimeType) {
|
||||
return (super.canEncode(elementType, mimeType) && !String.class.isAssignableFrom(elementType.toClass()) &&
|
||||
!ServerSentEvent.class.isAssignableFrom(elementType.toClass()));
|
||||
try {
|
||||
serializer(elementType.getType());
|
||||
return (super.canEncode(elementType, mimeType) && !String.class.isAssignableFrom(elementType.toClass()) &&
|
||||
!ServerSentEvent.class.isAssignableFrom(elementType.toClass()));
|
||||
}
|
||||
catch (Exception ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -105,6 +111,7 @@ public class KotlinSerializationJsonEncoder extends AbstractEncoder<Object> {
|
||||
* Tries to find a serializer that can marshall or unmarshall instances of the given type
|
||||
* using kotlinx.serialization. If no serializer can be found, an exception is thrown.
|
||||
* <p>Resolved serializers are cached and cached results are returned on successive calls.
|
||||
* TODO Avoid relying on throwing exception when https://github.com/Kotlin/kotlinx.serialization/pull/1164 is fixed
|
||||
* @param type the type to find a serializer for
|
||||
* @return a resolved serializer for the given type
|
||||
* @throws RuntimeException if no serializer supporting the given type can be found
|
||||
|
||||
@@ -312,6 +312,11 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure
|
||||
((ProtobufDecoder) codec).setMaxMessageSize(size);
|
||||
}
|
||||
}
|
||||
if (kotlinSerializationJsonPresent) {
|
||||
if (codec instanceof KotlinSerializationJsonDecoder) {
|
||||
((KotlinSerializationJsonDecoder) codec).setMaxInMemorySize(size);
|
||||
}
|
||||
}
|
||||
if (jackson2Present) {
|
||||
if (codec instanceof AbstractJackson2Decoder) {
|
||||
((AbstractJackson2Decoder) codec).setMaxInMemorySize(size);
|
||||
@@ -385,12 +390,12 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<HttpMessageReader<?>> readers = new ArrayList<>();
|
||||
if (kotlinSerializationJsonPresent) {
|
||||
addCodec(readers, new DecoderHttpMessageReader<>(getKotlinSerializationJsonDecoder()));
|
||||
}
|
||||
if (jackson2Present) {
|
||||
addCodec(readers, new DecoderHttpMessageReader<>(getJackson2JsonDecoder()));
|
||||
}
|
||||
else if (kotlinSerializationJsonPresent) {
|
||||
addCodec(readers, new DecoderHttpMessageReader<>(getKotlinSerializationJsonDecoder()));
|
||||
}
|
||||
if (jackson2SmilePresent) {
|
||||
addCodec(readers, new DecoderHttpMessageReader<>(this.jackson2SmileDecoder != null ?
|
||||
(Jackson2SmileDecoder) this.jackson2SmileDecoder : new Jackson2SmileDecoder()));
|
||||
@@ -484,12 +489,12 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure
|
||||
*/
|
||||
final List<HttpMessageWriter<?>> getBaseObjectWriters() {
|
||||
List<HttpMessageWriter<?>> writers = new ArrayList<>();
|
||||
if (kotlinSerializationJsonPresent) {
|
||||
writers.add(new EncoderHttpMessageWriter<>(getKotlinSerializationJsonEncoder()));
|
||||
}
|
||||
if (jackson2Present) {
|
||||
writers.add(new EncoderHttpMessageWriter<>(getJackson2JsonEncoder()));
|
||||
}
|
||||
else if (kotlinSerializationJsonPresent) {
|
||||
writers.add(new EncoderHttpMessageWriter<>(getKotlinSerializationJsonEncoder()));
|
||||
}
|
||||
if (jackson2SmilePresent) {
|
||||
writers.add(new EncoderHttpMessageWriter<>(this.jackson2SmileEncoder != null ?
|
||||
(Jackson2SmileEncoder) this.jackson2SmileEncoder : new Jackson2SmileEncoder()));
|
||||
|
||||
@@ -88,6 +88,28 @@ public class KotlinSerializationJsonHttpMessageConverter extends AbstractGeneric
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canRead(Type type, @Nullable Class<?> contextClass, @Nullable MediaType mediaType) {
|
||||
try {
|
||||
serializer(GenericTypeResolver.resolveType(type, contextClass));
|
||||
return canRead(mediaType);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canWrite(@Nullable Type type, @Nullable Class<?> clazz, @Nullable MediaType mediaType) {
|
||||
try {
|
||||
serializer(GenericTypeResolver.resolveType(type, clazz));
|
||||
return canWrite(mediaType);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Object read(Type type, @Nullable Class<?> contextClass, HttpInputMessage inputMessage)
|
||||
throws IOException, HttpMessageNotReadableException {
|
||||
@@ -151,6 +173,7 @@ public class KotlinSerializationJsonHttpMessageConverter extends AbstractGeneric
|
||||
* Tries to find a serializer that can marshall or unmarshall instances of the given type
|
||||
* using kotlinx.serialization. If no serializer can be found, an exception is thrown.
|
||||
* <p>Resolved serializers are cached and cached results are returned on successive calls.
|
||||
* TODO Avoid relying on throwing exception when https://github.com/Kotlin/kotlinx.serialization/pull/1164 is fixed
|
||||
* @param type the type to find a serializer for
|
||||
* @return a resolved serializer for the given type
|
||||
* @throws RuntimeException if no serializer supporting the given type can be found
|
||||
|
||||
Reference in New Issue
Block a user