Being still a little unfamiliar with Spring, I have encountered a problem that makes it necessary implementing my a custom deserialzer for Jackson. The procedure is described in a small tutorial, however, I am stuck with Spring. I do not understand, where
ObjectMapper mapper = new ObjectMapper();
in Spring MVC is carried out when json is deserializes by a method of a controller class. So I do not know, what to do in order to replace the default deserializer by a custom deserialiser.
Any suggestions most welcome.
New way to do this in 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/
Allows you to do something like this:
In my case (Spring 3.2.4 and Jackson 2.3.1), XML configuration for custom serializer:
was in unexplained way overwritten back to default by something.
This worked for me:
CustomObject.java
CustomObjectSerializer.java
No XML configuration (
<mvc:message-converters>(...)</mvc:message-converters>
) is needed in my solution.The solution referenced by Rakesh likely works with Spring MVC 3.0 but with 3.1 some of the MVC infrastructure has changed. As a result you may not have an
AnnotationMethodHandlerAdapter
bean registered in your application context and you'll end up with aBeanCreationException
at initialization time.For Spring MVC 3.1 the
mvc:annotation-driven
element will create a RequestMappingHandlerAdapter for you, so you should autowire that type instead. It will still provide access to the list of registered HttpMessageConverters and allow you to set the ObjectMapper property on theMappingJacksonHttpMessageConverter
. This also requires a slight change within theinit
. method to the type of the HttpMessageConverters reference.The updated class looks like:
UPDATE: It turns out the absolute easiest thing to do with Spring 3.1 is to add some additional configuration to your MVC configuration:
That will add a new instance of
MappingJacksonHttpMessageConverter
with the custom ObjectMapper before any of the default HttpMessageConverters (which are still present due toregister-defaults="true"
).I wish I knew Spring MVC better, but with Jax-RS implementations like Jersey and RESTeasy, one registers providers. Maybe Spring does something similar?
The spring docs for MappingJacksonHttpMessageConverter state:
2.4.5 MappingJacksonHttpMessageConverter
An HttpMessageConverter implementation that can read and write JSON using Jackson JSON Processor's ObjectMapper. JSON mapping can be customized as needed through the use of Jackson's provided annotations. When further control is needed, a custom ObjectMapper can be injected through the ObjectMapper property for cases where custom JSON serializers/deserializers need to be provided for specific types. By default this converter supports (application/json).
Couldn't you just autowire access to the ObjectMapper in order to modify it's behaviour?
You don't say how you're using Jackson in Spring, so I'll assume you're using it through
<mvc:annotation-driven/>
and the@RequestBody
and/or@ResponseBody
annotations.One of the things that
<mvc:annotation-driven/>
does is to register aAnnotationMethodHandlerAdapter
bean which comes with a number of pre-configuredHttpMessageConverter
beans, includingMappingJacksonHttpMessageConverter
, which handles marshalling to and from Jackson-annotated model classes.Now
MappingJacksonHttpMessageConverter
has asetObjectMapper()
method, which allows you to override the defaultObjectMapper
. But sinceMappingJacksonHttpMessageConverter
is created behind the scenes by<mvc:annotation-driven/>
, you can't get to it.However,
<mvc:annotation-driven/>
is just a convenient short-cut. It's just as a valid to declare your ownAnnotationMethodHandlerAdapter
bean, injecting into it your ownMappingJacksonHttpMessageConverter
bean (via themessageConverters
property), and injecting your own customizedObjectMapper
into that.You then have the problem of how to build a custom
ObjectMapper
, since it's not a very Spring-friendly class. I suggest writing your own simple implementation ofFactoryBean
.So you'd end up with something like this: