Skip to content

Commit 6bdb9bb

Browse files
committed
Support open polymorphism with Kotlin Serialization
This commit introduces open polymorphism support with Kotlin Serialization in HTTP converters and codecs as a follow-up of gh-34410 which considers Kotlin Serialization as a Jackson/Gson/Jsonb equivalent (it is not anymore configured before Jackson). Closes gh-34433
1 parent d910091 commit 6bdb9bb

26 files changed

+327
-159
lines changed

spring-web/src/main/java/org/springframework/http/codec/KotlinSerializationBinaryDecoder.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2024 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -37,6 +37,10 @@
3737
* Abstract base class for {@link Decoder} implementations that defer to Kotlin
3838
* {@linkplain BinaryFormat binary serializers}.
3939
*
40+
* <p>As of Spring Framework 7.0,
41+
* <a href="https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/polymorphism.md#open-polymorphism">open polymorphism</a>
42+
* is supported.
43+
*
4044
* @author Sebastien Deleuze
4145
* @author Iain Henderson
4246
* @author Arjen Poutsma

spring-web/src/main/java/org/springframework/http/codec/KotlinSerializationBinaryEncoder.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -38,6 +38,10 @@
3838
* Abstract base class for {@link Encoder} implementations that defer to Kotlin
3939
* {@linkplain BinaryFormat binary serializers}.
4040
*
41+
* <p>As of Spring Framework 7.0,
42+
* <a href="https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/polymorphism.md#open-polymorphism">open polymorphism</a>
43+
* is supported.
44+
*
4145
* @author Sebastien Deleuze
4246
* @author Iain Henderson
4347
* @author Arjen Poutsma

spring-web/src/main/java/org/springframework/http/codec/KotlinSerializationStringDecoder.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2024 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -38,6 +38,10 @@
3838
* Abstract base class for {@link Decoder} implementations that defer to Kotlin
3939
* {@linkplain StringFormat string serializers}.
4040
*
41+
* <p>As of Spring Framework 7.0,
42+
* <a href="https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/polymorphism.md#open-polymorphism">open polymorphism</a>
43+
* is supported.
44+
*
4145
* @author Sebastien Deleuze
4246
* @author Iain Henderson
4347
* @author Arjen Poutsma

spring-web/src/main/java/org/springframework/http/codec/KotlinSerializationStringEncoder.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2024 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -43,6 +43,10 @@
4343
* Abstract base class for {@link Encoder} implementations that defer to Kotlin
4444
* {@linkplain StringFormat string serializers}.
4545
*
46+
* <p>As of Spring Framework 7.0,
47+
* <a href="https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/polymorphism.md#open-polymorphism">open polymorphism</a>
48+
* is supported.
49+
*
4650
* @author Sebastien Deleuze
4751
* @author Iain Henderson
4852
* @author Arjen Poutsma

spring-web/src/main/java/org/springframework/http/codec/KotlinSerializationSupport.java

+5-26
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,10 +19,8 @@
1919
import java.lang.reflect.Method;
2020
import java.lang.reflect.Type;
2121
import java.util.Arrays;
22-
import java.util.HashSet;
2322
import java.util.List;
2423
import java.util.Map;
25-
import java.util.Set;
2624

2725
import kotlin.reflect.KFunction;
2826
import kotlin.reflect.KType;
@@ -31,8 +29,6 @@
3129
import kotlinx.serialization.KSerializer;
3230
import kotlinx.serialization.SerialFormat;
3331
import kotlinx.serialization.SerializersKt;
34-
import kotlinx.serialization.descriptors.PolymorphicKind;
35-
import kotlinx.serialization.descriptors.SerialDescriptor;
3632
import org.jspecify.annotations.Nullable;
3733

