From f6db2cc35fd9d3f172aa9bd338aad701ecec00fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Deleuze?= Date: Sun, 4 Sep 2022 16:05:25 +0200 Subject: [PATCH] Use serializerOrNull in Kotlin Serialization support Closes gh-29068 --- ...tlinSerializationJsonMessageConverter.java | 3 +- .../json/KotlinSerializationJsonDecoder.java | 24 ++++----- .../json/KotlinSerializationJsonEncoder.java | 26 ++++----- ...SerializationJsonHttpMessageConverter.java | 54 +++++++------------ 4 files changed, 42 insertions(+), 65 deletions(-) diff --git a/spring-messaging/src/main/java/org/springframework/messaging/converter/KotlinSerializationJsonMessageConverter.java b/spring-messaging/src/main/java/org/springframework/messaging/converter/KotlinSerializationJsonMessageConverter.java index 475a1f5000..44e4aa830f 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/converter/KotlinSerializationJsonMessageConverter.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/converter/KotlinSerializationJsonMessageConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -94,7 +94,6 @@ public class KotlinSerializationJsonMessageConverter extends AbstractJsonMessage * Tries to find a serializer that can marshall or unmarshall instances of the given type * using kotlinx.serialization. If no serializer can be found, an exception is thrown. *

Resolved serializers are cached and cached results are returned on successive calls. - * TODO Avoid relying on throwing exception when https://github.com/Kotlin/kotlinx.serialization/pull/1164 is fixed * @param type the type to find a serializer for * @return a resolved serializer for the given type * @throws RuntimeException if no serializer supporting the given type can be found diff --git a/spring-web/src/main/java/org/springframework/http/codec/json/KotlinSerializationJsonDecoder.java b/spring-web/src/main/java/org/springframework/http/codec/json/KotlinSerializationJsonDecoder.java index 304a0cfa7d..6ecec5a76f 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/json/KotlinSerializationJsonDecoder.java +++ b/spring-web/src/main/java/org/springframework/http/codec/json/KotlinSerializationJsonDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -100,13 +100,9 @@ public class KotlinSerializationJsonDecoder extends AbstractDecoder { @Override public boolean canDecode(ResolvableType elementType, @Nullable MimeType mimeType) { - try { - serializer(elementType.getType()); - return (super.canDecode(elementType, mimeType) && !CharSequence.class.isAssignableFrom(elementType.toClass())); - } - catch (Exception ex) { - return false; - } + return (serializer(elementType.getType()) != null && + super.canDecode(elementType, mimeType) && + !CharSequence.class.isAssignableFrom(elementType.toClass())); } @Override @@ -129,17 +125,17 @@ public class KotlinSerializationJsonDecoder extends AbstractDecoder { * Tries to find a serializer that can marshall or unmarshall instances of the given type * using kotlinx.serialization. If no serializer can be found, an exception is thrown. *

Resolved serializers are cached and cached results are returned on successive calls. - * TODO Avoid relying on throwing exception when https://github.com/Kotlin/kotlinx.serialization/pull/1164 is fixed * @param type the type to find a serializer for - * @return a resolved serializer for the given type - * @throws RuntimeException if no serializer supporting the given type can be found + * @return a resolved serializer for the given type or {@code null} if no serializer + * supporting the given type can be found */ + @Nullable private KSerializer serializer(Type type) { KSerializer serializer = serializerCache.get(type); if (serializer == null) { - serializer = SerializersKt.serializer(type); - if (hasPolymorphism(serializer.getDescriptor(), new HashSet<>())) { - throw new UnsupportedOperationException("Open polymorphic serialization is not supported yet"); + serializer = SerializersKt.serializerOrNull(type); + if (serializer == null || hasPolymorphism(serializer.getDescriptor(), new HashSet<>())) { + return null; } serializerCache.put(type, serializer); } diff --git a/spring-web/src/main/java/org/springframework/http/codec/json/KotlinSerializationJsonEncoder.java b/spring-web/src/main/java/org/springframework/http/codec/json/KotlinSerializationJsonEncoder.java index 8ee097d0ff..667ff4c5a2 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/json/KotlinSerializationJsonEncoder.java +++ b/spring-web/src/main/java/org/springframework/http/codec/json/KotlinSerializationJsonEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -77,14 +77,10 @@ public class KotlinSerializationJsonEncoder extends AbstractEncoder { @Override public boolean canEncode(ResolvableType elementType, @Nullable MimeType mimeType) { - try { - serializer(elementType.getType()); - return (super.canEncode(elementType, mimeType) && !String.class.isAssignableFrom(elementType.toClass()) && - !ServerSentEvent.class.isAssignableFrom(elementType.toClass())); - } - catch (Exception ex) { - return false; - } + return (serializer(elementType.getType()) != null && + super.canEncode(elementType, mimeType) && + !String.class.isAssignableFrom(elementType.toClass()) && + !ServerSentEvent.class.isAssignableFrom(elementType.toClass())); } @Override @@ -117,17 +113,17 @@ public class KotlinSerializationJsonEncoder extends AbstractEncoder { * Tries to find a serializer that can marshall or unmarshall instances of the given type * using kotlinx.serialization. If no serializer can be found, an exception is thrown. *

