diff --git a/spring-messaging/spring-messaging.gradle b/spring-messaging/spring-messaging.gradle
index c1ed06cb23..2973da3149 100644
--- a/spring-messaging/spring-messaging.gradle
+++ b/spring-messaging/spring-messaging.gradle
@@ -1,6 +1,7 @@
description = "Spring Messaging"
apply plugin: "kotlin"
+apply plugin: "kotlinx-serialization"
dependencies {
compile(project(":spring-beans"))
@@ -17,6 +18,7 @@ dependencies {
optional("javax.xml.bind:jaxb-api")
optional("com.google.protobuf:protobuf-java-util")
optional("org.jetbrains.kotlinx:kotlinx-coroutines-reactor")
+ optional("org.jetbrains.kotlinx:kotlinx-serialization-json")
testCompile(project(":kotlin-coroutines"))
testCompile(testFixtures(project(":spring-core")))
testCompile("javax.inject:javax.inject-tck")
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
new file mode 100644
index 0000000000..213e424edf
--- /dev/null
+++ b/spring-messaging/src/main/java/org/springframework/messaging/converter/KotlinSerializationJsonMessageConverter.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2002-2020 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.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.messaging.converter;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.Writer;
+import java.lang.reflect.Type;
+import java.util.Map;
+
+import kotlinx.serialization.KSerializer;
+import kotlinx.serialization.SerializersKt;
+import kotlinx.serialization.json.Json;
+
+import org.springframework.util.ConcurrentReferenceHashMap;
+import org.springframework.util.FileCopyUtils;
+
+/**
+ * Implementation of {@link MessageConverter} that can read and write JSON
+ * using kotlinx.serialization.
+ *
+ *
This converter can be used to bind {@code @Serializable} Kotlin classes.
+ *
+ * @author Sebastien Deleuze
+ * @since 5.3
+ */
+public class KotlinSerializationJsonMessageConverter extends AbstractJsonMessageConverter {
+
+ private static final Map> serializerCache = new ConcurrentReferenceHashMap<>();
+
+ private final Json json;
+
+
+ /**
+ * Construct a new {@code KotlinSerializationJsonMessageConverter} with default configuration.
+ */
+ public KotlinSerializationJsonMessageConverter() {
+ this(Json.Default);
+ }
+
+ /**
+ * Construct a new {@code KotlinSerializationJsonMessageConverter} with the given delegate.
+ * @param json the Json instance to use
+ */
+ public KotlinSerializationJsonMessageConverter(Json json) {
+ this.json = json;
+ }
+
+ @Override
+ protected Object fromJson(Reader reader, Type resolvedType) {
+ try {
+ return fromJson(FileCopyUtils.copyToString(reader), resolvedType);
+ }
+ catch (IOException ex) {
+ throw new MessageConversionException("Could not read JSON: " + ex.getMessage(), ex);
+ }
+ }
+
+ @Override
+ protected Object fromJson(String payload, Type resolvedType) {
+ return this.json.decodeFromString(serializer(resolvedType), payload);
+ }
+
+ @Override
+ protected void toJson(Object payload, Type resolvedType, Writer writer) {
+ try {
+ writer.write(toJson(payload, resolvedType).toCharArray());
+ }
+ catch (IOException ex) {
+ throw new MessageConversionException("Could not write JSON: " + ex.getMessage(), ex);
+ }
+ }
+
+ @Override
+ protected String toJson(Object payload, Type resolvedType) {
+ return this.json.encodeToString(serializer(resolvedType), payload);
+ }
+
+ /**
+ * 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.
+ * @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
+ */
+ private KSerializer