Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jackson: ignoring properties instead of throwing JsonMappingException

Tags:

java

json

jackson

I have a class that needs to be deserialized from JSON using Jackson. The class structure looks like this:

public class A {
    public B b;
}

public class B {
    public List<C> c;
}

public class C {
    public String s;
    public Long l1;
    public Long l2;
    public Long l3;
}

Deserializing objects mostly works fine; except, it is inter-operating with buggy code that emitted the wrong value when the list was empty. That is, instead of emitting:

{ "b" : { "c" : [] } }

it emitted:

{ "b" : { "c" : {} } }

Jackson throws this exception when it encounters this:

org.codehaus.jackson.map.JsonMappingException: Can not deserialize instance of java.util.ArrayList out of START_OBJECT token
 at [Source: [B@1ad5cabc; line: 1, column: 896] (through reference chain: A["b"]->B["c"])

This all makes sense, of course. The input is wrong.

However, the empty list in this case isn't relevant to any of the code; if it was null I wouldn't care. Is there any way to tell Jackson to ignore this property (and store null) if it's not possible to deserialize it?

I've tried using a custom deserializer:

public class CListDeserializer extends JsonDeserializer<List<C>>
{
    public CListDeserializer() { }

    @Override
    public List<C> deserialize(JsonParser arg0,
        DeserializationContext arg1) throws IOException,
            JsonProcessingException
    {
        try
        {
            return arg0.readValueAs(new TypeReference<List<C>>(){});
        }
        catch (JsonMappingException jme)
        {
        }
        return null;
    }
}

And if I add the annotation to the field:

@JsonDeserialize(using=CListDeserializer.class)
public List<C> c;

I get this exception instead:

org.codehaus.jackson.map.JsonMappingException: Can not instantiate value of type [simple type, class asgard.ChangeEntry] from JSON String; no single-String constructor/factory method (through reference chain: A["b"])

Note that this exception only happens if I try deserializing the outer type A -- if I pull out the inner serialized value for B, and deserialize that, it works fine.

like image 800
Casey Marshall Avatar asked Nov 04 '22 08:11

Casey Marshall


1 Answers

I've figured out why the custom deserializer doesn't work: the readValueAs method consumes the {, which triggers the exception, leaving } as the next token. This closes the inner object, and the parser will then think the enum value encountered next needs to be parsed as the inner type, not as the enum type.

I'll try this tomorrow, but I think the way to go is this, in the deserialize method:

ObjectMapper om = ...;

JsonNode node = arg0.readValueAs(JsonNode.class);
try
{
    return om.readValue(node, new TypeReference<List<C>>(){});
}
catch (JsonMappingException jme)
{
}
return null;
like image 69
Casey Marshall Avatar answered Nov 09 '22 13:11

Casey Marshall