Support CBOR and Protobuf with Kotlin Serialization
This commit introduces support for CBOR and Protobuf using Kotlin serialization. Support comes in the form of Encoder/Decoder as well as HttpMessageConverters. Seperate abstract base classes supply support for binary and string (de)serialization. The exising JSON codecs and message converters have been migrated to use the new base classes. Closes gh-27628
This commit is contained in:
committed by
Arjen Poutsma
parent
b6c2e8de23
commit
b8243e6f84
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -107,7 +107,7 @@ public class CancelWithoutDemandCodecTests {
|
||||
|
||||
Flux<DataBuffer> flux = encoder.encode(Mono.just(msg),
|
||||
this.bufferFactory, ResolvableType.forClass(Msg.class),
|
||||
new MimeType("application", "x-protobuf"), Collections.emptyMap());
|
||||
MediaType.APPLICATION_PROTOBUF, Collections.emptyMap());
|
||||
|
||||
BaseSubscriber<DataBuffer> subscriber = new ZeroDemandSubscriber();
|
||||
flux.subscribe(subscriber); // Assume sync execution (e.g. encoding with Flux.just)..
|
||||
|
||||
@@ -33,7 +33,6 @@ import org.springframework.core.testfixture.codec.AbstractDecoderTests;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.protobuf.Msg;
|
||||
import org.springframework.protobuf.SecondMsg;
|
||||
import org.springframework.util.MimeType;
|
||||
|
||||
import static java.util.Collections.emptyMap;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -48,8 +47,6 @@ import static org.springframework.core.io.buffer.DataBufferUtils.release;
|
||||
*/
|
||||
public class ProtobufDecoderTests extends AbstractDecoderTests<ProtobufDecoder> {
|
||||
|
||||
private final static MimeType PROTOBUF_MIME_TYPE = new MimeType("application", "x-protobuf");
|
||||
|
||||
private final SecondMsg secondMsg = SecondMsg.newBuilder().setBlah(123).build();
|
||||
|
||||
private final Msg testMsg1 = Msg.newBuilder().setFoo("Foo").setBlah(secondMsg).build();
|
||||
@@ -72,10 +69,10 @@ public class ProtobufDecoderTests extends AbstractDecoderTests<ProtobufDecoder>
|
||||
@Override
|
||||
public void canDecode() {
|
||||
assertThat(this.decoder.canDecode(forClass(Msg.class), null)).isTrue();
|
||||
assertThat(this.decoder.canDecode(forClass(Msg.class), PROTOBUF_MIME_TYPE)).isTrue();
|
||||
assertThat(this.decoder.canDecode(forClass(Msg.class), MediaType.APPLICATION_PROTOBUF)).isTrue();
|
||||
assertThat(this.decoder.canDecode(forClass(Msg.class), MediaType.APPLICATION_OCTET_STREAM)).isTrue();
|
||||
assertThat(this.decoder.canDecode(forClass(Msg.class), MediaType.APPLICATION_JSON)).isFalse();
|
||||
assertThat(this.decoder.canDecode(forClass(Object.class), PROTOBUF_MIME_TYPE)).isFalse();
|
||||
assertThat(this.decoder.canDecode(forClass(Object.class), MediaType.APPLICATION_PROTOBUF)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -55,6 +55,8 @@ import org.springframework.http.codec.HttpMessageWriter;
|
||||
import org.springframework.http.codec.ResourceHttpMessageReader;
|
||||
import org.springframework.http.codec.ResourceHttpMessageWriter;
|
||||
import org.springframework.http.codec.ServerSentEventHttpMessageReader;
|
||||
import org.springframework.http.codec.cbor.KotlinSerializationCborDecoder;
|
||||
import org.springframework.http.codec.cbor.KotlinSerializationCborEncoder;
|
||||
import org.springframework.http.codec.json.Jackson2CodecSupport;
|
||||
import org.springframework.http.codec.json.Jackson2JsonDecoder;
|
||||
import org.springframework.http.codec.json.Jackson2JsonEncoder;
|
||||
@@ -64,6 +66,8 @@ import org.springframework.http.codec.json.KotlinSerializationJsonDecoder;
|
||||
import org.springframework.http.codec.json.KotlinSerializationJsonEncoder;
|
||||
import org.springframework.http.codec.multipart.MultipartHttpMessageWriter;
|
||||
import org.springframework.http.codec.multipart.PartEventHttpMessageWriter;
|
||||
import org.springframework.http.codec.protobuf.KotlinSerializationProtobufDecoder;
|
||||
import org.springframework.http.codec.protobuf.KotlinSerializationProtobufEncoder;
|
||||
import org.springframework.http.codec.protobuf.ProtobufDecoder;
|
||||
import org.springframework.http.codec.protobuf.ProtobufHttpMessageWriter;
|
||||
import org.springframework.http.codec.xml.Jaxb2XmlDecoder;
|
||||
@@ -88,7 +92,7 @@ public class ClientCodecConfigurerTests {
|
||||
@Test
|
||||
public void defaultReaders() {
|
||||
List<HttpMessageReader<?>> readers = this.configurer.getReaders();
|
||||
assertThat(readers.size()).isEqualTo(15);
|
||||
assertThat(readers.size()).isEqualTo(17);
|
||||
assertThat(getNextDecoder(readers).getClass()).isEqualTo(ByteArrayDecoder.class);
|
||||
assertThat(getNextDecoder(readers).getClass()).isEqualTo(ByteBufferDecoder.class);
|
||||
assertThat(getNextDecoder(readers).getClass()).isEqualTo(DataBufferDecoder.class);
|
||||
@@ -99,7 +103,9 @@ public class ClientCodecConfigurerTests {
|
||||
assertThat(getNextDecoder(readers).getClass()).isEqualTo(ProtobufDecoder.class);
|
||||
// SPR-16804
|
||||
assertThat(readers.get(this.index.getAndIncrement()).getClass()).isEqualTo(FormHttpMessageReader.class);
|
||||
assertThat(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationCborDecoder.class);
|
||||
assertThat(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationJsonDecoder.class);
|
||||
assertThat(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationProtobufDecoder.class);
|
||||
assertThat(getNextDecoder(readers).getClass()).isEqualTo(Jackson2JsonDecoder.class);
|
||||
assertThat(getNextDecoder(readers).getClass()).isEqualTo(Jackson2SmileDecoder.class);
|
||||
assertThat(getNextDecoder(readers).getClass()).isEqualTo(Jaxb2XmlDecoder.class);
|
||||
@@ -110,7 +116,7 @@ public class ClientCodecConfigurerTests {
|
||||
@Test
|
||||
public void defaultWriters() {
|
||||
List<HttpMessageWriter<?>> writers = this.configurer.getWriters();
|
||||
assertThat(writers.size()).isEqualTo(15);
|
||||
assertThat(writers.size()).isEqualTo(17);
|
||||
assertThat(getNextEncoder(writers).getClass()).isEqualTo(ByteArrayEncoder.class);
|
||||
assertThat(getNextEncoder(writers).getClass()).isEqualTo(ByteBufferEncoder.class);
|
||||
assertThat(getNextEncoder(writers).getClass()).isEqualTo(DataBufferEncoder.class);
|
||||
@@ -121,7 +127,9 @@ public class ClientCodecConfigurerTests {
|
||||
assertThat(writers.get(index.getAndIncrement()).getClass()).isEqualTo(ProtobufHttpMessageWriter.class);
|
||||
assertThat(writers.get(this.index.getAndIncrement()).getClass()).isEqualTo(MultipartHttpMessageWriter.class);
|
||||
assertThat(writers.get(this.index.getAndIncrement()).getClass()).isEqualTo(PartEventHttpMessageWriter.class);
|
||||
assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationCborEncoder.class);
|
||||
assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationJsonEncoder.class);
|
||||
assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationProtobufEncoder.class);
|
||||
assertThat(getNextEncoder(writers).getClass()).isEqualTo(Jackson2JsonEncoder.class);
|
||||
assertThat(getNextEncoder(writers).getClass()).isEqualTo(Jackson2SmileEncoder.class);
|
||||
assertThat(getNextEncoder(writers).getClass()).isEqualTo(Jaxb2XmlEncoder.class);
|
||||
@@ -176,7 +184,7 @@ public class ClientCodecConfigurerTests {
|
||||
int size = 99;
|
||||
this.configurer.defaultCodecs().maxInMemorySize(size);
|
||||
List<HttpMessageReader<?>> readers = this.configurer.getReaders();
|
||||
assertThat(readers.size()).isEqualTo(15);
|
||||
assertThat(readers.size()).isEqualTo(17);
|
||||
assertThat(((ByteArrayDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size);
|
||||
assertThat(((ByteBufferDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size);
|
||||
assertThat(((DataBufferDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size);
|
||||
@@ -187,7 +195,9 @@ public class ClientCodecConfigurerTests {
|
||||
assertThat(((ProtobufDecoder) getNextDecoder(readers)).getMaxMessageSize()).isEqualTo(size);
|
||||
assertThat(((FormHttpMessageReader) nextReader(readers)).getMaxInMemorySize()).isEqualTo(size);
|
||||
|
||||
assertThat(((KotlinSerializationCborDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size);
|
||||
assertThat(((KotlinSerializationJsonDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size);
|
||||
assertThat(((KotlinSerializationProtobufDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size);
|
||||
assertThat(((Jackson2JsonDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size);
|
||||
assertThat(((Jackson2SmileDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size);
|
||||
assertThat(((Jaxb2XmlDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size);
|
||||
@@ -235,7 +245,7 @@ public class ClientCodecConfigurerTests {
|
||||
writers = findCodec(this.configurer.getWriters(), MultipartHttpMessageWriter.class).getPartWriters();
|
||||
|
||||
assertThat(sseDecoder).isNotSameAs(jackson2Decoder);
|
||||
assertThat(writers).hasSize(13);
|
||||
assertThat(writers).hasSize(15);
|
||||
}
|
||||
|
||||
@Test // gh-24194
|
||||
@@ -245,7 +255,7 @@ public class ClientCodecConfigurerTests {
|
||||
List<HttpMessageWriter<?>> writers =
|
||||
findCodec(clone.getWriters(), MultipartHttpMessageWriter.class).getPartWriters();
|
||||
|
||||
assertThat(writers).hasSize(13);
|
||||
assertThat(writers).hasSize(15);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -259,7 +269,7 @@ public class ClientCodecConfigurerTests {
|
||||
List<HttpMessageWriter<?>> writers =
|
||||
findCodec(clone.getWriters(), MultipartHttpMessageWriter.class).getPartWriters();
|
||||
|
||||
assertThat(writers).hasSize(13);
|
||||
assertThat(writers).hasSize(15);
|
||||
}
|
||||
|
||||
private Decoder<?> getNextDecoder(List<HttpMessageReader<?>> readers) {
|
||||
|
||||
@@ -50,12 +50,16 @@ import org.springframework.http.codec.ResourceHttpMessageReader;
|
||||
import org.springframework.http.codec.ResourceHttpMessageWriter;
|
||||
import org.springframework.http.codec.ServerSentEventHttpMessageReader;
|
||||
import org.springframework.http.codec.ServerSentEventHttpMessageWriter;
|
||||
import org.springframework.http.codec.cbor.KotlinSerializationCborDecoder;
|
||||
import org.springframework.http.codec.cbor.KotlinSerializationCborEncoder;
|
||||
import org.springframework.http.codec.json.Jackson2JsonDecoder;
|
||||
import org.springframework.http.codec.json.Jackson2JsonEncoder;
|
||||
import org.springframework.http.codec.json.Jackson2SmileDecoder;
|
||||
import org.springframework.http.codec.json.Jackson2SmileEncoder;
|
||||
import org.springframework.http.codec.json.KotlinSerializationJsonDecoder;
|
||||
import org.springframework.http.codec.json.KotlinSerializationJsonEncoder;
|
||||
import org.springframework.http.codec.protobuf.KotlinSerializationProtobufDecoder;
|
||||
import org.springframework.http.codec.protobuf.KotlinSerializationProtobufEncoder;
|
||||
import org.springframework.http.codec.protobuf.ProtobufDecoder;
|
||||
import org.springframework.http.codec.protobuf.ProtobufEncoder;
|
||||
import org.springframework.http.codec.protobuf.ProtobufHttpMessageWriter;
|
||||
@@ -83,7 +87,7 @@ class CodecConfigurerTests {
|
||||
@Test
|
||||
void defaultReaders() {
|
||||
List<HttpMessageReader<?>> readers = this.configurer.getReaders();
|
||||
assertThat(readers.size()).isEqualTo(14);
|
||||
assertThat(readers.size()).isEqualTo(16);
|
||||
assertThat(getNextDecoder(readers).getClass()).isEqualTo(ByteArrayDecoder.class);
|
||||
assertThat(getNextDecoder(readers).getClass()).isEqualTo(ByteBufferDecoder.class);
|
||||
assertThat(getNextDecoder(readers).getClass()).isEqualTo(DataBufferDecoder.class);
|
||||
@@ -93,7 +97,9 @@ class CodecConfigurerTests {
|
||||
assertStringDecoder(getNextDecoder(readers), true);
|
||||
assertThat(getNextDecoder(readers).getClass()).isEqualTo(ProtobufDecoder.class);
|
||||
assertThat(readers.get(this.index.getAndIncrement()).getClass()).isEqualTo(FormHttpMessageReader.class);
|
||||
assertThat(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationCborDecoder.class);
|
||||
assertThat(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationJsonDecoder.class);
|
||||
assertThat(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationProtobufDecoder.class);
|
||||
assertThat(getNextDecoder(readers).getClass()).isEqualTo(Jackson2JsonDecoder.class);
|
||||
assertThat(getNextDecoder(readers).getClass()).isEqualTo(Jackson2SmileDecoder.class);
|
||||
assertThat(getNextDecoder(readers).getClass()).isEqualTo(Jaxb2XmlDecoder.class);
|
||||
@@ -103,7 +109,7 @@ class CodecConfigurerTests {
|
||||
@Test
|
||||
void defaultWriters() {
|
||||
List<HttpMessageWriter<?>> writers = this.configurer.getWriters();
|
||||
assertThat(writers.size()).isEqualTo(13);
|
||||
assertThat(writers.size()).isEqualTo(15);
|
||||
assertThat(getNextEncoder(writers).getClass()).isEqualTo(ByteArrayEncoder.class);
|
||||
assertThat(getNextEncoder(writers).getClass()).isEqualTo(ByteBufferEncoder.class);
|
||||
assertThat(getNextEncoder(writers).getClass()).isEqualTo(DataBufferEncoder.class);
|
||||
@@ -112,7 +118,9 @@ class CodecConfigurerTests {
|
||||
assertThat(writers.get(index.getAndIncrement()).getClass()).isEqualTo(ResourceHttpMessageWriter.class);
|
||||
assertStringEncoder(getNextEncoder(writers), true);
|
||||
assertThat(writers.get(index.getAndIncrement()).getClass()).isEqualTo(ProtobufHttpMessageWriter.class);
|
||||
assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationCborEncoder.class);
|
||||
assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationJsonEncoder.class);
|
||||
assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationProtobufEncoder.class);
|
||||
assertThat(getNextEncoder(writers).getClass()).isEqualTo(Jackson2JsonEncoder.class);
|
||||
assertThat(getNextEncoder(writers).getClass()).isEqualTo(Jackson2SmileEncoder.class);
|
||||
assertThat(getNextEncoder(writers).getClass()).isEqualTo(Jaxb2XmlEncoder.class);
|
||||
@@ -141,7 +149,7 @@ class CodecConfigurerTests {
|
||||
|
||||
List<HttpMessageReader<?>> readers = this.configurer.getReaders();
|
||||
|
||||
assertThat(readers.size()).isEqualTo(18);
|
||||
assertThat(readers.size()).isEqualTo(20);
|
||||
assertThat(getNextDecoder(readers)).isSameAs(customDecoder1);
|
||||
assertThat(readers.get(this.index.getAndIncrement())).isSameAs(customReader1);
|
||||
assertThat(getNextDecoder(readers).getClass()).isEqualTo(ByteArrayDecoder.class);
|
||||
@@ -155,7 +163,9 @@ class CodecConfigurerTests {
|
||||
assertThat(readers.get(this.index.getAndIncrement()).getClass()).isEqualTo(FormHttpMessageReader.class);
|
||||
assertThat(getNextDecoder(readers)).isSameAs(customDecoder2);
|
||||
assertThat(readers.get(this.index.getAndIncrement())).isSameAs(customReader2);
|
||||
assertThat(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationCborDecoder.class);
|
||||
assertThat(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationJsonDecoder.class);
|
||||
assertThat(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationProtobufDecoder.class);
|
||||
assertThat(getNextDecoder(readers).getClass()).isEqualTo(Jackson2JsonDecoder.class);
|
||||
assertThat(getNextDecoder(readers).getClass()).isEqualTo(Jackson2SmileDecoder.class);
|
||||
assertThat(getNextDecoder(readers).getClass()).isEqualTo(Jaxb2XmlDecoder.class);
|
||||
@@ -184,7 +194,7 @@ class CodecConfigurerTests {
|
||||
|
||||
List<HttpMessageWriter<?>> writers = this.configurer.getWriters();
|
||||
|
||||
assertThat(writers.size()).isEqualTo(17);
|
||||
assertThat(writers.size()).isEqualTo(19);
|
||||
assertThat(getNextEncoder(writers)).isSameAs(customEncoder1);
|
||||
assertThat(writers.get(this.index.getAndIncrement())).isSameAs(customWriter1);
|
||||
assertThat(getNextEncoder(writers).getClass()).isEqualTo(ByteArrayEncoder.class);
|
||||
@@ -197,7 +207,9 @@ class CodecConfigurerTests {
|
||||
assertThat(writers.get(index.getAndIncrement()).getClass()).isEqualTo(ProtobufHttpMessageWriter.class);
|
||||
assertThat(getNextEncoder(writers)).isSameAs(customEncoder2);
|
||||
assertThat(writers.get(this.index.getAndIncrement())).isSameAs(customWriter2);
|
||||
assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationCborEncoder.class);
|
||||
assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationJsonEncoder.class);
|
||||
assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationProtobufEncoder.class);
|
||||
assertThat(getNextEncoder(writers).getClass()).isEqualTo(Jackson2JsonEncoder.class);
|
||||
assertThat(getNextEncoder(writers).getClass()).isEqualTo(Jackson2SmileEncoder.class);
|
||||
assertThat(getNextEncoder(writers).getClass()).isEqualTo(Jaxb2XmlEncoder.class);
|
||||
|
||||
@@ -54,6 +54,8 @@ import org.springframework.http.codec.ResourceHttpMessageReader;
|
||||
import org.springframework.http.codec.ResourceHttpMessageWriter;
|
||||
import org.springframework.http.codec.ServerCodecConfigurer;
|
||||
import org.springframework.http.codec.ServerSentEventHttpMessageWriter;
|
||||
import org.springframework.http.codec.cbor.KotlinSerializationCborDecoder;
|
||||
import org.springframework.http.codec.cbor.KotlinSerializationCborEncoder;
|
||||
import org.springframework.http.codec.json.Jackson2JsonDecoder;
|
||||
import org.springframework.http.codec.json.Jackson2JsonEncoder;
|
||||
import org.springframework.http.codec.json.Jackson2SmileDecoder;
|
||||
@@ -64,6 +66,8 @@ import org.springframework.http.codec.multipart.DefaultPartHttpMessageReader;
|
||||
import org.springframework.http.codec.multipart.MultipartHttpMessageReader;
|
||||
import org.springframework.http.codec.multipart.PartEventHttpMessageReader;
|
||||
import org.springframework.http.codec.multipart.PartHttpMessageWriter;
|
||||
import org.springframework.http.codec.protobuf.KotlinSerializationProtobufDecoder;
|
||||
import org.springframework.http.codec.protobuf.KotlinSerializationProtobufEncoder;
|
||||
import org.springframework.http.codec.protobuf.ProtobufDecoder;
|
||||
import org.springframework.http.codec.protobuf.ProtobufHttpMessageWriter;
|
||||
import org.springframework.http.codec.xml.Jaxb2XmlDecoder;
|
||||
@@ -88,7 +92,7 @@ public class ServerCodecConfigurerTests {
|
||||
@Test
|
||||
public void defaultReaders() {
|
||||
List<HttpMessageReader<?>> readers = this.configurer.getReaders();
|
||||
assertThat(readers.size()).isEqualTo(17);
|
||||
assertThat(readers.size()).isEqualTo(19);
|
||||
assertThat(getNextDecoder(readers).getClass()).isEqualTo(ByteArrayDecoder.class);
|
||||
assertThat(getNextDecoder(readers).getClass()).isEqualTo(ByteBufferDecoder.class);
|
||||
assertThat(getNextDecoder(readers).getClass()).isEqualTo(DataBufferDecoder.class);
|
||||
@@ -101,7 +105,9 @@ public class ServerCodecConfigurerTests {
|
||||
assertThat(readers.get(this.index.getAndIncrement()).getClass()).isEqualTo(DefaultPartHttpMessageReader.class);
|
||||
assertThat(readers.get(this.index.getAndIncrement()).getClass()).isEqualTo(MultipartHttpMessageReader.class);
|
||||
assertThat(readers.get(this.index.getAndIncrement()).getClass()).isEqualTo(PartEventHttpMessageReader.class);
|
||||
assertThat(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationCborDecoder.class);
|
||||
assertThat(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationJsonDecoder.class);
|
||||
assertThat(getNextDecoder(readers).getClass()).isEqualTo(KotlinSerializationProtobufDecoder.class);
|
||||
assertThat(getNextDecoder(readers).getClass()).isEqualTo(Jackson2JsonDecoder.class);
|
||||
assertThat(getNextDecoder(readers).getClass()).isEqualTo(Jackson2SmileDecoder.class);
|
||||
assertThat(getNextDecoder(readers).getClass()).isEqualTo(Jaxb2XmlDecoder.class);
|
||||
@@ -111,7 +117,7 @@ public class ServerCodecConfigurerTests {
|
||||
@Test
|
||||
public void defaultWriters() {
|
||||
List<HttpMessageWriter<?>> writers = this.configurer.getWriters();
|
||||
assertThat(writers.size()).isEqualTo(15);
|
||||
assertThat(writers.size()).isEqualTo(17);
|
||||
assertThat(getNextEncoder(writers).getClass()).isEqualTo(ByteArrayEncoder.class);
|
||||
assertThat(getNextEncoder(writers).getClass()).isEqualTo(ByteBufferEncoder.class);
|
||||
assertThat(getNextEncoder(writers).getClass()).isEqualTo(DataBufferEncoder.class);
|
||||
@@ -121,7 +127,9 @@ public class ServerCodecConfigurerTests {
|
||||
assertStringEncoder(getNextEncoder(writers), true);
|
||||
assertThat(writers.get(index.getAndIncrement()).getClass()).isEqualTo(ProtobufHttpMessageWriter.class);
|
||||
assertThat(writers.get(this.index.getAndIncrement()).getClass()).isEqualTo(PartHttpMessageWriter.class);
|
||||
assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationCborEncoder.class);
|
||||
assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationJsonEncoder.class);
|
||||
assertThat(getNextEncoder(writers).getClass()).isEqualTo(KotlinSerializationProtobufEncoder.class);
|
||||
assertThat(getNextEncoder(writers).getClass()).isEqualTo(Jackson2JsonEncoder.class);
|
||||
assertThat(getNextEncoder(writers).getClass()).isEqualTo(Jackson2SmileEncoder.class);
|
||||
assertThat(getNextEncoder(writers).getClass()).isEqualTo(Jaxb2XmlEncoder.class);
|
||||
@@ -168,7 +176,9 @@ public class ServerCodecConfigurerTests {
|
||||
assertThat((reader).getMaxInMemorySize()).isEqualTo(size);
|
||||
assertThat(((PartEventHttpMessageReader) nextReader(readers)).getMaxInMemorySize()).isEqualTo(size);
|
||||
|
||||
assertThat(((KotlinSerializationCborDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size);
|
||||
assertThat(((KotlinSerializationJsonDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size);
|
||||
assertThat(((KotlinSerializationProtobufDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size);
|
||||
assertThat(((Jackson2JsonDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size);
|
||||
assertThat(((Jackson2SmileDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size);
|
||||
assertThat(((Jaxb2XmlDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size);
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright 2002-2021 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.http.codec.cbor
|
||||
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.cbor.Cbor
|
||||
import kotlinx.serialization.serializer
|
||||
import org.assertj.core.api.Assertions
|
||||
import org.junit.jupiter.api.Test
|
||||
import reactor.core.publisher.Flux
|
||||
import reactor.core.publisher.Mono
|
||||
import reactor.test.StepVerifier
|
||||
import reactor.test.StepVerifier.FirstStep
|
||||
|
||||
import org.springframework.core.Ordered
|
||||
import org.springframework.core.ResolvableType
|
||||
import org.springframework.core.io.buffer.DataBuffer
|
||||
import org.springframework.core.testfixture.codec.AbstractDecoderTests
|
||||
import org.springframework.http.MediaType
|
||||
|
||||
/**
|
||||
* Tests for the JSON decoding using kotlinx.serialization.
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @author Iain Henderson
|
||||
*/
|
||||
@ExperimentalSerializationApi
|
||||
class KotlinSerializationCborDecoderTests : AbstractDecoderTests<KotlinSerializationCborDecoder>(KotlinSerializationCborDecoder()) {
|
||||
|
||||
@Suppress("UsePropertyAccessSyntax", "DEPRECATION")
|
||||
@Test
|
||||
override fun canDecode() {
|
||||
Assertions.assertThat(decoder.canDecode(ResolvableType.forClass(Pojo::class.java), MediaType.APPLICATION_CBOR)).isTrue()
|
||||
Assertions.assertThat(decoder.canDecode(ResolvableType.forClass(Pojo::class.java), null)).isTrue()
|
||||
Assertions.assertThat(decoder.canDecode(ResolvableType.forClass(String::class.java), null)).isFalse()
|
||||
Assertions.assertThat(decoder.canDecode(ResolvableType.forClass(Pojo::class.java), MediaType.APPLICATION_XML)).isFalse()
|
||||
|
||||
Assertions.assertThat(decoder.canDecode(ResolvableType.forClassWithGenerics(List::class.java, Int::class.java), MediaType.APPLICATION_CBOR)).isTrue()
|
||||
Assertions.assertThat(decoder.canDecode(ResolvableType.forClassWithGenerics(List::class.java, Ordered::class.java), MediaType.APPLICATION_CBOR)).isFalse()
|
||||
Assertions.assertThat(decoder.canDecode(ResolvableType.forClassWithGenerics(List::class.java, Pojo::class.java), MediaType.APPLICATION_CBOR)).isTrue()
|
||||
Assertions.assertThat(decoder.canDecode(ResolvableType.forClassWithGenerics(ArrayList::class.java, Int::class.java), MediaType.APPLICATION_CBOR)).isTrue()
|
||||
Assertions.assertThat(decoder.canDecode(ResolvableType.forClassWithGenerics(ArrayList::class.java, Int::class.java), MediaType.APPLICATION_PDF)).isFalse()
|
||||
Assertions.assertThat(decoder.canDecode(ResolvableType.forClass(Ordered::class.java), MediaType.APPLICATION_CBOR)).isFalse()
|
||||
}
|
||||
|
||||
@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
|
||||
override fun decodeToMono() {
|
||||
val pojo1 = Pojo("f1", "b1")
|
||||
val input = Flux.concat(
|
||||
byteBuffer(pojo1)
|
||||
)
|
||||
|
||||
val elementType = ResolvableType.forClass(Pojo::class.java)
|
||||
|
||||
testDecodeToMonoAll(input, elementType, { step: FirstStep<Any> ->
|
||||
step
|
||||
.expectNext(pojo1)
|
||||
.expectComplete()
|
||||
.verify()
|
||||
}, null, null)
|
||||
}
|
||||
|
||||
private fun byteBuffer(value: Any): Mono<DataBuffer> {
|
||||
return Mono.defer {
|
||||
val bytes = Cbor.Default.encodeToByteArray(serializer(Pojo::class.java), value)
|
||||
val buffer = bufferFactory.allocateBuffer(bytes.size)
|
||||
buffer.write(bytes)
|
||||
Mono.just(buffer)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@Serializable
|
||||
data class Pojo(val foo: String, val bar: String, val pojo: Pojo? = null)
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright 2002-2021 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.http.codec.cbor
|
||||
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.cbor.Cbor
|
||||
import kotlinx.serialization.encodeToByteArray
|
||||
import org.assertj.core.api.Assertions
|
||||
import org.junit.jupiter.api.Test
|
||||
import reactor.core.publisher.Flux
|
||||
import reactor.core.publisher.Mono
|
||||
import reactor.test.StepVerifier.FirstStep
|
||||
|
||||
import org.springframework.core.Ordered
|
||||
import org.springframework.core.ResolvableType
|
||||
import org.springframework.core.io.buffer.DataBuffer
|
||||
import org.springframework.core.io.buffer.DataBufferUtils
|
||||
import org.springframework.core.testfixture.codec.AbstractEncoderTests
|
||||
import org.springframework.http.MediaType
|
||||
import org.springframework.http.codec.ServerSentEvent
|
||||
|
||||
/**
|
||||
* Tests for the JSON encoding using kotlinx.serialization.
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @author Iain Henderson
|
||||
*/
|
||||
@Suppress("UsePropertyAccessSyntax")
|
||||
@ExperimentalSerializationApi
|
||||
class KotlinSerializationCborEncoderTests : AbstractEncoderTests<KotlinSerializationCborEncoder>(KotlinSerializationCborEncoder()) {
|
||||
|
||||
@Test
|
||||
override fun canEncode() {
|
||||
val pojoType = ResolvableType.forClass(Pojo::class.java)
|
||||
Assertions.assertThat(encoder.canEncode(pojoType, MediaType.APPLICATION_CBOR)).isTrue()
|
||||
Assertions.assertThat(encoder.canEncode(pojoType, null)).isTrue()
|
||||
|
||||
Assertions.assertThat(encoder.canEncode(ResolvableType.forClassWithGenerics(List::class.java, Int::class.java), MediaType.APPLICATION_CBOR)).isTrue()
|
||||
Assertions.assertThat(encoder.canEncode(ResolvableType.forClassWithGenerics(List::class.java, Ordered::class.java), MediaType.APPLICATION_CBOR)).isFalse()
|
||||
Assertions.assertThat(encoder.canEncode(ResolvableType.forClassWithGenerics(List::class.java, Pojo::class.java), MediaType.APPLICATION_CBOR)).isTrue()
|
||||
Assertions.assertThat(encoder.canEncode(ResolvableType.forClassWithGenerics(ArrayList::class.java, Int::class.java), MediaType.APPLICATION_CBOR)).isTrue()
|
||||
Assertions.assertThat(encoder.canEncode(ResolvableType.forClassWithGenerics(ArrayList::class.java, Int::class.java), MediaType.APPLICATION_PDF)).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
override fun encode() {
|
||||
val pojo1 = Pojo("foo", "bar")
|
||||
val pojo2 = Pojo("foofoo", "barbar")
|
||||
val pojo3 = Pojo("foofoofoo", "barbarbar")
|
||||
val input = Flux.just(
|
||||
pojo1,
|
||||
pojo2,
|
||||
pojo3
|
||||
)
|
||||
val pojoBytes = Cbor.Default.encodeToByteArray(arrayOf(pojo1, pojo2, pojo3))
|
||||
testEncode(input, Pojo::class.java) { step: FirstStep<DataBuffer?> ->
|
||||
step
|
||||
.consumeNextWith(expectBytes(pojoBytes)
|
||||
.andThen { dataBuffer: DataBuffer? -> DataBufferUtils.release(dataBuffer) })
|
||||
.verifyComplete()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun encodeMono() {
|
||||
val pojo = Pojo("foo", "bar")
|
||||
val input = Mono.just(pojo)
|
||||
testEncode(input, Pojo::class.java) { step: FirstStep<DataBuffer?> ->
|
||||
step
|
||||
.consumeNextWith(expectBytes(Cbor.Default.encodeToByteArray(pojo))
|
||||
.andThen { dataBuffer: DataBuffer? -> DataBufferUtils.release(dataBuffer) })
|
||||
.verifyComplete()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun canNotEncode() {
|
||||
Assertions.assertThat(encoder.canEncode(ResolvableType.forClass(String::class.java), null)).isFalse()
|
||||
Assertions.assertThat(encoder.canEncode(ResolvableType.forClass(Pojo::class.java), MediaType.APPLICATION_XML)).isFalse()
|
||||
val sseType = ResolvableType.forClass(ServerSentEvent::class.java)
|
||||
Assertions.assertThat(encoder.canEncode(sseType, MediaType.APPLICATION_CBOR)).isFalse()
|
||||
Assertions.assertThat(encoder.canEncode(ResolvableType.forClass(Ordered::class.java), MediaType.APPLICATION_CBOR)).isFalse()
|
||||
}
|
||||
|
||||
|
||||
@Serializable
|
||||
data class Pojo(val foo: String, val bar: String, val pojo: Pojo? = null)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright 2002-2022 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.http.codec.protobuf
|
||||
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.protobuf.ProtoBuf
|
||||
import kotlinx.serialization.serializer
|
||||
import org.assertj.core.api.Assertions
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.core.Ordered
|
||||
import org.springframework.core.ResolvableType
|
||||
import org.springframework.core.io.buffer.DataBuffer
|
||||
import org.springframework.core.testfixture.codec.AbstractDecoderTests
|
||||
import org.springframework.http.MediaType
|
||||
import reactor.core.publisher.Flux
|
||||
import reactor.core.publisher.Mono
|
||||
import reactor.test.StepVerifier
|
||||
import reactor.test.StepVerifier.FirstStep
|
||||
|
||||
/**
|
||||
* Tests for the JSON decoding using kotlinx.serialization.
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @author Iain Henderson
|
||||
*/
|
||||
@ExperimentalSerializationApi
|
||||
class KotlinSerializationCborDecoderTests : AbstractDecoderTests<KotlinSerializationProtobufDecoder>(KotlinSerializationProtobufDecoder()) {
|
||||
@Suppress("UsePropertyAccessSyntax")
|
||||
@Test
|
||||
override fun canDecode() {
|
||||
for (mimeType in listOf(MediaType.APPLICATION_PROTOBUF, MediaType.APPLICATION_OCTET_STREAM, MediaType("application", "vnd.google.protobuf"))) {
|
||||
Assertions.assertThat(decoder.canDecode(ResolvableType.forClass(Pojo::class.java),mimeType)).isTrue()
|
||||
|
||||
Assertions.assertThat(decoder.canDecode(ResolvableType.forClassWithGenerics(List::class.java, Int::class.java), mimeType)).isTrue()
|
||||
Assertions.assertThat(decoder.canDecode(ResolvableType.forClassWithGenerics(List::class.java, Ordered::class.java), mimeType)).isFalse()
|
||||
Assertions.assertThat(decoder.canDecode(ResolvableType.forClassWithGenerics(List::class.java, Pojo::class.java), mimeType)).isTrue()
|
||||
Assertions.assertThat(decoder.canDecode(ResolvableType.forClassWithGenerics(ArrayList::class.java, Int::class.java), mimeType)).isTrue()
|
||||
Assertions.assertThat(decoder.canDecode(ResolvableType.forClass(Ordered::class.java), mimeType)).isFalse()
|
||||
}
|
||||
Assertions.assertThat(decoder.canDecode(ResolvableType.forClass(Pojo::class.java), null)).isTrue()
|
||||
Assertions.assertThat(decoder.canDecode(ResolvableType.forClass(String::class.java), null)).isFalse()
|
||||
Assertions.assertThat(decoder.canDecode(ResolvableType.forClass(Pojo::class.java), MediaType.APPLICATION_XML)).isFalse()
|
||||
Assertions.assertThat(decoder.canDecode(ResolvableType.forClassWithGenerics(ArrayList::class.java, Int::class.java), MediaType.APPLICATION_PDF)).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
override fun decode() {
|
||||
val output = decoder.decode(Mono.empty(), ResolvableType.forClass(Pojo::class.java), null, emptyMap())
|
||||
StepVerifier
|
||||
.create(output)
|
||||
.expectError(UnsupportedOperationException::class.java)
|
||||
.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
override fun decodeToMono() {
|
||||
val pojo1 = Pojo("f1", "b1")
|
||||
val pojo2 = Pojo("f2", "b2")
|
||||
val input = Flux.concat(
|
||||
byteBuffer(pojo1),
|
||||
byteBuffer(pojo2)
|
||||
)
|
||||
|
||||
val elementType = ResolvableType.forClass(Pojo::class.java)
|
||||
|
||||
testDecodeToMonoAll(input, elementType, { step: FirstStep<Any> ->
|
||||
step
|
||||
.expectNext(pojo2)
|
||||
.expectComplete()
|
||||
.verify()
|
||||
}, null, null)
|
||||
}
|
||||
|
||||
private fun byteBuffer(value: Any): Mono<DataBuffer> {
|
||||
return Mono.defer {
|
||||
val bytes = ProtoBuf.Default.encodeToByteArray(serializer(Pojo::class.java), value)
|
||||
val buffer = bufferFactory.allocateBuffer(bytes.size)
|
||||
buffer.write(bytes)
|
||||
Mono.just(buffer)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@Serializable
|
||||
data class Pojo(val foo: String, val bar: String, val pojo: Pojo? = null)
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright 2002-2022 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.http.codec.protobuf
|
||||
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.encodeToByteArray
|
||||
import kotlinx.serialization.protobuf.ProtoBuf
|
||||
import org.assertj.core.api.Assertions
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.core.Ordered
|
||||
import org.springframework.core.ResolvableType
|
||||
import org.springframework.core.io.buffer.DataBuffer
|
||||
import org.springframework.core.io.buffer.DataBufferUtils
|
||||
import org.springframework.core.testfixture.codec.AbstractEncoderTests
|
||||
import org.springframework.http.MediaType
|
||||
import org.springframework.http.codec.ServerSentEvent
|
||||
import reactor.core.publisher.Flux
|
||||
import reactor.core.publisher.Mono
|
||||
import reactor.test.StepVerifier.FirstStep
|
||||
|
||||
/**
|
||||
* Tests for the JSON encoding using kotlinx.serialization.
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @author Iain Henderson
|
||||
*/
|
||||
@Suppress("UsePropertyAccessSyntax")
|
||||
@ExperimentalSerializationApi
|
||||
class KotlinSerializationProtobufEncoderTests : AbstractEncoderTests<KotlinSerializationProtobufEncoder>(KotlinSerializationProtobufEncoder()) {
|
||||
|
||||
private val mediaTypes = listOf(
|
||||
MediaType.APPLICATION_PROTOBUF,
|
||||
MediaType.APPLICATION_OCTET_STREAM,
|
||||
MediaType("application", "vnd.google.protobuf")
|
||||
)
|
||||
|
||||
@Test
|
||||
override fun canEncode() {
|
||||
val pojoType = ResolvableType.forClass(Pojo::class.java)
|
||||
Assertions.assertThat(encoder.canEncode(pojoType, null)).isTrue()
|
||||
|
||||
for (mimeType in ProtobufCodecSupport.MIME_TYPES) {
|
||||
val mediaType = MediaType(mimeType)
|
||||
Assertions.assertThat(encoder.canEncode(pojoType, mediaType)).isTrue()
|
||||
|
||||
Assertions.assertThat(encoder.canEncode(ResolvableType.forClassWithGenerics(List::class.java, Int::class.java), mimeType)).isTrue()
|
||||
Assertions.assertThat(encoder.canEncode(ResolvableType.forClassWithGenerics(List::class.java, Ordered::class.java), mimeType)).isFalse()
|
||||
Assertions.assertThat(encoder.canEncode(ResolvableType.forClassWithGenerics(List::class.java, Pojo::class.java), mimeType)).isTrue()
|
||||
Assertions.assertThat(encoder.canEncode(ResolvableType.forClassWithGenerics(ArrayList::class.java, Int::class.java), mimeType)).isTrue()
|
||||
}
|
||||
Assertions.assertThat(encoder.canEncode(ResolvableType.forClassWithGenerics(ArrayList::class.java, Int::class.java), MediaType.APPLICATION_PDF)).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
override fun encode() {
|
||||
val pojo1 = Pojo("foo", "bar")
|
||||
val pojo2 = Pojo("foofoo", "barbar")
|
||||
val pojo3 = Pojo("foofoofoo", "barbarbar")
|
||||
val input = Flux.just(
|
||||
pojo1,
|
||||
pojo2,
|
||||
pojo3
|
||||
)
|
||||
val pojoBytes = ProtoBuf.Default.encodeToByteArray(arrayOf(pojo1, pojo2, pojo3))
|
||||
testEncode(input, Pojo::class.java) { step: FirstStep<DataBuffer?> ->
|
||||
step
|
||||
.consumeNextWith(expectBytes(pojoBytes)
|
||||
.andThen { dataBuffer: DataBuffer? -> DataBufferUtils.release(dataBuffer) })
|
||||
.verifyComplete()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun encodeMono() {
|
||||
val pojo = Pojo("foo", "bar")
|
||||
val input = Mono.just(pojo)
|
||||
testEncode(input, Pojo::class.java) { step: FirstStep<DataBuffer?> ->
|
||||
step
|
||||
.consumeNextWith(expectBytes(ProtoBuf.Default.encodeToByteArray(pojo))
|
||||
.andThen { dataBuffer: DataBuffer? -> DataBufferUtils.release(dataBuffer) })
|
||||
.verifyComplete()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun canNotEncode() {
|
||||
Assertions.assertThat(encoder.canEncode(ResolvableType.forClass(String::class.java), null)).isFalse()
|
||||
Assertions.assertThat(encoder.canEncode(ResolvableType.forClass(Pojo::class.java), MediaType.APPLICATION_XML)).isFalse()
|
||||
val sseType = ResolvableType.forClass(ServerSentEvent::class.java)
|
||||
for (mediaType in mediaTypes) {
|
||||
Assertions.assertThat(encoder.canEncode(sseType, mediaType)).isFalse()
|
||||
Assertions.assertThat(encoder.canEncode(ResolvableType.forClass(Ordered::class.java), mediaType)).isFalse()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Serializable
|
||||
data class Pojo(val foo: String, val bar: String, val pojo: Pojo? = null)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
* Copyright 2002-2021 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.http.converter.cbor
|
||||
|
||||
import java.lang.reflect.ParameterizedType
|
||||
import java.lang.reflect.Type
|
||||
import java.nio.charset.StandardCharsets
|
||||
|
||||
import kotlin.reflect.javaType
|
||||
import kotlin.reflect.typeOf
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.cbor.Cbor
|
||||
import kotlinx.serialization.encodeToByteArray
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.assertj.core.api.Assertions.assertThatExceptionOfType
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
import org.springframework.core.Ordered
|
||||
import org.springframework.http.MediaType
|
||||
import org.springframework.http.MockHttpInputMessage
|
||||
import org.springframework.http.MockHttpOutputMessage
|
||||
import org.springframework.http.converter.HttpMessageNotReadableException
|
||||
|
||||
/**
|
||||
* Tests for the CBOR conversion using kotlinx.serialization.
|
||||
*
|
||||
* @author Andreas Ahlenstorf
|
||||
* @author Sebastien Deleuze
|
||||
* @author Iain Henderson
|
||||
*/
|
||||
@Suppress("UsePropertyAccessSyntax")
|
||||
@ExperimentalSerializationApi
|
||||
class KotlinSerializationCborHttpMessageConverterTests {
|
||||
|
||||
private val converter = KotlinSerializationCborHttpMessageConverter()
|
||||
private val serializableBean = SerializableBean(
|
||||
bytes = byteArrayOf(0x1, 0x2),
|
||||
array = arrayOf("Foo", "Bar"),
|
||||
number = 42,
|
||||
string = "Foo",
|
||||
bool = true,
|
||||
fraction = 42f
|
||||
)
|
||||
private val serializableBeanArray = arrayOf(serializableBean)
|
||||
private val serializableBeanArrayBody = Cbor.Default.encodeToByteArray(serializableBeanArray)
|
||||
|
||||
@Test
|
||||
fun canReadCbor() {
|
||||
assertThat(converter.canRead(SerializableBean::class.java, MediaType.APPLICATION_CBOR)).isTrue()
|
||||
assertThat(converter.canRead(SerializableBean::class.java, MediaType.APPLICATION_JSON)).isFalse()
|
||||
assertThat(converter.canRead(String::class.java, MediaType.APPLICATION_CBOR)).isTrue()
|
||||
assertThat(converter.canRead(NotSerializableBean::class.java, MediaType.APPLICATION_CBOR)).isFalse()
|
||||
|
||||
assertThat(converter.canRead(Map::class.java, MediaType.APPLICATION_CBOR)).isFalse()
|
||||
assertThat(converter.canRead(typeTokenOf<Map<String, SerializableBean>>(), Map::class.java, MediaType.APPLICATION_CBOR)).isTrue()
|
||||
assertThat(converter.canRead(List::class.java, MediaType.APPLICATION_CBOR)).isFalse()
|
||||
assertThat(converter.canRead(typeTokenOf<List<SerializableBean>>(), List::class.java, MediaType.APPLICATION_CBOR)).isTrue()
|
||||
assertThat(converter.canRead(Set::class.java, MediaType.APPLICATION_CBOR)).isFalse()
|
||||
assertThat(converter.canRead(typeTokenOf<Set<SerializableBean>>(), Set::class.java, MediaType.APPLICATION_CBOR)).isTrue()
|
||||
|
||||
assertThat(converter.canRead(typeTokenOf<List<Int>>(), List::class.java, MediaType.APPLICATION_CBOR)).isTrue()
|
||||
assertThat(converter.canRead(typeTokenOf<ArrayList<Int>>(), List::class.java, MediaType.APPLICATION_CBOR)).isTrue()
|
||||
assertThat(converter.canRead(typeTokenOf<List<Int>>(), List::class.java, MediaType.APPLICATION_JSON)).isFalse()
|
||||
|
||||
assertThat(converter.canRead(typeTokenOf<Ordered>(), Ordered::class.java, MediaType.APPLICATION_CBOR)).isFalse()
|
||||
assertThat(converter.canRead(typeTokenOf<List<Ordered>>(), List::class.java, MediaType.APPLICATION_CBOR)).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun canWriteCbor() {
|
||||
assertThat(converter.canWrite(SerializableBean::class.java, MediaType.APPLICATION_CBOR)).isTrue()
|
||||
assertThat(converter.canWrite(SerializableBean::class.java, MediaType.APPLICATION_JSON)).isFalse()
|
||||
assertThat(converter.canWrite(String::class.java, MediaType.APPLICATION_CBOR)).isTrue()
|
||||
assertThat(converter.canWrite(NotSerializableBean::class.java, MediaType.APPLICATION_CBOR)).isFalse()
|
||||
|
||||
assertThat(converter.canWrite(Map::class.java, MediaType.APPLICATION_CBOR)).isFalse()
|
||||
assertThat(converter.canWrite(typeTokenOf<Map<String, SerializableBean>>(), Map::class.java, MediaType.APPLICATION_CBOR)).isTrue()
|
||||
assertThat(converter.canWrite(List::class.java, MediaType.APPLICATION_CBOR)).isFalse()
|
||||
assertThat(converter.canWrite(typeTokenOf<List<SerializableBean>>(), List::class.java, MediaType.APPLICATION_CBOR)).isTrue()
|
||||
assertThat(converter.canWrite(Set::class.java, MediaType.APPLICATION_CBOR)).isFalse()
|
||||
assertThat(converter.canWrite(typeTokenOf<Set<SerializableBean>>(), Set::class.java, MediaType.APPLICATION_CBOR)).isTrue()
|
||||
|
||||
assertThat(converter.canWrite(typeTokenOf<List<Int>>(), List::class.java, MediaType.APPLICATION_CBOR)).isTrue()
|
||||
assertThat(converter.canWrite(typeTokenOf<ArrayList<Int>>(), List::class.java, MediaType.APPLICATION_CBOR)).isTrue()
|
||||
assertThat(converter.canWrite(typeTokenOf<List<Int>>(), List::class.java, MediaType.APPLICATION_JSON)).isFalse()
|
||||
|
||||
assertThat(converter.canWrite(typeTokenOf<Ordered>(), Ordered::class.java, MediaType.APPLICATION_CBOR)).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun readObject() {
|
||||
val serializableBeanBody = Cbor.Default.encodeToByteArray(serializableBean)
|
||||
val inputMessage = MockHttpInputMessage(serializableBeanBody)
|
||||
inputMessage.headers.contentType = MediaType.APPLICATION_CBOR
|
||||
val result = converter.read(SerializableBean::class.java, inputMessage) as SerializableBean
|
||||
|
||||
assertThat(result.bytes).containsExactly(*serializableBean.bytes)
|
||||
assertThat(result.array).containsExactly(*serializableBean.array)
|
||||
assertThat(result.number).isEqualTo(serializableBean.number)
|
||||
assertThat(result.string).isEqualTo(serializableBean.string)
|
||||
assertThat(result.bool).isTrue()
|
||||
assertThat(result.fraction).isEqualTo(serializableBean.fraction)
|
||||
}
|
||||
|
||||
@Test
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun readArrayOfObjects() {
|
||||
val inputMessage = MockHttpInputMessage(serializableBeanArrayBody)
|
||||
inputMessage.headers.contentType = MediaType.APPLICATION_CBOR
|
||||
val result = converter.read(Array<SerializableBean>::class.java, inputMessage) as Array<SerializableBean>
|
||||
|
||||
assertThat(result).hasSize(1)
|
||||
assertThat(result[0].bytes).containsExactly(*serializableBean.bytes)
|
||||
assertThat(result[0].array).containsExactly(*serializableBean.array)
|
||||
assertThat(result[0].number).isEqualTo(serializableBean.number)
|
||||
assertThat(result[0].string).isEqualTo(serializableBean.string)
|
||||
assertThat(result[0].bool).isTrue()
|
||||
assertThat(result[0].fraction).isEqualTo(serializableBean.fraction)
|
||||
}
|
||||
|
||||
@Test
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
@ExperimentalStdlibApi
|
||||
fun readGenericCollection() {
|
||||
val inputMessage = MockHttpInputMessage(serializableBeanArrayBody)
|
||||
inputMessage.headers.contentType = MediaType.APPLICATION_CBOR
|
||||
val result = converter.read(typeOf<List<SerializableBean>>().javaType, null, inputMessage)
|
||||
as List<SerializableBean>
|
||||
|
||||
assertThat(result).hasSize(1)
|
||||
assertThat(result[0].bytes).containsExactly(*serializableBean.bytes)
|
||||
assertThat(result[0].array).containsExactly(*serializableBean.array)
|
||||
assertThat(result[0].number).isEqualTo(serializableBean.number)
|
||||
assertThat(result[0].string).isEqualTo(serializableBean.string)
|
||||
assertThat(result[0].bool).isTrue()
|
||||
assertThat(result[0].fraction).isEqualTo(serializableBean.fraction)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun readFailsOnInvalidCbor() {
|
||||
val body = """
|
||||
this is an invalid JSON document and definitely NOT CBOR
|
||||
""".trimIndent()
|
||||
|
||||
val inputMessage = MockHttpInputMessage(body.toByteArray(StandardCharsets.UTF_8))
|
||||
inputMessage.headers.contentType = MediaType.APPLICATION_CBOR
|
||||
assertThatExceptionOfType(HttpMessageNotReadableException::class.java).isThrownBy {
|
||||
converter.read(SerializableBean::class.java, inputMessage)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun writeObject() {
|
||||
val outputMessage = MockHttpOutputMessage()
|
||||
|
||||
this.converter.write(serializableBean, null, outputMessage)
|
||||
|
||||
assertThat(outputMessage.headers).containsEntry("Content-Type", listOf("application/cbor"))
|
||||
assertThat(outputMessage.bodyAsBytes.isNotEmpty()).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun writeObjectWithNullableProperty() {
|
||||
val outputMessage = MockHttpOutputMessage()
|
||||
val serializableBean = SerializableBean(byteArrayOf(0x1, 0x2), arrayOf("Foo", "Bar"), 42, null, true, 42.0f)
|
||||
|
||||
this.converter.write(serializableBean, null, outputMessage)
|
||||
|
||||
assertThat(outputMessage.headers).containsEntry("Content-Type", listOf("application/cbor"))
|
||||
assertThat(outputMessage.bodyAsBytes.isNotEmpty()).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun writeArrayOfObjects() {
|
||||
val outputMessage = MockHttpOutputMessage()
|
||||
|
||||
this.converter.write(serializableBeanArray, null, outputMessage)
|
||||
|
||||
assertThat(outputMessage.headers).containsEntry("Content-Type", listOf("application/cbor"))
|
||||
assertThat(outputMessage.bodyAsBytes.isNotEmpty()).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalStdlibApi
|
||||
fun writeGenericCollection() {
|
||||
val outputMessage = MockHttpOutputMessage()
|
||||
|
||||
this.converter.write(listOf(serializableBean), typeOf<List<SerializableBean>>().javaType, null, outputMessage)
|
||||
|
||||
assertThat(outputMessage.headers).containsEntry("Content-Type", listOf("application/cbor"))
|
||||
assertThat(outputMessage.bodyAsBytes.isNotEmpty()).isTrue()
|
||||
}
|
||||
|
||||
@Serializable
|
||||
@Suppress("ArrayInDataClass")
|
||||
data class SerializableBean(
|
||||
val bytes: ByteArray,
|
||||
val array: Array<String>,
|
||||
val number: Int,
|
||||
val string: String?,
|
||||
val bool: Boolean,
|
||||
val fraction: Float,
|
||||
val serializableBean: SerializableBean? = null
|
||||
)
|
||||
|
||||
data class NotSerializableBean(val string: String)
|
||||
|
||||
open class TypeBase<T>
|
||||
|
||||
inline fun <reified T> typeTokenOf(): Type {
|
||||
val base = object : TypeBase<T>() {}
|
||||
val superType = base::class.java.genericSuperclass!!
|
||||
return (superType as ParameterizedType).actualTypeArguments.first()!!
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,21 +16,23 @@
|
||||
|
||||
package org.springframework.http.converter.json
|
||||
|
||||
import java.lang.reflect.ParameterizedType
|
||||
import java.lang.reflect.Type
|
||||
import java.nio.charset.StandardCharsets
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.assertj.core.api.Assertions.assertThatExceptionOfType
|
||||
import org.junit.jupiter.api.Test
|
||||
import kotlin.reflect.javaType
|
||||
import kotlin.reflect.typeOf
|
||||
|
||||
import org.springframework.core.Ordered
|
||||
import org.springframework.core.ResolvableType
|
||||
import org.springframework.http.MediaType
|
||||
import org.springframework.http.MockHttpInputMessage
|
||||
import org.springframework.http.MockHttpOutputMessage
|
||||
import org.springframework.http.converter.HttpMessageNotReadableException
|
||||
import java.lang.reflect.ParameterizedType
|
||||
import java.lang.reflect.Type
|
||||
import java.nio.charset.StandardCharsets
|
||||
import kotlin.reflect.javaType
|
||||
import kotlin.reflect.typeOf
|
||||
|
||||
/**
|
||||
* Tests for the JSON conversion using kotlinx.serialization.
|
||||
|
||||
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
* Copyright 2002-2022 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.http.converter.protobuf
|
||||
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.encodeToByteArray
|
||||
import kotlinx.serialization.protobuf.ProtoBuf
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.assertj.core.api.Assertions.assertThatExceptionOfType
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.core.Ordered
|
||||
import org.springframework.http.MediaType
|
||||
import org.springframework.http.MockHttpInputMessage
|
||||
import org.springframework.http.MockHttpOutputMessage
|
||||
import org.springframework.http.converter.HttpMessageNotReadableException
|
||||
import java.lang.reflect.ParameterizedType
|
||||
import java.lang.reflect.Type
|
||||
import java.nio.charset.StandardCharsets
|
||||
import kotlin.reflect.javaType
|
||||
import kotlin.reflect.typeOf
|
||||
|
||||
/**
|
||||
* Tests for the Protocol Buffer conversion using kotlinx.serialization.
|
||||
*
|
||||
* @author Andreas Ahlenstorf
|
||||
* @author Sebastien Deleuze
|
||||
* @author Iain Henderson
|
||||
*/
|
||||
@Suppress("UsePropertyAccessSyntax")
|
||||
@ExperimentalSerializationApi
|
||||
class KotlinSerializationProtobufHttpMessageConverterTests {
|
||||
|
||||
private val converter = KotlinSerializationProtobufHttpMessageConverter()
|
||||
private val mediaTypes = listOf(
|
||||
MediaType.APPLICATION_PROTOBUF,
|
||||
MediaType.APPLICATION_OCTET_STREAM,
|
||||
MediaType("application", "vnd.google.protobuf")
|
||||
)
|
||||
private val serializableBean = SerializableBean(
|
||||
bytes = byteArrayOf(0x1, 0x2),
|
||||
array = arrayOf("Foo", "Bar"),
|
||||
number = 42,
|
||||
string = "Foo",
|
||||
bool = true,
|
||||
fraction = 42f
|
||||
)
|
||||
private val serializableBeanArray = arrayOf(serializableBean)
|
||||
private val serializableBeanArrayBody = ProtoBuf.Default.encodeToByteArray(serializableBeanArray)
|
||||
@Test
|
||||
fun canReadProtobuf() {
|
||||
for (mimeType in mediaTypes) {
|
||||
assertThat(converter.canRead(SerializableBean::class.java, mimeType)).isTrue()
|
||||
assertThat(converter.canRead(String::class.java, mimeType)).isTrue()
|
||||
assertThat(converter.canRead(NotSerializableBean::class.java, mimeType)).isFalse()
|
||||
|
||||
assertThat(converter.canRead(Map::class.java, mimeType)).isFalse()
|
||||
assertThat(converter.canRead(typeTokenOf<Map<String, SerializableBean>>(), Map::class.java, mimeType)).isTrue()
|
||||
assertThat(converter.canRead(List::class.java, mimeType)).isFalse()
|
||||
assertThat(converter.canRead(typeTokenOf<List<SerializableBean>>(), List::class.java, mimeType)).isTrue()
|
||||
assertThat(converter.canRead(Set::class.java, mimeType)).isFalse()
|
||||
assertThat(converter.canRead(typeTokenOf<Set<SerializableBean>>(), Set::class.java, mimeType)).isTrue()
|
||||
|
||||
assertThat(converter.canRead(typeTokenOf<List<Int>>(), List::class.java, mimeType)).isTrue()
|
||||
assertThat(converter.canRead(typeTokenOf<ArrayList<Int>>(), List::class.java, mimeType)).isTrue()
|
||||
|
||||
assertThat(converter.canRead(typeTokenOf<Ordered>(), Ordered::class.java, mimeType)).isFalse()
|
||||
assertThat(converter.canRead(typeTokenOf<List<Ordered>>(), List::class.java, mimeType)).isFalse()
|
||||
}
|
||||
assertThat(converter.canRead(SerializableBean::class.java, MediaType.APPLICATION_JSON)).isFalse()
|
||||
assertThat(converter.canRead(typeTokenOf<List<Int>>(), List::class.java, MediaType.APPLICATION_JSON)).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun canWriteProtobuf() {
|
||||
for (mimeType in mediaTypes) {
|
||||
assertThat(converter.canWrite(SerializableBean::class.java, mimeType)).isTrue()
|
||||
assertThat(converter.canWrite(String::class.java, mimeType)).isTrue()
|
||||
assertThat(converter.canWrite(NotSerializableBean::class.java, mimeType)).isFalse()
|
||||
|
||||
assertThat(converter.canWrite(Map::class.java, mimeType)).isFalse()
|
||||
assertThat(converter.canWrite(typeTokenOf<Map<String, SerializableBean>>(), Map::class.java, mimeType)).isTrue()
|
||||
assertThat(converter.canWrite(List::class.java, mimeType)).isFalse()
|
||||
assertThat(converter.canWrite(typeTokenOf<List<SerializableBean>>(), List::class.java, mimeType)).isTrue()
|
||||
assertThat(converter.canWrite(Set::class.java, mimeType)).isFalse()
|
||||
assertThat(converter.canWrite(typeTokenOf<Set<SerializableBean>>(), Set::class.java, mimeType)).isTrue()
|
||||
|
||||
assertThat(converter.canWrite(typeTokenOf<List<Int>>(), List::class.java, mimeType)).isTrue()
|
||||
assertThat(converter.canWrite(typeTokenOf<ArrayList<Int>>(), List::class.java, mimeType)).isTrue()
|
||||
|
||||
assertThat(converter.canWrite(typeTokenOf<Ordered>(), Ordered::class.java, mimeType)).isFalse()
|
||||
}
|
||||
|
||||
assertThat(converter.canWrite(SerializableBean::class.java, MediaType.APPLICATION_JSON)).isFalse()
|
||||
assertThat(converter.canWrite(typeTokenOf<List<Int>>(), List::class.java, MediaType.APPLICATION_JSON)).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun readObject() {
|
||||
val serializableBeanBody = ProtoBuf.Default.encodeToByteArray(serializableBean)
|
||||
|
||||
for (mimeType in mediaTypes) {
|
||||
val inputMessage = MockHttpInputMessage(serializableBeanBody)
|
||||
inputMessage.headers.contentType = mimeType
|
||||
val result = converter.read(SerializableBean::class.java, inputMessage) as SerializableBean
|
||||
|
||||
assertThat(result.bytes).containsExactly(*serializableBean.bytes)
|
||||
assertThat(result.array).containsExactly(*serializableBean.array)
|
||||
assertThat(result.number).isEqualTo(serializableBean.number)
|
||||
assertThat(result.string).isEqualTo(serializableBean.string)
|
||||
assertThat(result.bool).isTrue()
|
||||
assertThat(result.fraction).isEqualTo(serializableBean.fraction)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun readArrayOfObjects() {
|
||||
for (mimeType in mediaTypes) {
|
||||
val inputMessage = MockHttpInputMessage(serializableBeanArrayBody)
|
||||
inputMessage.headers.contentType = mimeType
|
||||
val result = converter.read(Array<SerializableBean>::class.java, inputMessage) as Array<SerializableBean>
|
||||
|
||||
assertThat(result).hasSize(1)
|
||||
assertThat(result[0].bytes).containsExactly(*serializableBean.bytes)
|
||||
assertThat(result[0].array).containsExactly(*serializableBean.array)
|
||||
assertThat(result[0].number).isEqualTo(serializableBean.number)
|
||||
assertThat(result[0].string).isEqualTo(serializableBean.string)
|
||||
assertThat(result[0].bool).isTrue()
|
||||
assertThat(result[0].fraction).isEqualTo(serializableBean.fraction)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
@ExperimentalStdlibApi
|
||||
fun readGenericCollection() {
|
||||
for (mimeType in mediaTypes) {
|
||||
val inputMessage = MockHttpInputMessage(serializableBeanArrayBody)
|
||||
inputMessage.headers.contentType = mimeType
|
||||
val result = converter.read(typeOf<List<SerializableBean>>().javaType, null, inputMessage)
|
||||
as List<SerializableBean>
|
||||
|
||||
assertThat(result).hasSize(1)
|
||||
assertThat(result[0].bytes).containsExactly(*serializableBean.bytes)
|
||||
assertThat(result[0].array).containsExactly(*serializableBean.array)
|
||||
assertThat(result[0].number).isEqualTo(serializableBean.number)
|
||||
assertThat(result[0].string).isEqualTo(serializableBean.string)
|
||||
assertThat(result[0].bool).isTrue()
|
||||
assertThat(result[0].fraction).isEqualTo(serializableBean.fraction)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun readFailsOnInvalidProtobuf() {
|
||||
val body = """
|
||||
this is an invalid JSON document and definitely NOT a Protocol Buffer
|
||||
""".trimIndent()
|
||||
|
||||
for (mimeType in mediaTypes) {
|
||||
val inputMessage = MockHttpInputMessage(body.toByteArray(StandardCharsets.UTF_8))
|
||||
inputMessage.headers.contentType = mimeType
|
||||
assertThatExceptionOfType(HttpMessageNotReadableException::class.java).isThrownBy {
|
||||
converter.read(SerializableBean::class.java, inputMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun writeObject() {
|
||||
val outputMessage = MockHttpOutputMessage()
|
||||
|
||||
this.converter.write(serializableBean, null, outputMessage)
|
||||
|
||||
assertThat(outputMessage.headers).containsEntry("Content-Type", listOf("application/x-protobuf"))
|
||||
assertThat(outputMessage.bodyAsBytes.isNotEmpty()).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun writeObjectWithNullableProperty() {
|
||||
val outputMessage = MockHttpOutputMessage()
|
||||
val serializableBean = SerializableBean(byteArrayOf(0x1, 0x2), arrayOf("Foo", "Bar"), 42, null, true, 42.0f)
|
||||
|
||||
this.converter.write(serializableBean, null, outputMessage)
|
||||
|
||||
assertThat(outputMessage.headers).containsEntry("Content-Type", listOf("application/x-protobuf"))
|
||||
assertThat(outputMessage.bodyAsBytes.isNotEmpty()).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun writeArrayOfObjects() {
|
||||
val outputMessage = MockHttpOutputMessage()
|
||||
|
||||
this.converter.write(serializableBeanArray, null, outputMessage)
|
||||
|
||||
assertThat(outputMessage.headers).containsEntry("Content-Type", listOf("application/x-protobuf"))
|
||||
assertThat(outputMessage.bodyAsBytes.isNotEmpty()).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalStdlibApi
|
||||
fun writeGenericCollection() {
|
||||
val outputMessage = MockHttpOutputMessage()
|
||||
|
||||
this.converter.write(listOf(serializableBean), typeOf<List<SerializableBean>>().javaType, null, outputMessage)
|
||||
|
||||
assertThat(outputMessage.headers).containsEntry("Content-Type", listOf("application/x-protobuf"))
|
||||
assertThat(outputMessage.bodyAsBytes.isNotEmpty()).isTrue()
|
||||
}
|
||||
|
||||
@Serializable
|
||||
@Suppress("ArrayInDataClass")
|
||||
data class SerializableBean(
|
||||
val bytes: ByteArray,
|
||||
val array: Array<String>,
|
||||
val number: Int,
|
||||
val string: String?,
|
||||
val bool: Boolean,
|
||||
val fraction: Float,
|
||||
val serializableBean: SerializableBean? = null
|
||||
)
|
||||
|
||||
data class NotSerializableBean(val string: String)
|
||||
|
||||
open class TypeBase<T>
|
||||
|
||||
inline fun <reified T> typeTokenOf(): Type {
|
||||
val base = object : TypeBase<T>() {}
|
||||
val superType = base::class.java.genericSuperclass!!
|
||||
return (superType as ParameterizedType).actualTypeArguments.first()!!
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user