使用 RestTemplate 时如何配置内部 Jackson 映射器?
Posted
技术标签:
【中文标题】使用 RestTemplate 时如何配置内部 Jackson 映射器?【英文标题】:How can we configure the internal Jackson mapper when using RestTemplate? 【发布时间】:2012-03-12 00:08:19 【问题描述】:我想更新 Spring RestTemplate 使用的 jackson 映射器的 SerializationConfig.Feature... 属性,知道如何获取它或我可以/应该在哪里配置它。
【问题讨论】:
【参考方案1】:默认的RestTemplate
构造函数注册了一组HttpMessageConverter
s:
this.messageConverters.add(new ByteArrayHttpMessageConverter());
this.messageConverters.add(new StringHttpMessageConverter());
this.messageConverters.add(new ResourceHttpMessageConverter());
this.messageConverters.add(new SourceHttpMessageConverter());
this.messageConverters.add(new XmlAwareFormHttpMessageConverter());
if (jaxb2Present)
this.messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
if (jacksonPresent)
this.messageConverters.add(new MappingJacksonHttpMessageConverter());
if (romePresent)
this.messageConverters.add(new AtomFeedHttpMessageConverter());
this.messageConverters.add(new RssChannelHttpMessageConverter());
MappingJacksonHttpMessageConverter
依次创建ObjectMapper
实例。您可以找到此转换器并替换 ObjectMapper
或在其之前注册一个新转换器。这应该有效:
@Bean
public RestOperations restOperations()
RestTemplate rest = new RestTemplate();
//this is crucial!
rest.getMessageConverters().add(0, mappingJacksonHttpMessageConverter());
return rest;
@Bean
public MappingJacksonHttpMessageConverter mappingJacksonHttpMessageConverter()
MappingJacksonHttpMessageConverter converter = new MappingJacksonHttpMessageConverter();
converter.setObjectMapper(myObjectMapper());
return converter;
@Bean
public ObjectMapper myObjectMapper()
//your custom ObjectMapper here
在 XML 中是这样的:
<bean id="restOperations" class="org.springframework.web.client.RestTemplate">
<property name="messageConverters">
<util:list>
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"/>
<bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
<bean class="org.springframework.http.converter.ResourceHttpMessageConverter"/>
<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter"/>
<bean class="org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter"/>
<bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter"/>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="objectMapper" ref="customObjectMapper"/>
</bean>
</util:list>
</property>
</bean>
<bean id="customObjectMapper" class="org.codehaus.jackson.map.ObjectMapper"/>
请注意,转换并不是真正的 1:1 - 我必须在 XML 中显式创建 messageConverters
列表,而使用 @Configuration
方法我可以引用现有的并简单地修改它。但这应该可行。
【讨论】:
如果您能将其翻译成 XML,我将不胜感激。真的很想试试这个,但不知道如何配置它。非常感谢! 不确定这是否只是由于版本差异,但我相信 Jackson 转换器类的正确名称是 MappingJackson*2*HttpMessageConverter 我可能会避免在现有默认值的开头添加新的 mappingJacksonHttpMessageConverter,而是替换现有的 Jackson 消息转换器。否则,您最终会在列表中拥有 2 个 Jackson 消息转换器。 我尝试在索引 0 处添加它,但我得到了一些非常奇怪的 JSON 解析异常。像@mvogiatzis 建议的那样删除现有的效果更好 我需要在@Bean
定义中更改 RestOperations -> RestTemplate
以使其正常工作【参考方案2】:
如果你没有使用 Spring IOC,你可以这样做(Java 8):
ObjectMapper objectMapper = new ObjectMapper();
// configure your ObjectMapper here
RestTemplate restTemplate = new RestTemplate();
MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
messageConverter.setPrettyPrint(false);
messageConverter.setObjectMapper(objectMapper);
restTemplate.getMessageConverters().removeIf(m -> m.getClass().getName().equals(MappingJackson2HttpMessageConverter.class.getName()));
restTemplate.getMessageConverters().add(messageConverter);
【讨论】:
当你发现它在迭代时,为什么你需要删除并重新添加? restTemplate.getMessageConverters().removeIf(m -> m.getClass().isAssignableFrom(MappingJackson2HttpMessageConverter.class));【参考方案3】:RestTemplate 将初始化其默认消息转换器。你应该用你自己的bean替换MappingJackson2HttpMessageConverter
,它应该使用你想使用的对象映射器。这对我有用:
@Bean
public RestTemplate restTemplate()
final RestTemplate restTemplate = new RestTemplate();
//find and replace Jackson message converter with our own
for (int i = 0; i < restTemplate.getMessageConverters().size(); i++)
final HttpMessageConverter<?> httpMessageConverter = restTemplate.getMessageConverters().get(i);
if (httpMessageConverter instanceof MappingJackson2HttpMessageConverter)
restTemplate.getMessageConverters().set(i, mappingJackson2HttpMessageConverter());
return restTemplate;
@Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter()
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(myObjectMapper());
return converter;
@Bean
public ObjectMapper myObjectMapper()
// return your own object mapper
【讨论】:
将方法命名为myObjectMapper()
之类的名称似乎很重要,而不仅仅是objectMapper()
。出于某种原因,该方法似乎从未被调用过,而您会得到默认的ObjectMapper
。
这行得通,但似乎答案中有错字? restTemplate.getMessageConverters().set(i, mappingJackson2HttpMessageConverter);
应该是 restTemplate.getMessageConverters().set(i, mappingJackson2HttpMessageConverter());
(注意 mappingJackson2HttpMessageConverter() 中的括号,使其成为方法调用而不是引用)
True,或者您也可以将mappingJackson2HttpMessageConverter
作为参数添加到restTemplate
函数,按原样使用。
你不必创建一个新的,你可以设置你的映射器 if (httpMessageConverter instanceof MappingJackson2HttpMessageConverter) ((MappingJackson2HttpMessageConverter)httpMessageConverter).setObjectMapper(mapper());
在 Java8 中您可以使用流或 Java14 您可以对 instanceof 使用模式匹配。否则很好的声明性解决方案。【参考方案4】:
要完成其他答案:如果您的 ObjectMapper
只是使用自定义序列化器/反序列化器注册了 Jackson Module
,您可能希望从 RestTemplate
的默认 @987654325 直接在现有 ObjectMapper
上注册您的模块@ 如下(不使用 DI 的示例,但使用 DI 时同样适用):
SimpleModule module = new SimpleModule();
module.addSerializer(...);
module.addDeserializer(...);
MappingJackson2HttpMessageConverter messageConverter = restTemplate.getMessageConverters().stream()
.filter(MappingJackson2HttpMessageConverter.class::isInstance)
.map(MappingJackson2HttpMessageConverter.class::cast)
.findFirst().orElseThrow( () -> new RuntimeException("MappingJackson2HttpMessageConverter not found"));
messageConverter.getObjectMapper().registerModule(module);
这将允许您完成原始ObjectMapper
的配置(如Spring 的Jackson2ObjectMapperBuilder
所做的那样),而不是替换它。
【讨论】:
【参考方案5】:使用Spring Boot,就这么简单:
RestTemplate template = new RestTemplateBuilder()
.additionalMessageConverters(new MappingJackson2HttpMessageConverter(objectMapper))
.build()
(使用 Spring Boot 2.2.1 测试)
【讨论】:
使用这种方法,您的RestTemplate
将只有一个MessageConverter
:MappingJackson2HttpMessageConverter
。但我还是喜欢它
additionalMessageConverters
并不是真正的添加剂。它将执行完全替换,您将丢失其他转换器。它在其文档字符串中说明。 (它会添加到构建器的转换器列表中,这将完全替换实例的)以上是关于使用 RestTemplate 时如何配置内部 Jackson 映射器?的主要内容,如果未能解决你的问题,请参考以下文章
使用 RestTemplate 测试 ExceptionHandler
模拟 mock<RestTemplate> getForObject 时如何解决歧义?
使用resttemplate访问时,如何使端点仅接受springboot中启用@crossorigin的uri?为啥我没有收到 cors 错误? [复制]