Use JsonMapper instead of ObjectMapper when relevant

This commit updates Jackson 3 JSON support to use JsonMapper
instead of ObjectMapper in converters, codecs and view constructors.

As a consequence, AbstractJacksonDecoder, AbstractJacksonEncoder,
AbstractJacksonHttpMessageConverter and JacksonCodecSupport are
now parameterized with <T extends ObjectMapper>.

Closes gh-35282
This commit is contained in:
Sébastien Deleuze
2025-08-12 10:18:49 +02:00
parent 8f4107953d
commit dc26aaa0ec
34 changed files with 221 additions and 230 deletions
@@ -31,7 +31,6 @@ import reactor.test.StepVerifier;
import tools.jackson.core.JsonParser;
import tools.jackson.databind.DeserializationContext;
import tools.jackson.databind.JsonNode;
import tools.jackson.databind.ObjectMapper;
import tools.jackson.databind.annotation.JsonDeserialize;
import tools.jackson.databind.deser.std.StdDeserializer;
import tools.jackson.databind.json.JsonMapper;
@@ -101,9 +100,9 @@ class JacksonJsonDecoderTests extends AbstractDecoderTests<JacksonJsonDecoder> {
assertThat(decoder.canDecode(ResolvableType.forClass(Pojo.class), halFormsJsonMediaType)).isTrue();
assertThat(decoder.canDecode(ResolvableType.forClass(Map.class), MediaType.APPLICATION_JSON)).isTrue();
decoder.registerObjectMappersForType(Pojo.class, map -> {
map.put(halJsonMediaType, new ObjectMapper());
map.put(MediaType.APPLICATION_JSON, new ObjectMapper());
decoder.registerMappersForType(Pojo.class, map -> {
map.put(halJsonMediaType, new JsonMapper());
map.put(MediaType.APPLICATION_JSON, new JsonMapper());
});
assertThat(decoder.canDecode(ResolvableType.forClass(Pojo.class), halJsonMediaType)).isTrue();
@@ -115,7 +114,7 @@ class JacksonJsonDecoderTests extends AbstractDecoderTests<JacksonJsonDecoder> {
@Test // SPR-15866
void canDecodeWithProvidedMimeType() {
MimeType textJavascript = new MimeType("text", "javascript", StandardCharsets.UTF_8);
JacksonJsonDecoder decoder = new JacksonJsonDecoder(new ObjectMapper(), textJavascript);
JacksonJsonDecoder decoder = new JacksonJsonDecoder(new JsonMapper(), textJavascript);
assertThat(decoder.getDecodableMimeTypes()).isEqualTo(Collections.singletonList(textJavascript));
}
@@ -124,7 +123,7 @@ class JacksonJsonDecoderTests extends AbstractDecoderTests<JacksonJsonDecoder> {
@SuppressWarnings("unchecked")
void decodableMimeTypesIsImmutable() {
MimeType textJavascript = new MimeType("text", "javascript", StandardCharsets.UTF_8);
JacksonJsonDecoder decoder = new JacksonJsonDecoder(new ObjectMapper(), textJavascript);
JacksonJsonDecoder decoder = new JacksonJsonDecoder(new JsonMapper(), textJavascript);
assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() ->
decoder.getDecodableMimeTypes().add(new MimeType("text", "ecmascript")));
@@ -135,8 +134,8 @@ class JacksonJsonDecoderTests extends AbstractDecoderTests<JacksonJsonDecoder> {
MimeType mimeType1 = MediaType.parseMediaType("application/hal+json");
MimeType mimeType2 = new MimeType("text", "javascript", StandardCharsets.UTF_8);
JacksonJsonDecoder decoder = new JacksonJsonDecoder(new ObjectMapper(), mimeType2);
decoder.registerObjectMappersForType(Pojo.class, map -> map.put(mimeType1, new ObjectMapper()));
JacksonJsonDecoder decoder = new JacksonJsonDecoder(new JsonMapper(), mimeType2);
decoder.registerMappersForType(Pojo.class, map -> map.put(mimeType1, new JsonMapper()));
assertThat(decoder.getDecodableMimeTypes(ResolvableType.forClass(Pojo.class)))
.containsExactly(mimeType1);
@@ -28,7 +28,6 @@ import org.junit.jupiter.api.Test;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import tools.jackson.databind.ObjectMapper;
import tools.jackson.databind.SerializationFeature;
import tools.jackson.databind.json.JsonMapper;
@@ -109,7 +108,7 @@ class JacksonJsonEncoderTests extends AbstractEncoderTests<JacksonJsonEncoder> {
@Test // SPR-15866
public void canEncodeWithCustomMimeType() {
MimeType textJavascript = new MimeType("text", "javascript", StandardCharsets.UTF_8);
JacksonJsonEncoder encoder = new JacksonJsonEncoder(new ObjectMapper(), textJavascript);
JacksonJsonEncoder encoder = new JacksonJsonEncoder(new JsonMapper(), textJavascript);
assertThat(encoder.getEncodableMimeTypes()).isEqualTo(Collections.singletonList(textJavascript));
}
@@ -117,7 +116,7 @@ class JacksonJsonEncoderTests extends AbstractEncoderTests<JacksonJsonEncoder> {
@Test
void encodableMimeTypesIsImmutable() {
MimeType textJavascript = new MimeType("text", "javascript", StandardCharsets.UTF_8);
JacksonJsonEncoder encoder = new JacksonJsonEncoder(new ObjectMapper(), textJavascript);
JacksonJsonEncoder encoder = new JacksonJsonEncoder(new JsonMapper(), textJavascript);
assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() ->
encoder.getEncodableMimeTypes().add(new MimeType("text", "ecmascript")));
@@ -231,7 +230,7 @@ class JacksonJsonEncoderTests extends AbstractEncoderTests<JacksonJsonEncoder> {
@Test // gh-22771
public void encodeWithFlushAfterWriteOff() {
ObjectMapper mapper = JsonMapper.builder().configure(SerializationFeature.FLUSH_AFTER_WRITE_VALUE, false).build();
JsonMapper mapper = JsonMapper.builder().configure(SerializationFeature.FLUSH_AFTER_WRITE_VALUE, false).build();
JacksonJsonEncoder encoder = new JacksonJsonEncoder(mapper);
Flux<DataBuffer> result = encoder.encode(Flux.just(new Pojo("foo", "bar")), this.bufferFactory,
@@ -87,9 +87,9 @@ class JacksonJsonHttpMessageConverterTests {
assertThat(converter.canRead(MyBean.class, halFormsJsonMediaType)).isTrue();
assertThat(converter.canRead(Map.class, MediaType.APPLICATION_JSON)).isTrue();
converter.registerObjectMappersForType(MyBean.class, map -> {
map.put(halJsonMediaType, new ObjectMapper());
map.put(MediaType.APPLICATION_JSON, new ObjectMapper());
converter.registerMappersForType(MyBean.class, map -> {
map.put(halJsonMediaType, new JsonMapper());
map.put(MediaType.APPLICATION_JSON, new JsonMapper());
});
assertThat(converter.canRead(MyBean.class, halJsonMediaType)).isTrue();
@@ -121,9 +121,9 @@ class JacksonJsonHttpMessageConverterTests {
assertThat(converter.getSupportedMediaTypes(MyBean.class)).containsExactly(defaultMediaTypes);
MediaType halJson = MediaType.parseMediaType("application/hal+json");
converter.registerObjectMappersForType(MyBean.class, map -> {
map.put(halJson, new ObjectMapper());
map.put(MediaType.APPLICATION_JSON, new ObjectMapper());
converter.registerMappersForType(MyBean.class, map -> {
map.put(halJson, new JsonMapper());
map.put(MediaType.APPLICATION_JSON, new JsonMapper());
});
assertThat(converter.getSupportedMediaTypes(MyBean.class)).containsExactly(halJson, MediaType.APPLICATION_JSON);
@@ -365,7 +365,7 @@ class JacksonJsonHttpMessageConverterTests {
PrettyPrintBean bean = new PrettyPrintBean();
bean.setName("Jason");
ObjectMapper mapper = JsonMapper.builder().enable(SerializationFeature.INDENT_OUTPUT).build();
JsonMapper mapper = JsonMapper.builder().enable(SerializationFeature.INDENT_OUTPUT).build();
this.converter = new JacksonJsonHttpMessageConverter(mapper);
this.converter.write(bean, ResolvableType.forType(PrettyPrintBean.class),
MediaType.APPLICATION_JSON, outputMessage, null);
@@ -384,7 +384,7 @@ class JacksonJsonHttpMessageConverterTests {
PrettyPrintBean bean = new PrettyPrintBean();
bean.setName("Jason");
ObjectMapper mapper = JsonMapper.builder().enable(SerializationFeature.INDENT_OUTPUT).build();
JsonMapper mapper = JsonMapper.builder().enable(SerializationFeature.INDENT_OUTPUT).build();
this.converter = new JacksonJsonHttpMessageConverter(mapper);
this.converter.write(bean, ResolvableType.forType(PrettyPrintBean.class),
MediaType.APPLICATION_JSON, outputMessage, null);