3834
import org.springframework.core.KotlinDetector;
@@ -46,6 +42,10 @@
4642
* Base class providing support methods for encoding and decoding with Kotlin
4743
* serialization.
4844
*
45+
* <p>As of Spring Framework 7.0,
46+
* <a href="https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/polymorphism.md#open-polymorphism">open polymorphism</a>
47+
* is supported.
48+
*
4949
* @author Sebastien Deleuze
5050
* @author Iain Henderson
5151
* @author Arjen Poutsma
@@ -143,9 +143,6 @@ private boolean supports(@Nullable MimeType mimeType) {
143143
catch (IllegalArgumentException ignored) {
144144
}
145145
if (serializer != null) {
146-
if (hasPolymorphism(serializer.getDescriptor(), new HashSet<>())) {
147-
return null;
148-
}
149146
this.kTypeSerializerCache.put(type, serializer);
150147
}
151148
}
@@ -162,27 +159,9 @@ private boolean supports(@Nullable MimeType mimeType) {
162159
catch (IllegalArgumentException ignored) {
163160
}
164161
if (serializer != null) {
165-
if (hasPolymorphism(serializer.getDescriptor(), new HashSet<>())) {
166-
return null;
167-
}
168162
this.typeSerializerCache.put(type, serializer);
169163
}
170164
}
171165
return serializer;
172166
}
173-
174-
private static boolean hasPolymorphism(SerialDescriptor descriptor, Set<String> alreadyProcessed) {
175-
alreadyProcessed.add(descriptor.getSerialName());
176-
if (descriptor.getKind().equals(PolymorphicKind.OPEN.INSTANCE)) {
177-
return true;
178-
}
179-
for (int i = 0 ; i < descriptor.getElementsCount() ; i++) {
180-
SerialDescriptor elementDescriptor = descriptor.getElementDescriptor(i);
181-
if (!alreadyProcessed.contains(elementDescriptor.getSerialName()) && hasPolymorphism(elementDescriptor, alreadyProcessed)) {
182-
return true;
183-
}
184-
}
185-
return false;
186-
}
187-
188167
}

spring-web/src/main/java/org/springframework/http/codec/cbor/KotlinSerializationCborDecoder.java

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -24,12 +24,12 @@
2424
/**
2525
* Decode a byte stream into CBOR and convert to Objects with
2626
* <a href="https://github.com/Kotlin/kotlinx.serialization">kotlinx.serialization</a>.
27-
*
28-
* <p>This decoder can be used to bind {@code @Serializable} Kotlin classes,
29-
* <a href="https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/polymorphism.md#open-polymorphism">open polymorphic serialization</a>
30-
* is not supported.
3127
* It supports {@code application/cbor}.
3228
*
29+
* <p>As of Spring Framework 7.0,
30+
* <a href="https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/polymorphism.md#open-polymorphism">open polymorphism</a>
31+
* is supported.
32+
*
3333
* <p>Decoding streams is not supported yet, see
3434
* <a href="https://github.com/Kotlin/kotlinx.serialization/issues/1073">kotlinx.serialization/issues/1073</a>
3535
* related issue.

spring-web/src/main/java/org/springframework/http/codec/cbor/KotlinSerializationCborEncoder.java

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -24,12 +24,12 @@
2424
/**
2525
* Encode from an {@code Object} stream to a byte stream of CBOR objects using
2626
* <a href="https://github.com/Kotlin/kotlinx.serialization">kotlinx.serialization</a>.
27-
*
28-
* <p>This encoder can be used to bind {@code @Serializable} Kotlin classes,
29-
* <a href="https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/polymorphism.md#open-polymorphism">open polymorphic serialization</a>
30-
* is not supported.
3127
* It supports {@code application/cbor}.
3228
*
29+
* <p>As of Spring Framework 7.0,
30+
* <a href="https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/polymorphism.md#open-polymorphism">open polymorphism</a>
31+
* is supported.
32+
*
3333
* @author Iain Henderson
3434
* @since 6.0
3535
*/