Resolved serializers are cached and cached results are returned on successive calls. - * TODO Avoid relying on throwing exception when https://github.com/Kotlin/kotlinx.serialization/pull/1164 is fixed * @param type the type to find a serializer for - * @return a resolved serializer for the given type - * @throws RuntimeException if no serializer supporting the given type can be found + * @return a resolved serializer for the given type or {@code null} if no serializer + * supporting the given type can be found */ + @Nullable private KSerializer serializer(Type type) { KSerializer serializer = serializerCache.get(type); if (serializer == null) { - serializer = SerializersKt.serializer(type); - if (hasPolymorphism(serializer.getDescriptor(), new HashSet<>())) { - throw new UnsupportedOperationException("Open polymorphic serialization is not supported yet"); + serializer = SerializersKt.serializerOrNull(type); + if (serializer == null || hasPolymorphism(serializer.getDescriptor(), new HashSet<>())) { + return null; } serializerCache.put(type, serializer); } 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 9b1f9752bd..a5fc349716 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -39,6 +39,7 @@ import org.springframework.http.converter.AbstractGenericHttpMessageConverter; import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.http.converter.HttpMessageNotWritableException; import org.springframework.lang.Nullable; +import org.springframework.util.Assert; import org.springframework.util.ConcurrentReferenceHashMap; import org.springframework.util.StreamUtils; @@ -85,49 +86,33 @@ public class KotlinSerializationJsonHttpMessageConverter extends AbstractGeneric @Override protected boolean supports(Class clazz) { - try { - serializer(clazz); - return true; - } - catch (Exception ex) { - return false; - } + return serializer(clazz) != null; } @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; - } + return serializer(GenericTypeResolver.resolveType(type, contextClass)) != null && canRead(mediaType); } @Override public boolean canWrite(@Nullable Type type, Class clazz, @Nullable MediaType mediaType) { - try { - serializer(type != null ? GenericTypeResolver.resolveType(type, clazz) : clazz); - return canWrite(mediaType); - } - catch (Exception ex) { - return false; - } + return serializer(type != null ? GenericTypeResolver.resolveType(type, clazz) : clazz) != null && canWrite(mediaType); } @Override public final Object read(Type type, @Nullable Class contextClass, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException { - - return decode(serializer(GenericTypeResolver.resolveType(type, contextClass)), inputMessage); + KSerializer serializer = serializer(GenericTypeResolver.resolveType(type, contextClass)); + Assert.notNull(serializer, "The serializer should not be null"); + return decode(serializer, inputMessage); } @Override protected final Object readInternal(Class clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException { - - return decode(serializer(clazz), inputMessage); + KSerializer serializer = serializer(clazz); + Assert.notNull(serializer, "The serializer should not be null"); + return decode(serializer, inputMessage); } private Object decode(KSerializer serializer, HttpInputMessage inputMessage) @@ -147,8 +132,9 @@ public class KotlinSerializationJsonHttpMessageConverter extends AbstractGeneric @Override protected final void writeInternal(Object object, @Nullable Type type, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { - - encode(object, serializer(type != null ? type : object.getClass()), outputMessage); + KSerializer serializer = serializer(type != null ? type : object.getClass()); + Assert.notNull(serializer, "The serializer should not be null"); + encode(object, serializer, outputMessage); } private void encode(Object object, KSerializer serializer, HttpOutputMessage outputMessage) @@ -179,17 +165,17 @@ 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. *

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 + * @return a resolved serializer for the given type or {@code null} if no serializer + * supporting the given type can be found */ + @Nullable private KSerializer serializer(Type type) { KSerializer serializer = serializerCache.get(type); if (serializer == null) { - serializer = SerializersKt.serializer(type); - if (hasPolymorphism(serializer.getDescriptor(), new HashSet<>())) { - throw new UnsupportedOperationException("Open polymorphic serialization is not supported yet"); + serializer = SerializersKt.serializerOrNull(type); + if (serializer == null || hasPolymorphism(serializer.getDescriptor(), new HashSet<>())) { + return null; } serializerCache.put(type, serializer); }