Introduce Jackson 3 support for converters

This commit introduces Jackson 3 SmartHttpMessageConverter based
variants of the following Jackson 2 classes (and related dependent classes).

org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter ->
org.springframework.http.converter.AbstractJacksonHttpMessageConverter

MappingJackson2HttpMessageConverter -> JacksonJsonHttpMessageConverter
MappingJackson2SmileHttpMessageConverter -> JacksonSmileHttpMessageConverter
MappingJackson2CborHttpMessageConverter -> JacksonCborHttpMessageConverter
MappingJackson2XmlHttpMessageConverter -> JacksonXmlHttpMessageConverter
MappingJackson2YamlHttpMessageConverter -> JacksonYamlHttpMessageConverter

They use hints instead of MappingJacksonValue and MappingJacksonInputMessage
to support `@JsonView` and FilterProvider.

Jackson 3 support is configured if found in the classpath otherwise
fallback to Jackson 2.

JacksonHandlerInstantiator needs to be enabled explicitly if needed.

See gh-33798
This commit is contained in:
Sébastien Deleuze
2025-05-13 12:38:18 +02:00
parent 7a8db31dc3
commit d4e4a9ae06
23 changed files with 3028 additions and 86 deletions

View File

@@ -50,7 +50,7 @@ import org.springframework.context.MessageSourceResolvable;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.http.MediaType;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.json.JacksonJsonHttpMessageConverter;
import org.springframework.validation.Errors;
import org.springframework.validation.ObjectError;
import org.springframework.validation.Validator;
@@ -138,7 +138,7 @@ class MethodValidationTests {
handlerAdapter.setApplicationContext(context);
handlerAdapter.setBeanFactory(context.getBeanFactory());
handlerAdapter.setMessageConverters(
List.of(new StringHttpMessageConverter(), new MappingJackson2HttpMessageConverter()));
List.of(new StringHttpMessageConverter(), new JacksonJsonHttpMessageConverter()));
handlerAdapter.afterPropertiesSet();
return handlerAdapter;
}

View File

@@ -28,12 +28,13 @@ import java.util.List;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeName;
import com.fasterxml.jackson.annotation.JsonView;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.skyscreamer.jsonassert.JSONAssert;
import org.xmlunit.assertj.XmlAssert;
import tools.jackson.databind.SerializationFeature;
import tools.jackson.databind.json.JsonMapper;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.target.SingletonTargetSource;
@@ -51,8 +52,10 @@ import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.ResourceHttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.JacksonJsonHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter;
import org.springframework.http.converter.xml.JacksonXmlHttpMessageConverter;
import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
import org.springframework.util.MultiValueMap;
import org.springframework.util.ReflectionUtils;
@@ -69,8 +72,6 @@ import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
import org.springframework.web.testfixture.servlet.MockHttpServletResponse;
import org.springframework.web.util.WebUtils;
@@ -116,7 +117,7 @@ class RequestResponseBodyMethodProcessorTests {
this.servletRequest.setContent(content.getBytes(StandardCharsets.UTF_8));
this.servletRequest.setContentType(MediaType.APPLICATION_JSON_VALUE);
List<HttpMessageConverter<?>> converters = List.of(new MappingJackson2HttpMessageConverter());
List<HttpMessageConverter<?>> converters = List.of(new JacksonJsonHttpMessageConverter());
RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters);
@SuppressWarnings("unchecked")
@@ -151,7 +152,7 @@ class RequestResponseBodyMethodProcessorTests {
this.servletRequest.setContent(content.getBytes(StandardCharsets.UTF_8));
this.servletRequest.setContentType("application/json");
List<HttpMessageConverter<?>> converters = List.of(new MappingJackson2HttpMessageConverter());
List<HttpMessageConverter<?>> converters = List.of(new JacksonJsonHttpMessageConverter());
RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters);
SimpleBean result = (SimpleBean) processor.resolveArgument(
@@ -207,7 +208,7 @@ class RequestResponseBodyMethodProcessorTests {
this.servletRequest.setContent(content.getBytes(StandardCharsets.UTF_8));
this.servletRequest.setContentType(MediaType.APPLICATION_JSON_VALUE);
List<HttpMessageConverter<?>> converters = List.of(new MappingJackson2HttpMessageConverter());
List<HttpMessageConverter<?>> converters = List.of(new JacksonJsonHttpMessageConverter());
RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters);
SimpleBean result = (SimpleBean) processor.resolveArgument(methodParam, container, request, factory);
@@ -226,7 +227,7 @@ class RequestResponseBodyMethodProcessorTests {
this.servletRequest.setContent(content.getBytes(StandardCharsets.UTF_8));
this.servletRequest.setContentType(MediaType.APPLICATION_JSON_VALUE);
List<HttpMessageConverter<?>> converters = List.of(new MappingJackson2HttpMessageConverter());
List<HttpMessageConverter<?>> converters = List.of(new JacksonJsonHttpMessageConverter());
RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters);
@SuppressWarnings("unchecked")
@@ -246,7 +247,7 @@ class RequestResponseBodyMethodProcessorTests {
this.servletRequest.setContent(content.getBytes(StandardCharsets.UTF_8));
this.servletRequest.setContentType(MediaType.APPLICATION_JSON_VALUE);
HttpMessageConverter<Object> target = new MappingJackson2HttpMessageConverter();
HttpMessageConverter<Object> target = new JacksonJsonHttpMessageConverter();
HttpMessageConverter<?> proxy = ProxyFactory.getProxy(HttpMessageConverter.class, new SingletonTargetSource(target));
List<HttpMessageConverter<?>> converters = List.of(proxy);
RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters);
@@ -262,7 +263,7 @@ class RequestResponseBodyMethodProcessorTests {
this.servletRequest.addHeader("Accept", "text/plain; q=0.5, application/json");
List<HttpMessageConverter<?>> converters =
List.of(new MappingJackson2HttpMessageConverter(), new StringHttpMessageConverter());
List.of(new JacksonJsonHttpMessageConverter(), new StringHttpMessageConverter());
RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters);
processor.writeWithMessageConverters("Foo", returnTypeString, request);
@@ -331,15 +332,14 @@ class RequestResponseBodyMethodProcessorTests {
this.servletRequest.addHeader("Accept", halFormsMediaType + "," + halMediaType);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(SerializationFeature.INDENT_OUTPUT, true);
JsonMapper mapper = JsonMapper.builder().enable(SerializationFeature.INDENT_OUTPUT).build();
SimpleBean simpleBean = new SimpleBean();
simpleBean.setId(12L);
simpleBean.setName("Jason");
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.registerObjectMappersForType(SimpleBean.class, map -> map.put(halMediaType, objectMapper));
JacksonJsonHttpMessageConverter converter = new JacksonJsonHttpMessageConverter();
converter.registerObjectMappersForType(SimpleBean.class, map -> map.put(halMediaType, mapper));
RequestResponseBodyMethodProcessor processor =
new RequestResponseBodyMethodProcessor(List.of(converter));
MethodParameter returnType = new MethodParameter(getClass().getDeclaredMethod("getSimpleBean"), -1);
@@ -380,7 +380,7 @@ class RequestResponseBodyMethodProcessorTests {
RequestResponseBodyMethodProcessor processor =
new RequestResponseBodyMethodProcessor(List.of(
new MappingJackson2HttpMessageConverter(), new MappingJackson2XmlHttpMessageConverter()));
new JacksonJsonHttpMessageConverter(), new JacksonXmlHttpMessageConverter()));
MethodParameter returnType =
new MethodParameter(getClass().getDeclaredMethod("handleAndReturnProblemDetail"), -1);
@@ -393,10 +393,10 @@ class RequestResponseBodyMethodProcessorTests {
if (expectedContentType.equals(MediaType.APPLICATION_PROBLEM_XML_VALUE)) {
XmlAssert.assertThat(this.servletResponse.getContentAsString()).and("""
<problem xmlns="urn:ietf:rfc:7807">
<type>about:blank</type>
<title>Bad Request</title>
<status>400</status>
<instance>/path</instance>
<title>Bad Request</title>
<type>about:blank</type>
</problem>""")
.ignoreWhitespace()
.areIdentical();
@@ -413,6 +413,7 @@ class RequestResponseBodyMethodProcessorTests {
}
@Test
@Disabled("https://github.com/FasterXML/jackson-dataformat-xml/issues/757")
void problemDetailWhenProblemXmlRequested() throws Exception {
this.servletRequest.addHeader("Accept", MediaType.APPLICATION_PROBLEM_XML_VALUE);
testProblemDetailMediaType(MediaType.APPLICATION_PROBLEM_XML_VALUE);
@@ -504,6 +505,25 @@ class RequestResponseBodyMethodProcessorTests {
HandlerMethod handlerMethod = new HandlerMethod(new JacksonController(), method);
MethodParameter methodReturnType = handlerMethod.getReturnType();
List<HttpMessageConverter<?>> converters = List.of(new JacksonJsonHttpMessageConverter());
RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(
converters, null, List.of(new JsonViewResponseBodyAdvice()));
Object returnValue = new JacksonController().handleResponseBody();
processor.handleReturnValue(returnValue, methodReturnType, this.container, this.request);
assertThat(this.servletResponse.getContentAsString())
.doesNotContain("\"withView1\":\"with\"")
.contains("\"withView2\":\"with\"")
.doesNotContain("\"withoutView\":\"without\"");
}
@Test
void jackson2JsonViewWithResponseBodyAndJsonMessageConverter() throws Exception {
Method method = JacksonController.class.getMethod("handleResponseBody");
HandlerMethod handlerMethod = new HandlerMethod(new JacksonController(), method);
MethodParameter methodReturnType = handlerMethod.getReturnType();
List<HttpMessageConverter<?>> converters = List.of(new MappingJackson2HttpMessageConverter());
RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(
converters, null, List.of(new JsonViewResponseBodyAdvice()));
@@ -523,6 +543,25 @@ class RequestResponseBodyMethodProcessorTests {
HandlerMethod handlerMethod = new HandlerMethod(new JacksonController(), method);
MethodParameter methodReturnType = handlerMethod.getReturnType();
List<HttpMessageConverter<?>> converters = List.of(new JacksonJsonHttpMessageConverter());
HttpEntityMethodProcessor processor = new HttpEntityMethodProcessor(
converters, null, List.of(new JsonViewResponseBodyAdvice()));
Object returnValue = new JacksonController().handleResponseEntity();
processor.handleReturnValue(returnValue, methodReturnType, this.container, this.request);
assertThat(this.servletResponse.getContentAsString())
.doesNotContain("\"withView1\":\"with\"")
.contains("\"withView2\":\"with\"")
.doesNotContain("\"withoutView\":\"without\"");
}
@Test
void jackson2JsonViewWithResponseEntityAndJsonMessageConverter() throws Exception {
Method method = JacksonController.class.getMethod("handleResponseEntity");
HandlerMethod handlerMethod = new HandlerMethod(new JacksonController(), method);
MethodParameter methodReturnType = handlerMethod.getReturnType();
List<HttpMessageConverter<?>> converters = List.of(new MappingJackson2HttpMessageConverter());
HttpEntityMethodProcessor processor = new HttpEntityMethodProcessor(
converters, null, List.of(new JsonViewResponseBodyAdvice()));
@@ -536,12 +575,31 @@ class RequestResponseBodyMethodProcessorTests {
.doesNotContain("\"withoutView\":\"without\"");
}
@Test // SPR-12149
@Test
void jacksonJsonViewWithResponseBodyAndXmlMessageConverter() throws Exception {
Method method = JacksonController.class.getMethod("handleResponseBody");
HandlerMethod handlerMethod = new HandlerMethod(new JacksonController(), method);
MethodParameter methodReturnType = handlerMethod.getReturnType();
List<HttpMessageConverter<?>> converters = List.of(new JacksonXmlHttpMessageConverter());
RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(
converters, null, List.of(new JsonViewResponseBodyAdvice()));
Object returnValue = new JacksonController().handleResponseBody();
processor.handleReturnValue(returnValue, methodReturnType, this.container, this.request);
assertThat(this.servletResponse.getContentAsString())
.doesNotContain("<withView1>with</withView1>")
.contains("<withView2>with</withView2>")
.doesNotContain("<withoutView>without</withoutView>");
}
@Test // SPR-12149
void jackson2JsonViewWithResponseBodyAndXmlMessageConverter() throws Exception {
Method method = JacksonController.class.getMethod("handleResponseBody");
HandlerMethod handlerMethod = new HandlerMethod(new JacksonController(), method);
MethodParameter methodReturnType = handlerMethod.getReturnType();
List<HttpMessageConverter<?>> converters = List.of(new MappingJackson2XmlHttpMessageConverter());
RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(
converters, null, List.of(new JsonViewResponseBodyAdvice()));
@@ -555,12 +613,31 @@ class RequestResponseBodyMethodProcessorTests {
.doesNotContain("<withoutView>without</withoutView>");
}
@Test // SPR-12149
@Test
void jacksonJsonViewWithResponseEntityAndXmlMessageConverter() throws Exception {
Method method = JacksonController.class.getMethod("handleResponseEntity");
HandlerMethod handlerMethod = new HandlerMethod(new JacksonController(), method);
MethodParameter methodReturnType = handlerMethod.getReturnType();
List<HttpMessageConverter<?>> converters = List.of(new JacksonXmlHttpMessageConverter());
HttpEntityMethodProcessor processor = new HttpEntityMethodProcessor(
converters, null, List.of(new JsonViewResponseBodyAdvice()));
Object returnValue = new JacksonController().handleResponseEntity();
processor.handleReturnValue(returnValue, methodReturnType, this.container, this.request);
assertThat(this.servletResponse.getContentAsString())
.doesNotContain("<withView1>with</withView1>")
.contains("<withView2>with</withView2>")
.doesNotContain("<withoutView>without</withoutView>");
}
@Test // SPR-12149
void jackson2JsonViewWithResponseEntityAndXmlMessageConverter() throws Exception {
Method method = JacksonController.class.getMethod("handleResponseEntity");
HandlerMethod handlerMethod = new HandlerMethod(new JacksonController(), method);
MethodParameter methodReturnType = handlerMethod.getReturnType();
List<HttpMessageConverter<?>> converters = List.of(new MappingJackson2XmlHttpMessageConverter());
HttpEntityMethodProcessor processor = new HttpEntityMethodProcessor(
converters, null, List.of(new JsonViewResponseBodyAdvice()));
@@ -574,7 +651,7 @@ class RequestResponseBodyMethodProcessorTests {
.doesNotContain("<withoutView>without</withoutView>");
}
@Test // SPR-12501
@Test
void resolveArgumentWithJacksonJsonView() throws Exception {
String content = "{\"withView1\" : \"with\", \"withView2\" : \"with\", \"withoutView\" : \"without\"}";
this.servletRequest.setContent(content.getBytes(StandardCharsets.UTF_8));
@@ -584,6 +661,29 @@ class RequestResponseBodyMethodProcessorTests {
HandlerMethod handlerMethod = new HandlerMethod(new JacksonController(), method);
MethodParameter methodParameter = handlerMethod.getMethodParameters()[0];
List<HttpMessageConverter<?>> converters = List.of(new JacksonJsonHttpMessageConverter());
RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(
converters, null, List.of(new JsonViewRequestBodyAdvice()));
JacksonViewBean result = (JacksonViewBean)
processor.resolveArgument(methodParameter, this.container, this.request, this.factory);
assertThat(result).isNotNull();
assertThat(result.getWithView1()).isEqualTo("with");
assertThat(result.getWithView2()).isNull();
assertThat(result.getWithoutView()).isNull();
}
@Test // SPR-12501
void resolveArgumentWithJackson2JsonView() throws Exception {
String content = "{\"withView1\" : \"with\", \"withView2\" : \"with\", \"withoutView\" : \"without\"}";
this.servletRequest.setContent(content.getBytes(StandardCharsets.UTF_8));
this.servletRequest.setContentType(MediaType.APPLICATION_JSON_VALUE);
Method method = JacksonController.class.getMethod("handleRequestBody", JacksonViewBean.class);
HandlerMethod handlerMethod = new HandlerMethod(new JacksonController(), method);
MethodParameter methodParameter = handlerMethod.getMethodParameters()[0];
List<HttpMessageConverter<?>> converters = List.of(new MappingJackson2HttpMessageConverter());
RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(
converters, null, List.of(new JsonViewRequestBodyAdvice()));
@@ -597,7 +697,7 @@ class RequestResponseBodyMethodProcessorTests {
assertThat(result.getWithoutView()).isNull();
}
@Test // SPR-12501
@Test
void resolveHttpEntityArgumentWithJacksonJsonView() throws Exception {
String content = "{\"withView1\" : \"with\", \"withView2\" : \"with\", \"withoutView\" : \"without\"}";
this.servletRequest.setContent(content.getBytes(StandardCharsets.UTF_8));
@@ -607,6 +707,31 @@ class RequestResponseBodyMethodProcessorTests {
HandlerMethod handlerMethod = new HandlerMethod(new JacksonController(), method);
MethodParameter methodParameter = handlerMethod.getMethodParameters()[0];
List<HttpMessageConverter<?>> converters = List.of(new JacksonJsonHttpMessageConverter());
HttpEntityMethodProcessor processor = new HttpEntityMethodProcessor(
converters, null, List.of(new JsonViewRequestBodyAdvice()));
@SuppressWarnings("unchecked")
HttpEntity<JacksonViewBean> result = (HttpEntity<JacksonViewBean>)
processor.resolveArgument( methodParameter, this.container, this.request, this.factory);
assertThat(result).isNotNull();
assertThat(result.getBody()).isNotNull();
assertThat(result.getBody().getWithView1()).isEqualTo("with");
assertThat(result.getBody().getWithView2()).isNull();
assertThat(result.getBody().getWithoutView()).isNull();
}
@Test // SPR-12501
void resolveHttpEntityArgumentWithJackson2JsonView() throws Exception {
String content = "{\"withView1\" : \"with\", \"withView2\" : \"with\", \"withoutView\" : \"without\"}";
this.servletRequest.setContent(content.getBytes(StandardCharsets.UTF_8));
this.servletRequest.setContentType(MediaType.APPLICATION_JSON_VALUE);
Method method = JacksonController.class.getMethod("handleHttpEntity", HttpEntity.class);
HandlerMethod handlerMethod = new HandlerMethod(new JacksonController(), method);
MethodParameter methodParameter = handlerMethod.getMethodParameters()[0];
List<HttpMessageConverter<?>> converters = List.of(new MappingJackson2HttpMessageConverter());
HttpEntityMethodProcessor processor = new HttpEntityMethodProcessor(
converters, null, List.of(new JsonViewRequestBodyAdvice()));
@@ -622,7 +747,7 @@ class RequestResponseBodyMethodProcessorTests {
assertThat(result.getBody().getWithoutView()).isNull();
}
@Test // SPR-12501
@Test
void resolveArgumentWithJacksonJsonViewAndXmlMessageConverter() throws Exception {
String content = "<root>" +
"<withView1>with</withView1>" +
@@ -635,6 +760,32 @@ class RequestResponseBodyMethodProcessorTests {
HandlerMethod handlerMethod = new HandlerMethod(new JacksonController(), method);
MethodParameter methodParameter = handlerMethod.getMethodParameters()[0];
List<HttpMessageConverter<?>> converters = List.of(new JacksonXmlHttpMessageConverter());
RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(
converters, null, List.of(new JsonViewRequestBodyAdvice()));
JacksonViewBean result = (JacksonViewBean)
processor.resolveArgument(methodParameter, this.container, this.request, this.factory);
assertThat(result).isNotNull();
assertThat(result.getWithView1()).isEqualTo("with");
assertThat(result.getWithView2()).isNull();
assertThat(result.getWithoutView()).isNull();
}
@Test // SPR-12501
void resolveArgumentWithJackson2JsonViewAndXmlMessageConverter() throws Exception {
String content = "<root>" +
"<withView1>with</withView1>" +
"<withView2>with</withView2>" +
"<withoutView>without</withoutView></root>";
this.servletRequest.setContent(content.getBytes(StandardCharsets.UTF_8));
this.servletRequest.setContentType(MediaType.APPLICATION_XML_VALUE);
Method method = JacksonController.class.getMethod("handleRequestBody", JacksonViewBean.class);
HandlerMethod handlerMethod = new HandlerMethod(new JacksonController(), method);
MethodParameter methodParameter = handlerMethod.getMethodParameters()[0];
List<HttpMessageConverter<?>> converters = List.of(new MappingJackson2XmlHttpMessageConverter());
RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(
converters, null, List.of(new JsonViewRequestBodyAdvice()));
@@ -648,7 +799,7 @@ class RequestResponseBodyMethodProcessorTests {
assertThat(result.getWithoutView()).isNull();
}
@Test // SPR-12501
@Test
void resolveHttpEntityArgumentWithJacksonJsonViewAndXmlMessageConverter() throws Exception {
String content = "<root>" +
"<withView1>with</withView1>" +
@@ -661,6 +812,34 @@ class RequestResponseBodyMethodProcessorTests {
HandlerMethod handlerMethod = new HandlerMethod(new JacksonController(), method);
MethodParameter methodParameter = handlerMethod.getMethodParameters()[0];
List<HttpMessageConverter<?>> converters = List.of(new JacksonXmlHttpMessageConverter());
HttpEntityMethodProcessor processor = new HttpEntityMethodProcessor(
converters, null, List.of(new JsonViewRequestBodyAdvice()));
@SuppressWarnings("unchecked")
HttpEntity<JacksonViewBean> result = (HttpEntity<JacksonViewBean>)
processor.resolveArgument(methodParameter, this.container, this.request, this.factory);
assertThat(result).isNotNull();
assertThat(result.getBody()).isNotNull();
assertThat(result.getBody().getWithView1()).isEqualTo("with");
assertThat(result.getBody().getWithView2()).isNull();
assertThat(result.getBody().getWithoutView()).isNull();
}
@Test // SPR-12501
void resolveHttpEntityArgumentWithJackson2JsonViewAndXmlMessageConverter() throws Exception {
String content = "<root>" +
"<withView1>with</withView1>" +
"<withView2>with</withView2>" +
"<withoutView>without</withoutView></root>";
this.servletRequest.setContent(content.getBytes(StandardCharsets.UTF_8));
this.servletRequest.setContentType(MediaType.APPLICATION_XML_VALUE);
Method method = JacksonController.class.getMethod("handleHttpEntity", HttpEntity.class);
HandlerMethod handlerMethod = new HandlerMethod(new JacksonController(), method);
MethodParameter methodParameter = handlerMethod.getMethodParameters()[0];
List<HttpMessageConverter<?>> converters = List.of(new MappingJackson2XmlHttpMessageConverter());
HttpEntityMethodProcessor processor = new HttpEntityMethodProcessor(
converters, null, List.of(new JsonViewRequestBodyAdvice()));
@@ -676,12 +855,29 @@ class RequestResponseBodyMethodProcessorTests {
assertThat(result.getBody().getWithoutView()).isNull();
}
@Test // SPR-12811
@Test
void jacksonTypeInfoList() throws Exception {
Method method = JacksonController.class.getMethod("handleTypeInfoList");
HandlerMethod handlerMethod = new HandlerMethod(new JacksonController(), method);
MethodParameter methodReturnType = handlerMethod.getReturnType();
List<HttpMessageConverter<?>> converters = List.of(new JacksonJsonHttpMessageConverter());
RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters);
Object returnValue = new JacksonController().handleTypeInfoList();
processor.handleReturnValue(returnValue, methodReturnType, this.container, this.request);
assertThat(this.servletResponse.getContentAsString())
.contains("\"type\":\"foo\"")
.contains("\"type\":\"bar\"");
}
@Test // SPR-12811
void jackson2TypeInfoList() throws Exception {
Method method = JacksonController.class.getMethod("handleTypeInfoList");
HandlerMethod handlerMethod = new HandlerMethod(new JacksonController(), method);
MethodParameter methodReturnType = handlerMethod.getReturnType();
List<HttpMessageConverter<?>> converters = List.of(new MappingJackson2HttpMessageConverter());
RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters);
@@ -693,12 +889,29 @@ class RequestResponseBodyMethodProcessorTests {
.contains("\"type\":\"bar\"");
}
@Test // SPR-13318
@Test
void jacksonSubType() throws Exception {
Method method = JacksonController.class.getMethod("handleSubType");
HandlerMethod handlerMethod = new HandlerMethod(new JacksonController(), method);
MethodParameter methodReturnType = handlerMethod.getReturnType();
List<HttpMessageConverter<?>> converters = List.of(new JacksonJsonHttpMessageConverter());
RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters);
Object returnValue = new JacksonController().handleSubType();
processor.handleReturnValue(returnValue, methodReturnType, this.container, this.request);
assertThat(this.servletResponse.getContentAsString())
.contains("\"id\":123")
.contains("\"name\":\"foo\"");
}
@Test // SPR-13318
void jackson2SubType() throws Exception {
Method method = JacksonController.class.getMethod("handleSubType");
HandlerMethod handlerMethod = new HandlerMethod(new JacksonController(), method);
MethodParameter methodReturnType = handlerMethod.getReturnType();
List<HttpMessageConverter<?>> converters = List.of(new MappingJackson2HttpMessageConverter());
RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters);
@@ -710,12 +923,31 @@ class RequestResponseBodyMethodProcessorTests {
.contains("\"name\":\"foo\"");
}
@Test // SPR-13318
@Test
void jacksonSubTypeList() throws Exception {
Method method = JacksonController.class.getMethod("handleSubTypeList");
HandlerMethod handlerMethod = new HandlerMethod(new JacksonController(), method);
MethodParameter methodReturnType = handlerMethod.getReturnType();
List<HttpMessageConverter<?>> converters = List.of(new JacksonJsonHttpMessageConverter());
RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters);
Object returnValue = new JacksonController().handleSubTypeList();
processor.handleReturnValue(returnValue, methodReturnType, this.container, this.request);
assertThat(this.servletResponse.getContentAsString())
.contains("\"id\":123")
.contains("\"name\":\"foo\"")
.contains("\"id\":456")
.contains("\"name\":\"bar\"");
}
@Test // SPR-13318
void jackson2SubTypeList() throws Exception {
Method method = JacksonController.class.getMethod("handleSubTypeList");
HandlerMethod handlerMethod = new HandlerMethod(new JacksonController(), method);
MethodParameter methodReturnType = handlerMethod.getReturnType();
List<HttpMessageConverter<?>> converters = List.of(new MappingJackson2HttpMessageConverter());
RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters);
@@ -738,7 +970,7 @@ class RequestResponseBodyMethodProcessorTests {
HandlerMethod handlerMethod = new HandlerMethod(new MyControllerImplementingInterface(), method);
MethodParameter methodParameter = handlerMethod.getMethodParameters()[0];
List<HttpMessageConverter<?>> converters = List.of(new MappingJackson2HttpMessageConverter());
List<HttpMessageConverter<?>> converters = List.of(new JacksonJsonHttpMessageConverter());
RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters);
assertThat(processor.supportsParameter(methodParameter)).isTrue();
@@ -756,7 +988,7 @@ class RequestResponseBodyMethodProcessorTests {
HandlerMethod handlerMethod = new HandlerMethod(new SubControllerImplementingInterface(), method);
MethodParameter methodParameter = handlerMethod.getMethodParameters()[0];
List<HttpMessageConverter<?>> converters = List.of(new MappingJackson2HttpMessageConverter());
List<HttpMessageConverter<?>> converters = List.of(new JacksonJsonHttpMessageConverter());
RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters);
assertThat(processor.supportsParameter(methodParameter)).isTrue();
@@ -774,7 +1006,7 @@ class RequestResponseBodyMethodProcessorTests {
HandlerMethod handlerMethod = new HandlerMethod(new SubControllerImplementingAbstractMethod(), method);
MethodParameter methodParameter = handlerMethod.getMethodParameters()[0];
List<HttpMessageConverter<?>> converters = List.of(new MappingJackson2HttpMessageConverter());
List<HttpMessageConverter<?>> converters = List.of(new JacksonJsonHttpMessageConverter());
RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters);
assertThat(processor.supportsParameter(methodParameter)).isTrue();
@@ -1068,8 +1300,6 @@ class RequestResponseBodyMethodProcessorTests {
bean.setWithView1("with");
bean.setWithView2("with");
bean.setWithoutView("without");
ModelAndView mav = new ModelAndView(new MappingJackson2JsonView());
mav.addObject("bean", bean);
return new ResponseEntity<>(bean, HttpStatus.OK);
}

View File

@@ -35,7 +35,7 @@ import reactor.core.scheduler.Schedulers;
import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.json.JacksonJsonHttpMessageConverter;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.context.request.async.AsyncWebRequest;
@@ -63,7 +63,7 @@ import static org.springframework.web.testfixture.method.ResolvableMethod.on;
class ResponseBodyEmitterReturnValueHandlerTests {
private final ResponseBodyEmitterReturnValueHandler handler =
new ResponseBodyEmitterReturnValueHandler(List.of(new MappingJackson2HttpMessageConverter()));
new ResponseBodyEmitterReturnValueHandler(List.of(new JacksonJsonHttpMessageConverter()));
private final MockHttpServletRequest request = new MockHttpServletRequest();

View File

@@ -41,7 +41,7 @@ import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.json.JacksonJsonHttpMessageConverter;
import org.springframework.web.accept.ContentNegotiationManager;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
@@ -373,7 +373,7 @@ class ServletInvocableHandlerMethodTests {
@Test
void wrapConcurrentResult_CollectedValuesList() throws Exception {
List<HttpMessageConverter<?>> converters = Collections.singletonList(new MappingJackson2HttpMessageConverter());
List<HttpMessageConverter<?>> converters = Collections.singletonList(new JacksonJsonHttpMessageConverter());
ResolvableType elementType = ResolvableType.forClass(List.class);
ReactiveTypeHandler.CollectedValuesList result = new ReactiveTypeHandler.CollectedValuesList(elementType);
result.add(Arrays.asList("foo1", "bar1"));
@@ -391,7 +391,7 @@ class ServletInvocableHandlerMethodTests {
@Test // SPR-15478
public void wrapConcurrentResult_CollectedValuesListWithResponseEntity() throws Exception {
List<HttpMessageConverter<?>> converters = Collections.singletonList(new MappingJackson2HttpMessageConverter());
List<HttpMessageConverter<?>> converters = Collections.singletonList(new JacksonJsonHttpMessageConverter());
ResolvableType elementType = ResolvableType.forClass(Bar.class);
ReactiveTypeHandler.CollectedValuesList result = new ReactiveTypeHandler.CollectedValuesList(elementType);
result.add(new Bar("foo"));