parent
11898daed7
commit
4f16297e45
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -16,7 +16,8 @@
|
||||||
|
|
||||||
package org.springframework.http.codec;
|
package org.springframework.http.codec;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import kotlinx.serialization.KSerializer;
|
import kotlinx.serialization.KSerializer;
|
||||||
import kotlinx.serialization.StringFormat;
|
import kotlinx.serialization.StringFormat;
|
||||||
|
|
@ -92,8 +93,7 @@ public abstract class KotlinSerializationStringDecoder<T extends StringFormat> e
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Flux<Object> decode(Publisher<DataBuffer> inputStream, ResolvableType elementType,
|
public Flux<Object> decode(Publisher<DataBuffer> inputStream, ResolvableType elementType,
|
||||||
@Nullable MimeType mimeType,
|
@Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
|
||||||
@Nullable Map<String, Object> hints) {
|
|
||||||
return Flux.defer(() -> {
|
return Flux.defer(() -> {
|
||||||
KSerializer<Object> serializer = serializer(elementType);
|
KSerializer<Object> serializer = serializer(elementType);
|
||||||
if (serializer == null) {
|
if (serializer == null) {
|
||||||
|
|
@ -107,7 +107,7 @@ public abstract class KotlinSerializationStringDecoder<T extends StringFormat> e
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<Object> decodeToMono(Publisher<DataBuffer> inputStream, ResolvableType elementType,
|
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(() -> {
|
return Mono.defer(() -> {
|
||||||
KSerializer<Object> serializer = serializer(elementType);
|
KSerializer<Object> serializer = serializer(elementType);
|
||||||
if (serializer == null) {
|
if (serializer == null) {
|
||||||
|
|
|
||||||
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -16,13 +16,16 @@
|
||||||
|
|
||||||
package org.springframework.http.codec;
|
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 kotlin.text.Charsets;
|
||||||
import kotlinx.serialization.KSerializer;
|
import kotlinx.serialization.KSerializer;
|
||||||
import kotlinx.serialization.StringFormat;
|
import kotlinx.serialization.StringFormat;
|
||||||
import org.reactivestreams.Publisher;
|
import org.reactivestreams.Publisher;
|
||||||
import org.springframework.http.MediaType;
|
|
||||||
import reactor.core.publisher.Flux;
|
import reactor.core.publisher.Flux;
|
||||||
import reactor.core.publisher.Mono;
|
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.codec.EncodingException;
|
||||||
import org.springframework.core.io.buffer.DataBuffer;
|
import org.springframework.core.io.buffer.DataBuffer;
|
||||||
import org.springframework.core.io.buffer.DataBufferFactory;
|
import org.springframework.core.io.buffer.DataBufferFactory;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.util.MimeType;
|
import org.springframework.util.MimeType;
|
||||||
|
|
||||||
|
|
@ -87,9 +91,10 @@ public abstract class KotlinSerializationStringEncoder<T extends StringFormat> e
|
||||||
.flux();
|
.flux();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mimeType != null && streamingMediaTypes.contains(mimeType)) {
|
if (mimeType != null && this.streamingMediaTypes.contains(mimeType)) {
|
||||||
return Flux.from(inputStream)
|
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);
|
ResolvableType listType = ResolvableType.forClassWithGenerics(List.class, elementType);
|
||||||
|
|
|
||||||
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -16,13 +16,13 @@
|
||||||
|
|
||||||
package org.springframework.http.codec.json;
|
package org.springframework.http.codec.json;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import kotlinx.serialization.json.Json;
|
import kotlinx.serialization.json.Json;
|
||||||
|
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.codec.KotlinSerializationStringEncoder;
|
import org.springframework.http.codec.KotlinSerializationStringEncoder;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encode from an {@code Object} stream to a byte stream of JSON objects using
|
* 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>.
|
* <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,
|
* <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>
|
* <a href="https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/polymorphism.md#open-polymorphism">open polymorphic serialization</a>
|
||||||
* is not supported.
|
* 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.
|
* various character sets, {@code UTF-8} being the default.
|
||||||
*
|
*
|
||||||
* @author Sebastien Deleuze
|
* @author Sebastien Deleuze
|
||||||
|
|
|
||||||
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
|
||||||
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -69,23 +69,44 @@ class KotlinSerializationJsonDecoderTests : AbstractDecoderTests<KotlinSerializa
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
override fun decode() {
|
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(
|
val input = Flux.concat(
|
||||||
stringBuffer("{\"bar\":\"b1\",\"foo\":\"f1\"}\n"),
|
stringBuffer("{\"bar\":\"b1\",\"foo\":\"f1\"}\n"),
|
||||||
stringBuffer("{\"bar\":\"b2\",\"foo\":\"f2\"}\n")
|
stringBuffer("{\"bar\":\"b2\",\"foo\":\"f2\"}\n")
|
||||||
)
|
)
|
||||||
|
|
||||||
testDecodeAll(input, ResolvableType.forClass(Pojo::class.java), { step: FirstStep<Any> ->
|
testDecodeAll(input, ResolvableType.forClass(Pojo::class.java), {
|
||||||
step
|
it.expectNext(Pojo("f1", "b1"))
|
||||||
.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"))
|
.expectNext(Pojo("f2", "b2"))
|
||||||
.expectComplete()
|
.expectComplete()
|
||||||
.verify()
|
.verify()
|
||||||
|
|
@ -100,11 +121,10 @@ class KotlinSerializationJsonDecoderTests : AbstractDecoderTests<KotlinSerializa
|
||||||
|
|
||||||
val elementType = ResolvableType.forClassWithGenerics(List::class.java, Pojo::class.java)
|
val elementType = ResolvableType.forClassWithGenerics(List::class.java, Pojo::class.java)
|
||||||
|
|
||||||
testDecodeToMonoAll(input, elementType, { step: FirstStep<Any> ->
|
testDecodeToMonoAll(input, elementType, {
|
||||||
step
|
it.expectNext(listOf(Pojo("f1", "b1"), Pojo("f2", "b2")))
|
||||||
.expectNext(listOf(Pojo("f1", "b1"), Pojo("f2", "b2")))
|
.expectComplete()
|
||||||
.expectComplete()
|
.verify()
|
||||||
.verify()
|
|
||||||
}, null, null)
|
}, null, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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("foofoo", "barbar"),
|
||||||
Pojo("foofoofoo", "barbarbar")
|
Pojo("foofoofoo", "barbarbar")
|
||||||
)
|
)
|
||||||
testEncode(input, Pojo::class.java, { step: FirstStep<DataBuffer?> -> step
|
testEncode(input, Pojo::class.java) {
|
||||||
.consumeNextWith(expectString("[" +
|
it.consumeNextWith(expectString("[" +
|
||||||
"{\"foo\":\"foo\",\"bar\":\"bar\"}," +
|
"{\"foo\":\"foo\",\"bar\":\"bar\"}," +
|
||||||
"{\"foo\":\"foofoo\",\"bar\":\"barbar\"}," +
|
"{\"foo\":\"foofoo\",\"bar\":\"barbar\"}," +
|
||||||
"{\"foo\":\"foofoofoo\",\"bar\":\"barbarbar\"}]")
|
"{\"foo\":\"foofoofoo\",\"bar\":\"barbarbar\"}]")
|
||||||
.andThen { dataBuffer: DataBuffer? -> DataBufferUtils.release(dataBuffer) })
|
.andThen { dataBuffer -> DataBufferUtils.release(dataBuffer) })
|
||||||
.verifyComplete()
|
.verifyComplete()
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun encodeStream() {
|
fun encodeStream() {
|
||||||
val input = Flux.just(
|
val input = Flux.just(
|
||||||
Pojo("foo", "bar"),
|
Pojo("foo", "bar"),
|
||||||
Pojo("foofoo", "barbar"),
|
Pojo("foofoo", "barbar"),
|
||||||
Pojo("foofoofoo", "barbarbar")
|
Pojo("foofoofoo", "barbarbar")
|
||||||
)
|
)
|
||||||
testEncodeAll(
|
testEncodeAll(
|
||||||
input,
|
input,
|
||||||
ResolvableType.forClass(Pojo::class.java),
|
ResolvableType.forClass(Pojo::class.java),
|
||||||
MediaType.APPLICATION_NDJSON,
|
MediaType.APPLICATION_NDJSON,
|
||||||
null
|
null
|
||||||
) { step: FirstStep<DataBuffer?> ->
|
) {
|
||||||
step
|
it.consumeNextWith(expectString("{\"foo\":\"foo\",\"bar\":\"bar\"}\n"))
|
||||||
.consumeNextWith(expectString("{\"foo\":\"foo\",\"bar\":\"bar\"}\n"))
|
|
||||||
.consumeNextWith(expectString("{\"foo\":\"foofoo\",\"bar\":\"barbar\"}\n"))
|
.consumeNextWith(expectString("{\"foo\":\"foofoo\",\"bar\":\"barbar\"}\n"))
|
||||||
.consumeNextWith(expectString("{\"foo\":\"foofoofoo\",\"bar\":\"barbarbar\"}\n"))
|
.consumeNextWith(expectString("{\"foo\":\"foofoofoo\",\"bar\":\"barbarbar\"}\n"))
|
||||||
.verifyComplete()
|
.verifyComplete()
|
||||||
|
|
@ -102,11 +102,11 @@ class KotlinSerializationJsonEncoderTests : AbstractEncoderTests<KotlinSerializa
|
||||||
@Test
|
@Test
|
||||||
fun encodeMono() {
|
fun encodeMono() {
|
||||||
val input = Mono.just(Pojo("foo", "bar"))
|
val input = Mono.just(Pojo("foo", "bar"))
|
||||||
testEncode(input, Pojo::class.java, { step: FirstStep<DataBuffer?> -> step
|
testEncode(input, Pojo::class.java) {
|
||||||
.consumeNextWith(expectString("{\"foo\":\"foo\",\"bar\":\"bar\"}")
|
it.consumeNextWith(expectString("{\"foo\":\"foo\",\"bar\":\"bar\"}")
|
||||||
.andThen { dataBuffer: DataBuffer? -> DataBufferUtils.release(dataBuffer) })
|
.andThen { dataBuffer: DataBuffer? -> DataBufferUtils.release(dataBuffer) })
|
||||||
.verifyComplete()
|
.verifyComplete()
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue