Skip to content

Commit 4f38079

Browse files
committed
Throw proper DecodingException in Kotlin Serialization decoders
Closes gh-33138
1 parent 3008d97 commit 4f38079

File tree

4 files changed

+72
-6
lines changed

4 files changed

+72
-6
lines changed

spring-web/src/main/java/org/springframework/http/codec/KotlinSerializationBinaryDecoder.java

+10-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -109,7 +109,15 @@ public Mono<Object> decodeToMono(Publisher<DataBuffer> inputStream, ResolvableTy
109109
}
110110
return this.byteArrayDecoder
111111
.decodeToMono(inputStream, elementType, mimeType, hints)
112-
.map(byteArray -> format().decodeFromByteArray(serializer, byteArray));
112+
.handle((byteArray, sink) -> {
113+
try {
114+
sink.next(format().decodeFromByteArray(serializer, byteArray));
115+
sink.complete();
116+
}
117+
catch (IllegalArgumentException ex) {
118+
sink.error(new DecodingException("Decoding error: " + ex.getMessage(), ex));
119+
}
120+
});
113121
});
114122
}
115123

spring-web/src/main/java/org/springframework/http/codec/KotlinSerializationStringDecoder.java

+22-2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import reactor.core.publisher.Mono;
2727

2828
import org.springframework.core.ResolvableType;
29+
import org.springframework.core.codec.CodecException;
2930
import org.springframework.core.codec.Decoder;
3031
import org.springframework.core.codec.DecodingException;
3132
import org.springframework.core.codec.StringDecoder;
@@ -101,7 +102,14 @@ public Flux<Object> decode(Publisher<DataBuffer> inputStream, ResolvableType ele
101102
}
102103
return this.stringDecoder
103104
.decode(inputStream, elementType, mimeType, hints)
104-
.map(string -> format().decodeFromString(serializer, string));
105+
.handle((string, sink) -> {
106+
try {
107+
sink.next(format().decodeFromString(serializer, string));
108+
}
109+
catch (IllegalArgumentException ex) {
110+
sink.error(processException(ex));
111+
}
112+
});
105113
});
106114
}
107115

@@ -115,8 +123,20 @@ public Mono<Object> decodeToMono(Publisher<DataBuffer> inputStream, ResolvableTy
115123
}
116124
return this.stringDecoder
117125
.decodeToMono(inputStream, elementType, mimeType, hints)
118-
.map(string -> format().decodeFromString(serializer, string));
126+
.handle((string, sink) -> {
127+
try {
128+
sink.next(format().decodeFromString(serializer, string));
129+
sink.complete();
130+
}
131+
catch (IllegalArgumentException ex) {
132+
sink.error(processException(ex));
133+
}
134+
});
119135
});
120136
}
121137

138+
private CodecException processException(IllegalArgumentException ex) {
139+
return new DecodingException("Decoding error: " + ex.getMessage(), ex);
140+
}
141+
122142
}

spring-web/src/test/kotlin/org/springframework/http/codec/json/KotlinSerializationJsonDecoderTests.kt

+24-2
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,13 @@ import org.assertj.core.api.Assertions.assertThat
2121
import org.junit.jupiter.api.Test
2222
import org.springframework.core.Ordered
2323
import org.springframework.core.ResolvableType
24+
import org.springframework.core.codec.DecodingException
2425
import org.springframework.core.io.buffer.DataBuffer
2526
import org.springframework.core.testfixture.codec.AbstractDecoderTests
2627
import org.springframework.http.MediaType
2728
import reactor.core.publisher.Flux
2829
import reactor.core.publisher.Mono
29-
import reactor.test.StepVerifier
3030
import reactor.test.StepVerifier.FirstStep
31-
import java.lang.UnsupportedOperationException
3231
import java.math.BigDecimal
3332
import java.nio.charset.Charset
3433
import java.nio.charset.StandardCharsets
@@ -82,6 +81,29 @@ class KotlinSerializationJsonDecoderTests : AbstractDecoderTests<KotlinSerializa
8281
}, null, null)
8382
}
8483

84+
@Test
85+
fun decodeWithUnexpectedFormat() {
86+
val input = Flux.concat(
87+
stringBuffer("{\"ba\":\"b1\",\"fo\":\"f1\"}\n"),
88+
)
89+
90+
testDecode(input, ResolvableType.forClass(Pojo::class.java), { step: FirstStep<Pojo> ->
91+
step
92+
.expectError(DecodingException::class.java)
93+
.verify() }, null, null)
94+
}
95+
96+
@Test
97+
fun decodeToMonoWithUnexpectedFormat() {
98+
val input = Flux.concat(
99+
stringBuffer("{\"ba\":\"b1\",\"fo\":\"f1\"}\n"),
100+
)
101+
102+
testDecodeToMono(input, ResolvableType.forClass(Pojo::class.java), { step: FirstStep<Pojo> ->
103+
step.expectError(DecodingException::class.java)
104+
.verify() }, null, null)
105+
}
106+
85107
@Test
86108
fun decodeStreamWithSingleBuffer() {
87109
val input = Flux.concat(

spring-web/src/test/kotlin/org/springframework/http/codec/protobuf/KotlinSerializationProtobufDecoderTests.kt

+16
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import org.assertj.core.api.Assertions.assertThat
2424
import org.junit.jupiter.api.Test
2525
import org.springframework.core.Ordered
2626
import org.springframework.core.ResolvableType
27+
import org.springframework.core.codec.DecodingException
2728
import org.springframework.core.io.buffer.DataBuffer
2829
import org.springframework.core.testfixture.codec.AbstractDecoderTests
2930
import org.springframework.http.MediaType
@@ -86,6 +87,21 @@ class KotlinSerializationProtobufDecoderTests : AbstractDecoderTests<KotlinSeria
8687
}, null, null)
8788
}
8889

90+
@Test
91+
fun decodeToMonoWithUnexpectedFormat() {
92+
val input = Mono.just(
93+
bufferFactory.allocateBuffer(0),
94+
)
95+
96+
val elementType = ResolvableType.forClass(Pojo::class.java)
97+
98+
testDecodeToMono(input, elementType, { step: FirstStep<Any> ->
99+
step
100+
.expectError(DecodingException::class.java)
101+
.verify()
102+
}, null, null)
103+
}
104+
89105
private fun byteBuffer(value: Any): Mono<DataBuffer> {
90106
return Mono.defer {
91107
val bytes = ProtoBuf.Default.encodeToByteArray(serializer(Pojo::class.java), value)

0 commit comments

Comments
 (0)