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 64e2d43ddb..304a0cfa7d 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-2020 the original author or authors. + * Copyright 2002-2021 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. @@ -17,11 +17,14 @@ package org.springframework.http.codec.json; import java.lang.reflect.Type; +import java.util.HashSet; import java.util.Map; +import java.util.Set; import kotlinx.serialization.KSerializer; import kotlinx.serialization.SerializersKt; import kotlinx.serialization.descriptors.PolymorphicKind; +import kotlinx.serialization.descriptors.SerialDescriptor; import kotlinx.serialization.json.Json; import org.reactivestreams.Publisher; import reactor.core.publisher.Flux; @@ -135,7 +138,7 @@ public class KotlinSerializationJsonDecoder extends AbstractDecoder { KSerializer serializer = serializerCache.get(type); if (serializer == null) { serializer = SerializersKt.serializer(type); - if (serializer.getDescriptor().getKind().equals(PolymorphicKind.OPEN.INSTANCE)) { + if (hasPolymorphism(serializer.getDescriptor(), new HashSet<>())) { throw new UnsupportedOperationException("Open polymorphic serialization is not supported yet"); } serializerCache.put(type, serializer); @@ -143,4 +146,18 @@ public class KotlinSerializationJsonDecoder extends AbstractDecoder { return serializer; } + private boolean hasPolymorphism(SerialDescriptor descriptor, Set alreadyProcessed) { + alreadyProcessed.add(descriptor.getSerialName()); + if (descriptor.getKind().equals(PolymorphicKind.OPEN.INSTANCE)) { + return true; + } + for (int i = 0 ; i < descriptor.getElementsCount() ; i++) { + SerialDescriptor elementDescriptor = descriptor.getElementDescriptor(i); + if (!alreadyProcessed.contains(elementDescriptor.getSerialName()) && hasPolymorphism(elementDescriptor, alreadyProcessed)) { + return true; + } + } + return false; + } + } 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 3c30b2b0e0..8ee097d0ff 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-2020 the original author or authors. + * Copyright 2002-2021 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. @@ -17,12 +17,15 @@ package org.springframework.http.codec.json; import java.lang.reflect.Type; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import kotlinx.serialization.KSerializer; import kotlinx.serialization.SerializersKt; import kotlinx.serialization.descriptors.PolymorphicKind; +import kotlinx.serialization.descriptors.SerialDescriptor; import kotlinx.serialization.json.Json; import org.reactivestreams.Publisher; import reactor.core.publisher.Flux; @@ -123,7 +126,7 @@ public class KotlinSerializationJsonEncoder extends AbstractEncoder { KSerializer serializer = serializerCache.get(type); if (serializer == null) { serializer = SerializersKt.serializer(type); - if (serializer.getDescriptor().getKind().equals(PolymorphicKind.OPEN.INSTANCE)) { + if (hasPolymorphism(serializer.getDescriptor(), new HashSet<>())) { throw new UnsupportedOperationException("Open polymorphic serialization is not supported yet"); } serializerCache.put(type, serializer); @@ -131,4 +134,18 @@ public class KotlinSerializationJsonEncoder extends AbstractEncoder { return serializer; } + private boolean hasPolymorphism(SerialDescriptor descriptor, Set alreadyProcessed) { + alreadyProcessed.add(descriptor.getSerialName()); + if (descriptor.getKind().equals(PolymorphicKind.OPEN.INSTANCE)) { + return true; + } + for (int i = 0 ; i < descriptor.getElementsCount() ; i++) { + SerialDescriptor elementDescriptor = descriptor.getElementDescriptor(i); + if (!alreadyProcessed.contains(elementDescriptor.getSerialName()) && hasPolymorphism(elementDescriptor, alreadyProcessed)) { + return true; + } + } + return false; + } + } 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 6025255e19..9b1f9752bd 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 @@ -20,12 +20,15 @@ import java.io.IOException; import java.lang.reflect.Type; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import java.util.HashSet; import java.util.Map; +import java.util.Set; import kotlinx.serialization.KSerializer; import kotlinx.serialization.SerializationException; import kotlinx.serialization.SerializersKt; import kotlinx.serialization.descriptors.PolymorphicKind; +import kotlinx.serialization.descriptors.SerialDescriptor; import kotlinx.serialization.json.Json; import org.springframework.core.GenericTypeResolver; @@ -185,7 +188,7 @@ public class KotlinSerializationJsonHttpMessageConverter extends AbstractGeneric KSerializer serializer = serializerCache.get(type); if (serializer == null) { serializer = SerializersKt.serializer(type); - if (serializer.getDescriptor().getKind().equals(PolymorphicKind.OPEN.INSTANCE)) { + if (hasPolymorphism(serializer.getDescriptor(), new HashSet<>())) { throw new UnsupportedOperationException("Open polymorphic serialization is not supported yet"); } serializerCache.put(type, serializer); @@ -193,4 +196,18 @@ public class KotlinSerializationJsonHttpMessageConverter extends AbstractGeneric return serializer; } + private boolean hasPolymorphism(SerialDescriptor descriptor, Set alreadyProcessed) { + alreadyProcessed.add(descriptor.getSerialName()); + if (descriptor.getKind().equals(PolymorphicKind.OPEN.INSTANCE)) { + return true; + } + for (int i = 0 ; i < descriptor.getElementsCount() ; i++) { + SerialDescriptor elementDescriptor = descriptor.getElementDescriptor(i); + if (!alreadyProcessed.contains(elementDescriptor.getSerialName()) && hasPolymorphism(elementDescriptor, alreadyProcessed)) { + return true; + } + } + return false; + } + } diff --git a/spring-web/src/test/kotlin/org/springframework/http/codec/json/KotlinSerializationJsonDecoderTests.kt b/spring-web/src/test/kotlin/org/springframework/http/codec/json/KotlinSerializationJsonDecoderTests.kt index d333bd0a86..bd86de61cf 100644 --- a/spring-web/src/test/kotlin/org/springframework/http/codec/json/KotlinSerializationJsonDecoderTests.kt +++ b/spring-web/src/test/kotlin/org/springframework/http/codec/json/KotlinSerializationJsonDecoderTests.kt @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2021 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. @@ -56,6 +56,7 @@ class KotlinSerializationJsonDecoderTests : AbstractDecoderTests>(), List::class.java, MediaType.APPLICATION_PDF)).isFalse() assertThat(converter.canRead(typeTokenOf(), Ordered::class.java, MediaType.APPLICATION_JSON)).isFalse() + assertThat(converter.canRead(typeTokenOf>(), List::class.java, MediaType.APPLICATION_JSON)).isFalse() } @Test @@ -315,7 +316,8 @@ class KotlinSerializationJsonHttpMessageConverterTests { val number: Int, val string: String?, val bool: Boolean, - val fraction: Float + val fraction: Float, + val serializableBean: SerializableBean? = null ) data class NotSerializableBean(val string: String)