Skip to content

Commit f380a94

Browse files
committed
Support properties in kotlinx.serialization converters
This commit adds support for Kotlin properties in Spring WebMVC controllers, supported for reasons explained in spring-projectsgh-31856, with kotlinx.serialization converters. Closes spring-projectsgh-34284
1 parent 62f1a68 commit f380a94

File tree

2 files changed

+36
-22
lines changed

2 files changed

+36
-22
lines changed

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

+16-15
Original file line numberDiff line numberDiff line change
@@ -150,24 +150,25 @@ private KSerializer<Object> serializer(ResolvableType resolvableType) {
150150
Assert.notNull(method, "Method must not be null");
151151
if (KotlinDetector.isKotlinType(method.getDeclaringClass())) {
152152
KFunction<?> function = ReflectJvmMapping.getKotlinFunction(method);
153-
Assert.notNull(function, "Kotlin function must not be null");
154-
KType type = (parameter.getParameterIndex() == -1 ? function.getReturnType() :
155-
KCallables.getValueParameters(function).get(parameter.getParameterIndex()).getType());
156-
KSerializer<Object> serializer = this.kTypeSerializerCache.get(type);
157-
if (serializer == null) {
158-
try {
159-
serializer = SerializersKt.serializerOrNull(this.format.getSerializersModule(), type);
160-
}
161-
catch (IllegalArgumentException ignored) {
162-
}
163-
if (serializer != null) {
164-
if (hasPolymorphism(serializer.getDescriptor(), new HashSet<>())) {
165-
return null;
153+
if (function != null) {
154+
KType type = (parameter.getParameterIndex() == -1 ? function.getReturnType() :
155+
KCallables.getValueParameters(function).get(parameter.getParameterIndex()).getType());
156+
KSerializer<Object> serializer = this.kTypeSerializerCache.get(type);
157+
if (serializer == null) {
158+
try {
159+
serializer = SerializersKt.serializerOrNull(this.format.getSerializersModule(), type);
160+
}
161+
catch (IllegalArgumentException ignored) {
162+
}
163+
if (serializer != null) {
164+
if (hasPolymorphism(serializer.getDescriptor(), new HashSet<>())) {
165+
return null;
166+
}
167+
this.kTypeSerializerCache.put(type, serializer);
166168
}
167-
this.kTypeSerializerCache.put(type, serializer);
168169
}
170+
return serializer;
169171
}
170-
return serializer;
171172
}
172173
}
173174
Type type = resolvableType.getType();

spring-web/src/test/kotlin/org/springframework/http/converter/json/KotlinSerializationJsonHttpMessageConverterTests.kt

+20-7
Original file line numberDiff line numberDiff line change
@@ -16,27 +16,24 @@
1616

1717
package org.springframework.http.converter.json
1818

19-
import java.lang.reflect.ParameterizedType
20-
import java.lang.reflect.Type
21-
import java.nio.charset.StandardCharsets
22-
2319
import kotlinx.serialization.Serializable
2420
import org.assertj.core.api.Assertions.assertThat
2521
import org.assertj.core.api.Assertions.assertThatExceptionOfType
2622
import org.junit.jupiter.api.Test
2723
import org.springframework.core.MethodParameter
28-
import kotlin.reflect.javaType
29-
import kotlin.reflect.typeOf
30-
3124
import org.springframework.core.Ordered
3225
import org.springframework.core.ResolvableType
3326
import org.springframework.http.MediaType
3427
import org.springframework.http.converter.HttpMessageNotReadableException
3528
import org.springframework.http.customJson
3629
import org.springframework.web.testfixture.http.MockHttpInputMessage
3730
import org.springframework.web.testfixture.http.MockHttpOutputMessage
31+
import java.lang.reflect.ParameterizedType
3832
import java.math.BigDecimal
33+
import java.nio.charset.StandardCharsets
34+
import kotlin.reflect.javaType
3935
import kotlin.reflect.jvm.javaMethod
36+
import kotlin.reflect.typeOf
4037

4138
/**
4239
* Tests for the JSON conversion using kotlinx.serialization.
@@ -388,6 +385,19 @@ class KotlinSerializationJsonHttpMessageConverterTests {
388385
assertThat(result).isEqualTo(expectedJson)
389386
}
390387

388+
@Test
389+
fun writeProperty() {
390+
val outputMessage = MockHttpOutputMessage()
391+
val method = this::class.java.getDeclaredMethod("getValue")
392+
val methodParameter = MethodParameter.forExecutable(method, -1)
393+
394+
this.converter.write(value, ResolvableType.forMethodParameter(methodParameter), null, outputMessage, null)
395+
val result = outputMessage.getBodyAsString(StandardCharsets.UTF_8)
396+
397+
assertThat(outputMessage.headers).containsEntry("Content-Type", listOf("application/json"))
398+
assertThat(result).isEqualTo("42")
399+
}
400+
391401

392402
@Serializable
393403
@Suppress("ArrayInDataClass")
@@ -413,4 +423,7 @@ class KotlinSerializationJsonHttpMessageConverterTests {
413423

414424
fun handleMapWithNullable(map: Map<String, String?>) = map
415425

426+
val value: Int
427+
get() = 42
428+
416429
}

0 commit comments

Comments
 (0)