Spring、Jackson 和自定义(例如 CustomDeserializer)
Posted
技术标签:
【中文标题】Spring、Jackson 和自定义(例如 CustomDeserializer)【英文标题】:Spring, Jackson and Customization (e.g. CustomDeserializer) 【发布时间】:2011-04-05 05:06:32 【问题描述】:由于对 Spring 还有些陌生,我遇到了一个 problem,这使得我有必要为 Jackson 实现一个自定义解串器。该过程在一个小的tutorial 中进行了描述,但是,我坚持使用 Spring。我不明白,在哪里
ObjectMapper mapper = new ObjectMapper();
在 Spring MVC 中,当 json 通过控制器类的方法反序列化时执行。所以我不知道该怎么做才能用自定义反序列化器替换默认反序列化器。
欢迎提出任何建议。
【问题讨论】:
【参考方案1】:你没有说你在 Spring 中是如何使用 Jackson 的,所以我假设你是通过 <mvc:annotation-driven/>
和 @RequestBody
和/或 @ResponseBody
注释来使用它的。
<mvc:annotation-driven/>
所做的一件事是注册一个 AnnotationMethodHandlerAdapter
bean,它带有许多预配置的 HttpMessageConverter
bean,包括 MappingJacksonHttpMessageConverter
,它处理与 Jackson 注释的模型类之间的编组.
现在MappingJacksonHttpMessageConverter
有一个setObjectMapper()
方法,它允许您覆盖默认的ObjectMapper
。但由于MappingJacksonHttpMessageConverter
是<mvc:annotation-driven/>
在幕后创建的,所以您无法访问它。
但是,<mvc:annotation-driven/>
只是一个方便的捷径。声明您自己的 AnnotationMethodHandlerAdapter
bean,将您自己的 MappingJacksonHttpMessageConverter
bean 注入其中(通过 messageConverters
属性),并将您自己的自定义 ObjectMapper
注入其中。
然后你就会遇到如何构建自定义ObjectMapper
的问题,因为它不是一个对 Spring 非常友好的类。我建议写你的own simple implementation of FactoryBean
。
所以你最终会得到这样的结果:
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="objectMapper">
<bean class="com.x.MyObjectMapperFactoryBean"/>
</property>
</bean>
</property>
</bean>
【讨论】:
【参考方案2】:在 Spring 3.1 中执行此操作的新方法:http://magicmonster.com/kb/prg/java/spring/webmvc/mvc_spring_config_namespace.html
http://blog.springsource.org/2011/02/21/spring-3-1-m1-mvc-namespace-enhancements-and-configuration/
允许您执行以下操作:
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="objectMapper" ref="customObjectMapper"/>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
【讨论】:
【参考方案3】:Rakesh 引用的解决方案可能适用于 Spring MVC 3.0,但适用于 3.1 的一些 MVC 基础架构has changed。因此,您可能没有在应用程序上下文中注册 AnnotationMethodHandlerAdapter
bean,并且您最终会在初始化时得到 BeanCreationException
。
对于 Spring MVC 3.1,mvc:annotation-driven
元素将为您创建一个 RequestMappingHandlerAdapter,因此您应该改为自动装配该类型。它仍将提供对已注册 HttpMessageConverters 列表的访问权限,并允许您在 MappingJacksonHttpMessageConverter
上设置 ObjectMapper 属性。这也需要在init
内稍作更改。 HttpMessageConverters 引用类型的方法。
更新后的类如下所示:
@Component
public class JacksonFix
private RequestMappingHandlerAdapter requestMappingHandlerAdapter;
private CustomObjectMapper objectMapper;
@PostConstruct
public void init()
List<HttpMessageConverter<?>> messageConverters = requestMappingHandlerAdapter.getMessageConverters();
for (HttpMessageConverter<?> messageConverter : messageConverters)
if (messageConverter instanceof MappingJacksonHttpMessageConverter)
MappingJacksonHttpMessageConverter m = (MappingJacksonHttpMessageConverter) messageConverter;
m.setObjectMapper(objectMapper);
// this will exist due to the <mvc:annotation-driven/> bean
@Autowired
public void setRequestMappingHandlerAdapter(RequestMappingHandlerAdapter requestMappingHandlerAdapter)
this.requestMappingHandlerAdapter = requestMappingHandlerAdapter;
@Autowired
public void setObjectMapper(CustomObjectMapper objectMapper)
this.objectMapper = objectMapper;
更新:事实证明,使用 Spring 3.1 最简单的事情就是在 MVC 配置中添加一些额外的配置:
<mvc:annotation-driven conversion-service="applicationConversionService">
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="objectMapper" ref="customObjectMapper" />
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
这将在任何默认 HttpMessageConverters 之前添加一个带有自定义 ObjectMapper 的 MappingJacksonHttpMessageConverter
的新实例(由于 register-defaults="true"
而仍然存在)。
【讨论】:
【参考方案4】:就我而言(Spring 3.2.4 和 Jackson 2.3.1),自定义序列化程序的 XML 配置:
<mvc:annotation-driven>
<mvc:message-converters register-defaults="false">
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
<property name="serializers">
<array>
<bean class="com.example.business.serializer.json.CustomObjectSerializer"/>
</array>
</property>
</bean>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
被某些东西以无法解释的方式覆盖回默认值。
这对我有用:
CustomObject.java
@JsonSerialize(using = CustomObjectSerializer.class)
public class CustomObject
private Long value;
public Long getValue()
return value;
public void setValue(Long value)
this.value = value;
CustomObjectSerializer.java
public class CustomObjectSerializer extends JsonSerializer<CustomObject>
@Override
public void serialize(CustomObject value, JsonGenerator jgen,
SerializerProvider provider) throws IOException,JsonProcessingException
jgen.writeStartObject();
jgen.writeNumberField("y", value.getValue());
jgen.writeEndObject();
@Override
public Class<CustomObject> handledType()
return CustomObject.class;
我的解决方案中不需要 XML 配置 (<mvc:message-converters>(...)</mvc:message-converters>
)。
【讨论】:
【参考方案5】:我希望我更了解 Spring MVC,但是对于像 Jersey 和 RESTeasy 这样的 Jax-RS 实现,需要注册提供程序。也许 Spring 会做类似的事情?
【讨论】:
【参考方案6】:MappingJacksonHttpMessageConverter 状态的 Spring 文档:
2.4.5 映射JacksonHttpMessageConverter
可以使用 Jackson JSON 处理器的 ObjectMapper 读取和写入 JSON 的 HttpMessageConverter 实现。 JSON 映射可以通过使用 Jackson 提供的注释根据需要进行自定义。当需要进一步控制时,可以通过 ObjectMapper 属性注入自定义 ObjectMapper,以应对需要为特定类型提供自定义 JSON 序列化器/反序列化器的情况。默认情况下,此转换器支持 (application/json)。
难道你不能自动访问 ObjectMapper 来修改它的行为吗?
【讨论】:
以上是关于Spring、Jackson 和自定义(例如 CustomDeserializer)的主要内容,如果未能解决你的问题,请参考以下文章
你能配置 Spring 控制器特定的 Jackson 反序列化吗?