Add support for JSON streams to Kotlin Serialization

Closes gh-32074
This commit is contained in:
Felipe
2024-01-20 14:36:51 +01:00
committed by Sébastien Deleuze
parent 4d7da0059e
commit 11898daed7
7 changed files with 88 additions and 20 deletions

View File

@@ -16,8 +16,7 @@
package org.springframework.http.codec;
import java.util.List;
import java.util.Map;
import java.util.*;
import kotlinx.serialization.KSerializer;
import kotlinx.serialization.StringFormat;
@@ -95,13 +94,20 @@ public abstract class KotlinSerializationStringDecoder<T extends StringFormat> e
public Flux<Object> decode(Publisher<DataBuffer> inputStream, ResolvableType elementType,
@Nullable MimeType mimeType,
@Nullable Map<String, Object> hints) {
return Flux.error(new UnsupportedOperationException());
return Flux.defer(() -> {
KSerializer<Object> serializer = serializer(elementType);
if (serializer == null) {
return Mono.error(new DecodingException("Could not find KSerializer for " + elementType));
}
return this.stringDecoder
.decode(inputStream, elementType, mimeType, hints)
.map(string -> format().decodeFromString(serializer, string));
});
}
@Override
public Mono<Object> decodeToMono(Publisher<DataBuffer> inputStream, ResolvableType elementType,
@Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
return Mono.defer(() -> {
KSerializer<Object> serializer = serializer(elementType);
if (serializer == null) {

View File

@@ -16,12 +16,13 @@
package org.springframework.http.codec;
import java.util.List;
import java.util.Map;
import java.util.*;
import kotlin.text.Charsets;
import kotlinx.serialization.KSerializer;
import kotlinx.serialization.StringFormat;
import org.reactivestreams.Publisher;
import org.springframework.http.MediaType;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@@ -49,11 +50,17 @@ public abstract class KotlinSerializationStringEncoder<T extends StringFormat> e
// CharSequence encoding needed for now, see https://github.com/Kotlin/kotlinx.serialization/issues/204 for more details
private final CharSequenceEncoder charSequenceEncoder = CharSequenceEncoder.allMimeTypes();
private final Set<MimeType> streamingMediaTypes = new HashSet<>();
protected KotlinSerializationStringEncoder(T format, MimeType... supportedMimeTypes) {
super(format, supportedMimeTypes);
}
public void setStreamingMediaTypes(Collection<MediaType> streamingMediaTypes) {
this.streamingMediaTypes.clear();
this.streamingMediaTypes.addAll(streamingMediaTypes);
}
@Override
public boolean canEncode(ResolvableType elementType, @Nullable MimeType mimeType) {
return canSerialize(elementType, mimeType);
@@ -79,13 +86,17 @@ public abstract class KotlinSerializationStringEncoder<T extends StringFormat> e
.map(value -> encodeValue(value, bufferFactory, elementType, mimeType, hints))
.flux();
}
else {
ResolvableType listType = ResolvableType.forClassWithGenerics(List.class, elementType);
if (mimeType != null && streamingMediaTypes.contains(mimeType)) {
return Flux.from(inputStream)
.collectList()
.map(list -> encodeValue(list, bufferFactory, listType, mimeType, hints))
.flux();
.map(list -> encodeValue(list, bufferFactory, elementType, mimeType, hints).write("\n", Charsets.UTF_8));
}
ResolvableType listType = ResolvableType.forClassWithGenerics(List.class, elementType);
return Flux.from(inputStream)
.collectList()
.map(list -> encodeValue(list, bufferFactory, listType, mimeType, hints))
.flux();
}

View File

@@ -46,7 +46,8 @@ public class KotlinSerializationJsonDecoder extends KotlinSerializationStringDec
}
public KotlinSerializationJsonDecoder(Json json) {
super(json, MediaType.APPLICATION_JSON, new MediaType("application", "*+json"));
super(json, MediaType.APPLICATION_JSON, new MediaType("application", "*+json"),
MediaType.APPLICATION_NDJSON);
}
}

View File

@@ -21,6 +21,8 @@ import kotlinx.serialization.json.Json;
import org.springframework.http.MediaType;
import org.springframework.http.codec.KotlinSerializationStringEncoder;
import java.util.List;
/**
* Encode from an {@code Object} stream to a byte stream of JSON objects using
* <a href="https://github.com/Kotlin/kotlinx.serialization">kotlinx.serialization</a>.
@@ -42,7 +44,9 @@ public class KotlinSerializationJsonEncoder extends KotlinSerializationStringEnc
}
public KotlinSerializationJsonEncoder(Json json) {
super(json, MediaType.APPLICATION_JSON, new MediaType("application", "*+json"));
super(json, MediaType.APPLICATION_JSON, new MediaType("application", "*+json"),
MediaType.APPLICATION_NDJSON);
setStreamingMediaTypes(List.of(MediaType.APPLICATION_NDJSON));
}
}