Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jackson, custom deserialization for specific field names

I would like to know if it is possible to customize the deserialization of json depending the field name, for example

{
   id: "abc123",
   field1: {...}
   other: {
        field1: {....}
     }
}

I the previous json, I would like to have a custom deserializer for the fields named "field1", in any level in the json.

The reason: We have our data persisted as JSON, and we have a REST service that returns such data, but before return it, the service must inject extra information in the "field1" attribute.

The types are very dynamic, so we cannot define a Java class to map the json to use annotations.

An first approach was to deserialize to Map.class and then use JsonPath to search the $..field1 pattern, but this process is expensive for bigger objects.

I appreciate any help.

Thanks,

Edwin Miguel

like image 978
Edwin Miguel Avatar asked Dec 15 '14 23:12

Edwin Miguel


2 Answers

You should consider registering a custom deserializer with the ObjectMapper for this purpose.

Then you should be able to simply map your JSON stream to a Map<String, Object> knowing that your field1 objects will be handled by your custom code.

like image 94
Costi Ciudatu Avatar answered Sep 28 '22 04:09

Costi Ciudatu


I create a custom deserializer and added it to a SimpleModule for the ObjectMapper

public class CustomDeserializer extends StdDeserializer<Map> {
public CustomDeserializer() {
    super(Map.class);
}

@Override
public Map deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
    Map<String, Object> result = new HashMap<String, Object>();
    jp.nextToken();
    while (!JsonToken.END_OBJECT.equals(jp.getCurrentToken())) {
        String key = jp.getText();
        jp.nextToken();
        if ("field1".equals(key)) {
            MyObject fiedlObj= jp.readValueAs(MyObject.class);
            //inject extra info
            //...
            result.put(key, fieldObj);
        } else {
            if (JsonToken.START_OBJECT.equals(jp.getCurrentToken())) {
                result.put(key, deserialize(jp, ctxt));
            } else if (JsonToken.START_ARRAY.equals(jp.getCurrentToken())) {
                jp.nextToken();
                List<Object> linkedList = new LinkedList<Object>();
                while (!JsonToken.END_ARRAY.equals(jp.getCurrentToken())) {
                    linkedList.add(deserialize(jp, ctxt));
                    jp.nextToken();
                }
                result.put(key, linkedList);
            } else {
                result.put(key, jp.readValueAs(Object.class));
            }
        }
        jp.nextToken();
    }
    return result;
}

}

The problem is that I had to implement the parsing for the remaining attributes.

For now, it is my solution...

like image 35
Edwin Miguel Avatar answered Sep 28 '22 06:09

Edwin Miguel