Polishing

See gh-32074
This commit is contained in:
Sébastien Deleuze 2024-01-24 15:18:28 +01:00
parent 11898daed7
commit 4f16297e45
6 changed files with 76 additions and 51 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2024 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.
@ -16,7 +16,8 @@
package org.springframework.http.codec;
import java.util.*;
import java.util.List;
import java.util.Map;
import kotlinx.serialization.KSerializer;
import kotlinx.serialization.StringFormat;
@ -92,8 +93,7 @@ public abstract class KotlinSerializationStringDecoder<T extends StringFormat> e
@Override
public Flux<Object> decode(Publisher<DataBuffer> inputStream, ResolvableType elementType,
@Nullable MimeType mimeType,
@Nullable Map<String, Object> hints) {
@Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
return Flux.defer(() -> {
KSerializer<Object> serializer = serializer(elementType);
if (serializer == null) {
@ -107,7 +107,7 @@ public abstract class KotlinSerializationStringDecoder<T extends StringFormat> e
@Override
public Mono<Object> decodeToMono(Publisher<DataBuffer> inputStream, ResolvableType elementType,
@Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
@Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
return Mono.defer(() -> {
KSerializer<Object> serializer = serializer(elementType);
if (serializer == null) {

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2024 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.
@ -16,13 +16,16 @@
package org.springframework.http.codec;
import java.util.*;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
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;
@ -32,6 +35,7 @@ import org.springframework.core.codec.Encoder;
import org.springframework.core.codec.EncodingException;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.MediaType;
import org.springframework.lang.Nullable;
import org.springframework.util.MimeType;
@ -87,9 +91,10 @@ public abstract class KotlinSerializationStringEncoder<T extends StringFormat> e
.flux();
}
if (mimeType != null && streamingMediaTypes.contains(mimeType)) {
if (mimeType != null && this.streamingMediaTypes.contains(mimeType)) {
return Flux.from(inputStream)
.map(list -> encodeValue(list, bufferFactory, elementType, mimeType, hints).write("\n", Charsets.UTF_8));
.map(list -> encodeValue(list, bufferFactory, elementType, mimeType, hints)
.write("\n", Charsets.UTF_8));
}
ResolvableType listType = ResolvableType.forClassWithGenerics(List.class, elementType);

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2024 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.
@ -16,13 +16,13 @@
package org.springframework.http.codec.json;
import java.util.List;
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>.
@ -30,7 +30,7 @@ import java.util.List;
* <p>This encoder can be used to bind {@code @Serializable} Kotlin classes,
* <a href="https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/polymorphism.md#open-polymorphism">open polymorphic serialization</a>
* is not supported.
* It supports {@code application/json} and {@code application/*+json} with
* It supports {@code application/json}, {@code application/x-ndjson} and {@code application/*+json} with
* various character sets, {@code UTF-8} being the default.
*
* @author Sebastien Deleuze

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 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.
@ -69,23 +69,44 @@ class KotlinSerializationJsonDecoderTests : AbstractDecoderTests<KotlinSerializa
@Test
override fun decode() {
val output = decoder.decode(Mono.empty(), ResolvableType.forClass(Pojo::class.java), null, emptyMap())
StepVerifier
.create(output)
.expectError(UnsupportedOperationException::class.java)
}
@Test
fun decodeStream() {
val input = Flux.concat(
stringBuffer("{\"bar\":\"b1\",\"foo\":\"f1\"}\n"),
stringBuffer("{\"bar\":\"b2\",\"foo\":\"f2\"}\n")
)
testDecodeAll(input, ResolvableType.forClass(Pojo::class.java), { step: FirstStep<Any> ->
step
.expectNext(Pojo("f1", "b1"))
testDecodeAll(input, ResolvableType.forClass(Pojo::class.java), {
it.expectNext(Pojo("f1", "b1"))
.expectNext(Pojo("f2", "b2"))
.expectComplete()
.verify()
}, null, null)
}
@Test
fun decodeStreamWithSingleBuffer() {
val input = Flux.concat(
stringBuffer("{\"bar\":\"b1\",\"foo\":\"f1\"}\n{\"bar\":\"b2\",\"foo\":\"f2\"}\n"),
)
testDecodeAll(input, ResolvableType.forClass(Pojo::class.java), {
it.expectNext(Pojo("f1", "b1"))
.expectNext(Pojo("f2", "b2"))
.expectComplete()
.verify()
}, null, null)
}
@Test
fun decodeStreamWithMultipleBuffersPerElement() {
val input = Flux.concat(
stringBuffer("{\"bar\":\"b1\","),
stringBuffer("\"foo\":\"f1\"}\n"),
stringBuffer("{\""),
stringBuffer("bar\":\"b2\",\"foo\":\"f2\"}\n")
)
testDecodeAll(input, ResolvableType.forClass(Pojo::class.java), {
it.expectNext(Pojo("f1", "b1"))
.expectNext(Pojo("f2", "b2"))
.expectComplete()
.verify()
@ -100,11 +121,10 @@ class KotlinSerializationJsonDecoderTests : AbstractDecoderTests<KotlinSerializa
val elementType = ResolvableType.forClassWithGenerics(List::class.java, Pojo::class.java)
testDecodeToMonoAll(input, elementType, { step: FirstStep<Any> ->
step
.expectNext(listOf(Pojo("f1", "b1"), Pojo("f2", "b2")))
.expectComplete()
.verify()
testDecodeToMonoAll(input, elementType, {
it.expectNext(listOf(Pojo("f1", "b1"), Pojo("f2", "b2")))
.expectComplete()
.verify()
}, null, null)
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 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.
@ -69,30 +69,30 @@ class KotlinSerializationJsonEncoderTests : AbstractEncoderTests<KotlinSerializa
Pojo("foofoo", "barbar"),
Pojo("foofoofoo", "barbarbar")
)
testEncode(input, Pojo::class.java, { step: FirstStep<DataBuffer?> -> step
.consumeNextWith(expectString("[" +
"{\"foo\":\"foo\",\"bar\":\"bar\"}," +
"{\"foo\":\"foofoo\",\"bar\":\"barbar\"}," +
"{\"foo\":\"foofoofoo\",\"bar\":\"barbarbar\"}]")
.andThen { dataBuffer: DataBuffer? -> DataBufferUtils.release(dataBuffer) })
.verifyComplete()
})
testEncode(input, Pojo::class.java) {
it.consumeNextWith(expectString("[" +
"{\"foo\":\"foo\",\"bar\":\"bar\"}," +
"{\"foo\":\"foofoo\",\"bar\":\"barbar\"}," +
"{\"foo\":\"foofoofoo\",\"bar\":\"barbarbar\"}]")
.andThen { dataBuffer -> DataBufferUtils.release(dataBuffer) })
.verifyComplete()
}
}
@Test
fun encodeStream() {
val input = Flux.just(
Pojo("foo", "bar"),
Pojo("foofoo", "barbar"),
Pojo("foofoofoo", "barbarbar")
Pojo("foo", "bar"),
Pojo("foofoo", "barbar"),
Pojo("foofoofoo", "barbarbar")
)
testEncodeAll(
input,
ResolvableType.forClass(Pojo::class.java),
MediaType.APPLICATION_NDJSON,
null
) { step: FirstStep<DataBuffer?> ->
step
.consumeNextWith(expectString("{\"foo\":\"foo\",\"bar\":\"bar\"}\n"))
) {
it.consumeNextWith(expectString("{\"foo\":\"foo\",\"bar\":\"bar\"}\n"))
.consumeNextWith(expectString("{\"foo\":\"foofoo\",\"bar\":\"barbar\"}\n"))
.consumeNextWith(expectString("{\"foo\":\"foofoofoo\",\"bar\":\"barbarbar\"}\n"))
.verifyComplete()
@ -102,11 +102,11 @@ class KotlinSerializationJsonEncoderTests : AbstractEncoderTests<KotlinSerializa
@Test
fun encodeMono() {
val input = Mono.just(Pojo("foo", "bar"))
testEncode(input, Pojo::class.java, { step: FirstStep<DataBuffer?> -> step
.consumeNextWith(expectString("{\"foo\":\"foo\",\"bar\":\"bar\"}")
testEncode(input, Pojo::class.java) {
it.consumeNextWith(expectString("{\"foo\":\"foo\",\"bar\":\"bar\"}")
.andThen { dataBuffer: DataBuffer? -> DataBufferUtils.release(dataBuffer) })
.verifyComplete()
})
}
}
@Test