Skip to content

Commit 816cee1

Browse files
committed
Change default converters ordering
This commit adds a new withKotlinSerializationCborConverter method to HttpMessageConverters and updates DefaultHttpMessageConverters to put JSON and CBOR Kotlin Serialization converters before their Jackson/GSON/JSONB counterparts with their new default behavior that only handles classes with `@Serializable` at type or generics level. When there is no alternative converter for the same mime type, Kotlin Serialization converters handle all supported cases. Closes gh-35761
1 parent d64edc0 commit 816cee1

File tree

3 files changed

+78
-25
lines changed

3 files changed

+78
-25
lines changed

spring-web/src/main/java/org/springframework/http/converter/DefaultHttpMessageConverters.java

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
* Default implementation for {@link HttpMessageConverters}.
5151
*
5252
* @author Brian Clozel
53+
* @author Sebastien Deleuze
5354
*/
5455
@SuppressWarnings("removal")
5556
class DefaultHttpMessageConverters implements HttpMessageConverters {
@@ -122,6 +123,8 @@ abstract static class DefaultBuilder {
122123

123124
@Nullable HttpMessageConverter<?> smileConverter;
124125

126+
@Nullable HttpMessageConverter<?> kotlinCborConverter;
127+
125128
@Nullable HttpMessageConverter<?> cborConverter;
126129

127130
@Nullable HttpMessageConverter<?> yamlConverter;
@@ -187,6 +190,11 @@ void setSmileConverter(HttpMessageConverter<?> smileConverter) {
187190
this.smileConverter = smileConverter;
188191
}
189192

193+
void setKotlinSerializationCborConverter(HttpMessageConverter<?> kotlinCborConverter) {
194+
Assert.notNull(kotlinCborConverter, "kotlinCborConverter must not be null");
195+
this.kotlinCborConverter = kotlinCborConverter;
196+
}
197+
190198
void setCborConverter(HttpMessageConverter<?> cborConverter) {
191199
Assert.isTrue(cborConverter.getSupportedMediaTypes().contains(MediaType.APPLICATION_CBOR),
192200
"cborConverter should support 'application/cbor'");
@@ -230,6 +238,9 @@ List<HttpMessageConverter<?>> getCoreConverters() {
230238
if (this.smileConverter != null) {
231239
converters.add(this.smileConverter);
232240
}
241+
if (this.kotlinCborConverter != null) {
242+
converters.add(this.kotlinCborConverter);
243+
}
233244
if (this.cborConverter != null) {
234245
converters.add(this.cborConverter);
235246
}
@@ -263,7 +274,12 @@ void detectMessageConverters() {
263274
}
264275
if (this.kotlinJsonConverter == null) {
265276
if (KOTLIN_SERIALIZATION_JSON_PRESENT) {
266-
this.kotlinJsonConverter = new KotlinSerializationJsonHttpMessageConverter();
277+
if (this.jsonConverter != null || JACKSON_PRESENT || JACKSON_2_PRESENT || GSON_PRESENT || JSONB_PRESENT) {
278+
this.kotlinJsonConverter = new KotlinSerializationJsonHttpMessageConverter();
279+
}
280+
else {
281+
this.kotlinJsonConverter = new KotlinSerializationJsonHttpMessageConverter(type -> true);
282+
}
267283
}
268284
}
269285
if (this.jsonConverter == null) {
@@ -302,16 +318,23 @@ else if (JACKSON_2_SMILE_PRESENT) {
302318
}
303319
}
304320

321+
if (this.kotlinCborConverter == null) {
322+
if (KOTLIN_SERIALIZATION_CBOR_PRESENT) {
323+
if (this.cborConverter != null || JACKSON_CBOR_PRESENT || JACKSON_2_CBOR_PRESENT) {
324+
this.kotlinCborConverter = new KotlinSerializationCborHttpMessageConverter();
325+
}
326+
else {
327+
this.kotlinCborConverter = new KotlinSerializationCborHttpMessageConverter(type -> true);
328+
}
329+
}
330+
}
305331
if (this.cborConverter == null) {
306332
if (JACKSON_CBOR_PRESENT) {
307333
this.cborConverter = new JacksonCborHttpMessageConverter();
308334
}
309335
else if (JACKSON_2_CBOR_PRESENT) {
310336
this.cborConverter = new MappingJackson2CborHttpMessageConverter();
311337
}
312-
else if (KOTLIN_SERIALIZATION_CBOR_PRESENT) {
313-
this.cborConverter = new KotlinSerializationCborHttpMessageConverter();
314-
}
315338
}
316339

317340
if (this.yamlConverter == null) {
@@ -325,7 +348,7 @@ else if (JACKSON_2_YAML_PRESENT) {
325348

326349
if (this.protobufConverter == null) {
327350
if (KOTLIN_SERIALIZATION_PROTOBUF_PRESENT) {
328-
this.protobufConverter = new KotlinSerializationProtobufHttpMessageConverter();
351+
this.protobufConverter = new KotlinSerializationProtobufHttpMessageConverter(type -> true);
329352
}
330353
}
331354

@@ -379,6 +402,12 @@ public ClientBuilder withSmileConverter(HttpMessageConverter<?> smileConverter)
379402
return this;
380403
}
381404

405+
@Override
406+
public ClientBuilder withKotlinSerializationCborConverter(HttpMessageConverter<?> kotlinSerializationCborConverter) {
407+
setKotlinSerializationCborConverter(kotlinSerializationCborConverter);
408+
return this;
409+
}
410+
382411
@Override
383412
public ClientBuilder withCborConverter(HttpMessageConverter<?> cborConverter) {
384413
setCborConverter(cborConverter);
@@ -470,6 +499,12 @@ public ServerBuilder withSmileConverter(HttpMessageConverter<?> smileConverter)
470499
return this;
471500
}
472501

502+
@Override
503+
public ServerBuilder withKotlinSerializationCborConverter(HttpMessageConverter<?> kotlinSerializationCborConverter) {
504+
setKotlinSerializationCborConverter(kotlinSerializationCborConverter);
505+
return this;
506+
}
507+
473508
@Override
474509
public ServerBuilder withCborConverter(HttpMessageConverter<?> cborConverter) {
475510
setCborConverter(cborConverter);

spring-web/src/main/java/org/springframework/http/converter/HttpMessageConverters.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
* Finally, {@link Builder#configureMessageConverters(Consumer) default and custom converters can be configured}.
2828
*
2929
* @author Brian Clozel
30+
* @author Sebastien Deleuze
3031
* @since 7.0
3132
*/
3233
public interface HttpMessageConverters extends Iterable<HttpMessageConverter<?>> {
@@ -40,9 +41,10 @@ public interface HttpMessageConverters extends Iterable<HttpMessageConverter<?>>
4041
* <li>{@link StringHttpMessageConverter} with the {@link java.nio.charset.StandardCharsets#ISO_8859_1} charset
4142
* <li>{@link ResourceHttpMessageConverter}, with resource streaming support disabled
4243
* <li>a Multipart converter, using all detected and custom converters for part conversion
43-
* <li>A Kotlin Serialization converter
44+
* <li>A Kotlin Serialization JSON converter
4445
* <li>A JSON converter
4546
* <li>A Smile converter
47+
* <li>A Kotlin Serialization CBOR converter
4648
* <li>A CBOR converter
4749
* <li>A YAML converter
4850
* <li>An XML converter
@@ -63,9 +65,10 @@ static ClientBuilder forClient() {
6365
* <li>{@link StringHttpMessageConverter} with the {@link java.nio.charset.StandardCharsets#ISO_8859_1} charset
6466
* <li>{@link ResourceHttpMessageConverter}
6567
* <li>{@link ResourceRegionHttpMessageConverter}
66-
* <li>A Kotlin Serialization converter
68+
* <li>A Kotlin Serialization JSON converter
6769
* <li>A JSON converter
6870
* <li>A Smile converter
71+
* <li>A Kotlin Serialization CBOR converter
6972
* <li>A CBOR converter
7073
* <li>A YAML converter
7174
* <li>An XML converter
@@ -128,6 +131,14 @@ interface Builder<T extends Builder<T>> {
128131
*/
129132
T withSmileConverter(HttpMessageConverter<?> smileMessageConverter);
130133

134+
/**
135+
* Override the default String {@code HttpMessageConverter}
136+
* with any converter supporting the Kotlin Serialization conversion for CBOR.
137+
* @param kotlinSerializationConverter the converter instance to use
138+
* @see org.springframework.http.converter.cbor.KotlinSerializationCborHttpMessageConverter
139+
*/
140+
T withKotlinSerializationCborConverter(HttpMessageConverter<?> kotlinSerializationConverter);
141+
131142
/**
132143
* Override the default Jackson 3.x CBOR {@code HttpMessageConverter}
133144
* with any converter supporting the CBOR format.

spring-web/src/test/java/org/springframework/http/converter/DefaultHttpMessageConvertersTests.java

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.springframework.http.HttpInputMessage;
2929
import org.springframework.http.HttpOutputMessage;
3030
import org.springframework.http.converter.cbor.JacksonCborHttpMessageConverter;
31+
import org.springframework.http.converter.cbor.KotlinSerializationCborHttpMessageConverter;
3132
import org.springframework.http.converter.feed.AtomFeedHttpMessageConverter;
3233
import org.springframework.http.converter.feed.RssChannelHttpMessageConverter;
3334
import org.springframework.http.converter.json.JacksonJsonHttpMessageConverter;
@@ -113,9 +114,10 @@ void defaultConverters() {
113114
StringHttpMessageConverter.class, ResourceHttpMessageConverter.class,
114115
AllEncompassingFormHttpMessageConverter.class, KotlinSerializationJsonHttpMessageConverter.class,
115116
JacksonJsonHttpMessageConverter.class, JacksonSmileHttpMessageConverter.class,
116-
JacksonCborHttpMessageConverter.class, JacksonYamlHttpMessageConverter.class,
117-
JacksonXmlHttpMessageConverter.class, KotlinSerializationProtobufHttpMessageConverter.class,
118-
AtomFeedHttpMessageConverter.class, RssChannelHttpMessageConverter.class);
117+
KotlinSerializationCborHttpMessageConverter.class, JacksonCborHttpMessageConverter.class,
118+
JacksonYamlHttpMessageConverter.class, JacksonXmlHttpMessageConverter.class,
119+
KotlinSerializationProtobufHttpMessageConverter.class, AtomFeedHttpMessageConverter.class,
120+
RssChannelHttpMessageConverter.class);
119121
}
120122

121123
@Test
@@ -127,9 +129,10 @@ void multipartConverterContainsOtherConverters() {
127129
ByteArrayHttpMessageConverter.class, StringHttpMessageConverter.class,
128130
ResourceHttpMessageConverter.class, KotlinSerializationJsonHttpMessageConverter.class,
129131
JacksonJsonHttpMessageConverter.class, JacksonSmileHttpMessageConverter.class,
130-
JacksonCborHttpMessageConverter.class, JacksonYamlHttpMessageConverter.class,
131-
JacksonXmlHttpMessageConverter.class, KotlinSerializationProtobufHttpMessageConverter.class,
132-
AtomFeedHttpMessageConverter.class, RssChannelHttpMessageConverter.class);
132+
KotlinSerializationCborHttpMessageConverter.class, JacksonCborHttpMessageConverter.class,
133+
JacksonYamlHttpMessageConverter.class, JacksonXmlHttpMessageConverter.class,
134+
KotlinSerializationProtobufHttpMessageConverter.class, AtomFeedHttpMessageConverter.class,
135+
RssChannelHttpMessageConverter.class);
133136
}
134137

135138
@Test
@@ -148,9 +151,10 @@ void registerCustomMessageConverterAheadOfDefaults() {
148151
StringHttpMessageConverter.class, ResourceHttpMessageConverter.class,
149152
AllEncompassingFormHttpMessageConverter.class, KotlinSerializationJsonHttpMessageConverter.class,
150153
JacksonJsonHttpMessageConverter.class, JacksonSmileHttpMessageConverter.class,
151-
JacksonCborHttpMessageConverter.class, JacksonYamlHttpMessageConverter.class,
152-
JacksonXmlHttpMessageConverter.class, KotlinSerializationProtobufHttpMessageConverter.class,
153-
AtomFeedHttpMessageConverter.class, RssChannelHttpMessageConverter.class);
154+
KotlinSerializationCborHttpMessageConverter.class, JacksonCborHttpMessageConverter.class,
155+
JacksonYamlHttpMessageConverter.class, JacksonXmlHttpMessageConverter.class,
156+
KotlinSerializationProtobufHttpMessageConverter.class, AtomFeedHttpMessageConverter.class,
157+
RssChannelHttpMessageConverter.class);
154158
}
155159

156160
@Test
@@ -216,9 +220,10 @@ void defaultConverters() {
216220
ResourceHttpMessageConverter.class, ResourceRegionHttpMessageConverter.class,
217221
AllEncompassingFormHttpMessageConverter.class, KotlinSerializationJsonHttpMessageConverter.class,
218222
JacksonJsonHttpMessageConverter.class, JacksonSmileHttpMessageConverter.class,
219-
JacksonCborHttpMessageConverter.class, JacksonYamlHttpMessageConverter.class,
220-
JacksonXmlHttpMessageConverter.class, KotlinSerializationProtobufHttpMessageConverter.class,
221-
AtomFeedHttpMessageConverter.class, RssChannelHttpMessageConverter.class);
223+
KotlinSerializationCborHttpMessageConverter.class, JacksonCborHttpMessageConverter.class,
224+
JacksonYamlHttpMessageConverter.class, JacksonXmlHttpMessageConverter.class,
225+
KotlinSerializationProtobufHttpMessageConverter.class, AtomFeedHttpMessageConverter.class,
226+
RssChannelHttpMessageConverter.class);
222227
}
223228

224229
@Test
@@ -230,9 +235,10 @@ void multipartConverterContainsOtherConverters() {
230235
ByteArrayHttpMessageConverter.class, StringHttpMessageConverter.class,
231236
ResourceHttpMessageConverter.class, KotlinSerializationJsonHttpMessageConverter.class,
232237
JacksonJsonHttpMessageConverter.class, JacksonSmileHttpMessageConverter.class,
233-
JacksonCborHttpMessageConverter.class, JacksonYamlHttpMessageConverter.class,
234-
JacksonXmlHttpMessageConverter.class, KotlinSerializationProtobufHttpMessageConverter.class,
235-
AtomFeedHttpMessageConverter.class, RssChannelHttpMessageConverter.class);
238+
KotlinSerializationCborHttpMessageConverter.class, JacksonCborHttpMessageConverter.class,
239+
JacksonYamlHttpMessageConverter.class, JacksonXmlHttpMessageConverter.class,
240+
KotlinSerializationProtobufHttpMessageConverter.class, AtomFeedHttpMessageConverter.class,
241+
RssChannelHttpMessageConverter.class);
236242
}
237243

238244
@Test
@@ -252,9 +258,10 @@ void registerCustomMessageConverterAheadOfDefaults() {
252258
ResourceHttpMessageConverter.class, ResourceRegionHttpMessageConverter.class,
253259
AllEncompassingFormHttpMessageConverter.class, KotlinSerializationJsonHttpMessageConverter.class,
254260
JacksonJsonHttpMessageConverter.class, JacksonSmileHttpMessageConverter.class,
255-
JacksonCborHttpMessageConverter.class, JacksonYamlHttpMessageConverter.class,
256-
JacksonXmlHttpMessageConverter.class, KotlinSerializationProtobufHttpMessageConverter.class,
257-
AtomFeedHttpMessageConverter.class, RssChannelHttpMessageConverter.class);
261+
KotlinSerializationCborHttpMessageConverter.class, JacksonCborHttpMessageConverter.class,
262+
JacksonYamlHttpMessageConverter.class, JacksonXmlHttpMessageConverter.class,
263+
KotlinSerializationProtobufHttpMessageConverter.class, AtomFeedHttpMessageConverter.class,
264+
RssChannelHttpMessageConverter.class);
258265
}
259266

260267
@Test

0 commit comments

Comments
 (0)