Search code examples
javajsonjacksonjson-deserialization

Ignore empty string as null during deserialization


I try to deserialize the following json into a java pojo.

[{
    "image" : {
        "url" : "http://foo.bar"
    }
}, {
    "image" : ""      <-- This is some funky null replacement
}, {
    "image" : null    <-- This is the expected null value (Never happens in that API for images though)
}]

And my Java classes looks like this:

public class Server {

    public Image image;
    // lots of other attributes

}

and

public class Image {

    public String url;
    // few other attributes

}

I use jackson 2.8.6

ObjectMapper.read(json, LIST_OF_SERVER_TYPE_REFERENCE);

but i keep getting the following exception:

Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of Image: no String-argument constructor/factory method to deserialize from String value ('')

If I add a String setter for it

public void setImage(Image image) {
    this.image = image;
}

public void setImage(String value) {
    // Ignore
}

I get the following exception

Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.lang.String out of START_OBJECT token

The exception does not change whether or not I (also) add a Image setter or not.

I also tried @JsonInclude(NOT_EMPTY) but this only seems to affect the serialization.

Summary: Some (badly designed) API sends me an empty string ("") instead of null and I have to tell Jackson to just ignore that bad value. How can I do this?


Solution

  • There doesn't seem to be a outof the box solution, so i went for the custom deserializer one:

    import com.fasterxml.jackson.core.JsonParser;
    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.core.JsonToken;
    import com.fasterxml.jackson.databind.DeserializationContext;
    import com.fasterxml.jackson.databind.JsonDeserializer;
    
    import java.io.IOException;
    
    public class ImageDeserializer extends JsonDeserializer<Image> {
    
        @Override
        public Image deserialize(final JsonParser parser, final DeserializationContext context)
                throws IOException, JsonProcessingException {
            final JsonToken type = parser.currentToken();
            switch (type) {
                case VALUE_NULL:
                    return null;
                case VALUE_STRING:
                    return null; // TODO: Should check whether it is empty
                case START_OBJECT:
                    return context.readValue(parser, Image.class);
                default:
                    throw new IllegalArgumentException("Unsupported JsonToken type: " + type);
            }
        }
    
    }
    

    And use it using the following code

    @JsonDeserialize(using = ImageDeserializer.class)
    @JsonProperty("image")
    public Image image;