Right way to write JSON deserializer in Spring or extend it Right way to write JSON deserializer in Spring or extend it spring spring

Right way to write JSON deserializer in Spring or extend it


I've searched a lot and the best way I've found so far is on this article:

Class to serialize

package net.sghill.example;import net.sghill.example.UserDeserializerimport net.sghill.example.UserSerializerimport org.codehaus.jackson.map.annotate.JsonDeserialize;import org.codehaus.jackson.map.annotate.JsonSerialize;@JsonDeserialize(using = UserDeserializer.class)public class User {    private ObjectId id;    private String   username;    private String   password;    public User(ObjectId id, String username, String password) {        this.id = id;        this.username = username;        this.password = password;    }    public ObjectId getId()       { return id; }    public String   getUsername() { return username; }    public String   getPassword() { return password; }}

Deserializer class

package net.sghill.example;import net.sghill.example.User;import org.codehaus.jackson.JsonNode;import org.codehaus.jackson.JsonParser;import org.codehaus.jackson.ObjectCodec;import org.codehaus.jackson.map.DeserializationContext;import org.codehaus.jackson.map.JsonDeserializer;import java.io.IOException;public class UserDeserializer extends JsonDeserializer<User> {    @Override    public User deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {        ObjectCodec oc = jsonParser.getCodec();        JsonNode node = oc.readTree(jsonParser);        return new User(null, node.get("username").getTextValue(), node.get("password").getTextValue());    }}

Edit:Alternatively you can look at this article which uses new versions of com.fasterxml.jackson.databind.JsonDeserializer.


I was trying to @Autowire a Spring-managed service into my Deserializer. Somebody tipped me off to Jackson using the new operator when invoking the serializers/deserializers. This meant no auto-wiring of Jackson's instance of my Deserializer. Here's how I was able to @Autowire my service class into my Deserializer:

context.xml

<mvc:annotation-driven>  <mvc:message-converters>    <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">      <property name="objectMapper" ref="objectMapper" />    </bean>  </mvc:message-converters></mvc><bean id="objectMapper" class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">    <!-- Add deserializers that require autowiring -->    <property name="deserializersByType">        <map key-type="java.lang.Class">            <entry key="com.acme.Anchor">                <bean class="com.acme.AnchorDeserializer" />            </entry>        </map>    </property></bean>

Now that my Deserializer is a Spring-managed bean, auto-wiring works!

AnchorDeserializer.java

public class AnchorDeserializer extends JsonDeserializer<Anchor> {    @Autowired    private AnchorService anchorService;    public Anchor deserialize(JsonParser parser, DeserializationContext context)             throws IOException, JsonProcessingException {        // Do stuff    }}

AnchorService.java

@Servicepublic class AnchorService {}

Update: While my original answer worked for me back when I wrote this, @xi.lin's response is exactly what is needed. Nice find!


With Spring MVC 4.2.1.RELEASE, you need to use the new Jackson2 dependencies as below for the Deserializer to work.

Dont use this

<dependency>              <groupId>org.codehaus.jackson</groupId>              <artifactId>jackson-mapper-asl</artifactId>              <version>1.9.12</version>          </dependency>  

Use this instead.

<dependency>            <groupId>com.fasterxml.jackson.core</groupId>            <artifactId>jackson-annotations</artifactId>            <version>2.2.2</version>        </dependency>        <dependency>            <groupId>com.fasterxml.jackson.core</groupId>            <artifactId>jackson-core</artifactId>            <version>2.2.2</version>        </dependency>        <dependency>            <groupId>com.fasterxml.jackson.core</groupId>            <artifactId>jackson-databind</artifactId>            <version>2.2.2</version>        </dependency>  

Also use com.fasterxml.jackson.databind.JsonDeserializer and com.fasterxml.jackson.databind.annotation.JsonDeserialize for the deserialization and not the classes from org.codehaus.jackson