java jackson deserializer如何处理同一字段上的Boolean和Object

时间:2017-04-25 06:20:36

标签: java json jackson deserialization

我正在使用第三方JSON API,它会返回如下数据:

{details: {...}, ...}

我使用Java Jackson将此JSON字符串反序列化为POJO对象,字段声明为:

@JsonProperty("details") public Details getDetails(){...}

Details是另一个类。

一切都很好,直到我发现API可能返回这样的数据:

{details: false, ...}

如果详细信息为空,则返回false !!!杰克逊给了我这个例外:

com.fasterxml.jackson.databind.JsonMappingException: Can not instantiate value of type [simple type, class Details] from Boolean value; no single-boolean/Boolean-arg constructor/factory method (through reference chain: ...["details"])

那么,如何处理这种JSON字符串?如果为空,我只需要将此字段设置为null。

2 个答案:

答案 0 :(得分:2)

来自Jackson的错误消息暗示该库具有支持静态工厂方法的功能。这可能是一个比自定义反序列化器更简单的解决方案:

我创建了这个示例POJO,使用静态工厂方法,注释以便Jackson使用它:

public class Details {
    public String name;  // example property

    @JsonCreator
    public static Details factory(Map<String,Object> props) {

        if (props.get("details") instanceof Boolean) return null;

        Details details = new Details();
        Map<String,Object> detailsProps = (Map<String,Object>)props.get("details");
        details.name = (String)detailsProps.get("name");
        return details;
    }
}

测试方法:

public static void main(String[] args)
{
    String fullDetailsJson = "{\"details\": {\"name\":\"My Details\"}} ";
    String emptyDetailsJson = "{\"details\": false} ";
    ObjectMapper mapper = new ObjectMapper();
    try {
        Details details = mapper.readValue(fullDetailsJson, Details.class);
        System.out.println(details.name);
        details = mapper.readValue(emptyDetailsJson, Details.class);
        System.out.println(details);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

结果如预期:

My Details
null

答案 1 :(得分:1)

创建一个自定义JsonDeserializer来处理反序列化你的Details对象,如果你得到false则返回null,或者如果它是一个实际的对象,则将对象传递给默认的反序列化器。伪代码:

public class CustomDeserializer extends JsonDeserializer<Details>{
    @Override
    public Details deserialize(JsonParser jsonParser, DeserializationContext ctx){
        //if object use default deserializer else return null
    }
}

您还必须编写一个ObjectMapperProvider来注册您的反序列化器,如下所示:

@Provider
public class ObjectMapperProvider implements ContextResolver<ObjectMapper>{
    private ObjectMapper mapper;

    public ObjectMapperProvider(){
        mapper = new ObjectMapper();
        SimpleModule sm = new SimpleModule();
        sm.addDeserializer(Details.class, new CustomDeserializer());
        mapper.registerModule(sm);
    }

    public ObjectMapper getContext(Class<?> arg0){
        return mapper;
    }
}