spring-web/src/main/java/org/springframework/http/codec/json/KotlinSerializationJsonDecoder.java

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2024 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -24,13 +24,13 @@
2424
/**
2525
* Decode a byte stream into JSON and convert to Object's with
2626
* <a href="https://github.com/Kotlin/kotlinx.serialization">kotlinx.serialization</a>.
27-
*
28-
* <p>This decoder can be used to bind {@code @Serializable} Kotlin classes,
29-
* <a href="https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/polymorphism.md#open-polymorphism">open polymorphic serialization</a>
30-
* is not supported.
3127
* It supports {@code application/json} and {@code application/*+json} with
3228
* various character sets, {@code UTF-8} being the default.
3329
*
30+
* <p>As of Spring Framework 7.0,
31+
* <a href="https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/polymorphism.md#open-polymorphism">open polymorphism</a>
32+
* is supported.
33+
*
3434
* <p>Decoding streams is not supported yet, see
3535
* <a href="https://github.com/Kotlin/kotlinx.serialization/issues/1073">kotlinx.serialization/issues/1073</a>
3636
* related issue.

spring-web/src/main/java/org/springframework/http/codec/json/KotlinSerializationJsonEncoder.java

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2024 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -35,13 +35,13 @@
3535
/**
3636
* Encode from an {@code Object} stream to a byte stream of JSON objects using
3737
* <a href="https://github.com/Kotlin/kotlinx.serialization">kotlinx.serialization</a>.
38-
*
39-
* <p>This encoder can be used to bind {@code @Serializable} Kotlin classes,
40-
* <a href="https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/polymorphism.md#open-polymorphism">open polymorphic serialization</a>
41-
* is not supported.
4238
* It supports {@code application/json}, {@code application/x-ndjson} and {@code application/*+json} with
4339
* various character sets, {@code UTF-8} being the default.
4440
*
41+
* <p>As of Spring Framework 7.0,
42+
* <a href="https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/polymorphism.md#open-polymorphism">open polymorphism</a>
43+
* is supported.
44+
*
4545
* @author Sebastien Deleuze
4646
* @author Iain Henderson
4747
* @since 5.3

spring-web/src/main/java/org/springframework/http/codec/protobuf/KotlinSerializationProtobufDecoder.java

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -23,12 +23,12 @@
2323
/**
2424
* Decode a byte stream into a protocol Buffer and convert to Objects with
2525
* <a href="https://github.com/Kotlin/kotlinx.serialization">kotlinx.serialization</a>.
26-
*
27-
* <p>This decoder can be used to bind {@code @Serializable} Kotlin classes,
28-
* <a href="https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/polymorphism.md#open-polymorphism">open polymorphic serialization</a>
29-
* is not supported.
3026
* It supports {@code application/x-protobuf}, {@code application/octet-stream}, and {@code application/vnd.google.protobuf}.
3127
*
28+
* <p>As of Spring Framework 7.0,
29+
* <a href="https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/polymorphism.md#open-polymorphism">open polymorphism</a>
30+
* is supported.
31+
*
3232
* <p>Decoding streams is not supported yet, see
3333
* <a href="https://github.com/Kotlin/kotlinx.serialization/issues/1073">kotlinx.serialization/issues/1073</a>
3434
* related issue.

spring-web/src/main/java/org/springframework/http/codec/protobuf/KotlinSerializationProtobufEncoder.java

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -23,12 +23,12 @@
2323
/**
2424
* Decode a byte stream into a Protocol Buffer and convert to Objects with
2525
* <a href="https://github.com/Kotlin/kotlinx.serialization">kotlinx.serialization</a>.
26-
*
27-
* <p>This decoder can be used to bind {@code @Serializable} Kotlin classes,
28-
* <a href="https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/polymorphism.md#open-polymorphism">open polymorphic serialization</a>
29-
* is not supported.
3026
* It supports {@code application/x-protobuf}, {@code application/octet-stream}, and {@code application/vnd.google.protobuf}.
3127
*
28+
* <p>As of Spring Framework 7.0,
29+
* <a href="https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/polymorphism.md#open-polymorphism">open polymorphism</a>
30+
* is supported.
31+
*
3232
* <p>Decoding streams is not supported yet, see
3333
* <a href="https://github.com/Kotlin/kotlinx.serialization/issues/1073">kotlinx.serialization/issues/1073</a>
3434
* related issue.

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

+5-25
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2024 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,9 +19,7 @@
1919
import java.io.IOException;
2020
import java.lang.reflect.Method;
2121
import java.lang.reflect.Type;
22-
import java.util.HashSet;
2322
import java.util.Map;
24-
import java.util.Set;
2523

2624
import kotlin.reflect.KFunction;
2725
import kotlin.reflect.KType;
@@ -30,8 +28,6 @@
3028
import kotlinx.serialization.KSerializer;
3129
import kotlinx.serialization.SerialFormat;
3230
import kotlinx.serialization.SerializersKt;
33-
import kotlinx.serialization.descriptors.PolymorphicKind;
34-
import kotlinx.serialization.descriptors.SerialDescriptor;
3531
import org.jspecify.annotations.Nullable;
3632

3733
import org.springframework.core.KotlinDetector;
@@ -48,6 +44,10 @@
4844
* Abstract base class for {@link HttpMessageConverter} implementations that
4945
* use Kotlin serialization.
5046
*
47+
* <p>As of Spring Framework 7.0,
48+
* <a href="https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/polymorphism.md#open-polymorphism">open polymorphism</a>
49+
* is supported.
50+
*
5151
* @author Andreas Ahlenstorf
5252
* @author Sebastien Deleuze
5353
* @author Juergen Hoeller
@@ -160,9 +160,6 @@ protected abstract void writeInternal(Object object, KSerializer<Object> seriali
160160
catch (IllegalArgumentException ignored) {
161161
}
162162
if (serializer != null) {
163-
if (hasPolymorphism(serializer.getDescriptor(), new HashSet<>())) {
164-
return null;
165-
}
166163
this.kTypeSerializerCache.put(type, serializer);
167164
}
168165
}
@@ -179,29 +176,12 @@ protected abstract void writeInternal(Object object, KSerializer<Object> seriali
179176
catch (IllegalArgumentException ignored) {
180177
}
181178
if (serializer != null) {
182-
if (hasPolymorphism(serializer.getDescriptor(), new HashSet<>())) {
183-
return null;
184-
}
185179
this.typeSerializerCache.put(type, serializer);
186180
}
187181
}
188182
return serializer;
189183
}
190184

191-
private boolean hasPolymorphism(SerialDescriptor descriptor, Set<String> alreadyProcessed) {
192-
alreadyProcessed.add(descriptor.getSerialName());
193-
if (descriptor.getKind().equals(PolymorphicKind.OPEN.INSTANCE)) {
194-
return true;
195-
}
196-
for (int i = 0 ; i < descriptor.getElementsCount() ; i++) {
197-
SerialDescriptor elementDescriptor = descriptor.getElementDescriptor(i);
198-
if (!alreadyProcessed.contains(elementDescriptor.getSerialName()) && hasPolymorphism(elementDescriptor, alreadyProcessed)) {
199-
return true;
200-
}
201-
}
202-
return false;
203-
}
204-
205185
@Override
206186
protected boolean supportsRepeatableWrites(Object object) {
207187
return true;

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

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -31,6 +31,10 @@
3131
* Abstract base class for {@link HttpMessageConverter} implementations that
3232
* defer to Kotlin {@linkplain BinaryFormat binary serializers}.
3333
*
34+
* <p>As of Spring Framework 7.0,
35+
* <a href="https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/polymorphism.md#open-polymorphism">open polymorphism</a>
36+
* is supported.
37+
*
3438
* @author Andreas Ahlenstorf
3539
* @author Sebastien Deleuze
3640
* @author Juergen Hoeller

0 commit comments

Comments
 (0)