Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Right way to write JSON deserializer in Spring or extend it

I am trying to write a custom JSON deserializer in Spring. I want to use default serializer for most part of fields and use a custom deserializer for few properties. Is it possible? I am trying this way because, most part of properties are values, so for these I can let Jackson use default deserializer; but few properties are references, so in the custom deserializer I have to query a database for reference name and get reference value from database.

I'll show some code if needed.

like image 296
gc5 Avatar asked Jul 07 '12 15:07

gc5


People also ask

How do I create a custom JSON deserializer?

The @JsonDeserialize annotation is used to declare custom deserializer while deserializing JSON to Java object. We can implement a custom deserializer by extending the StdDeserializer class with a generic type Employee and need to override the deserialize() method of StdDeserializer class.

How do I register a custom deserializer?

To create a custom deserializer, we need to create a class extending StdDeserializer and then override its deserialize() method. We can use custom deserializer either by registering with ObjectMapper or annotating class with @JsonDeserialize .

What is the purpose of JsonDeserialize?

@JsonDeserialize is used to specify custom deserializer to unmarshall the json object.

What is Jackson deserializer?

Jackson is a powerful and efficient Java library that handles the serialization and deserialization of Java objects and their JSON representations. It's one of the most widely used libraries for this task, and runs under the hood of many other frameworks.


2 Answers

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.UserDeserializer import net.sghill.example.UserSerializer import 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.

like image 96
3 revs, 3 users 95% Avatar answered Sep 30 '22 12:09

3 revs, 3 users 95%


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

@Service public 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!

like image 22
Beez Avatar answered Sep 30 '22 12:09

Beez