如何告诉杰克逊反序列化" null"字符串为null literal?

时间:2014-09-17 01:47:16

标签: java json jackson deserialization

我有一个webservice,它将“null”打印为任何属性的字符串,而不是null literal。它适用于几乎所有数据类型(String或Date)。例如,在理想情况下,它返回

{
    "item" : {
        "title": "Some title",
        "expires": "2014-11-02 00:00:00"
    }
}

但有时它会返回:

{
    "item" : {
        "title": "null",
        "expires": "2014-11-02 00:00:00"
    }
}

这使得title属性值为“null”,而不是将其设置为null。 或者有时候这个:

{
    "item" : {
        "title": "Some title",
        "expires": "null"
    }
}

这使得反序列化失败,因为dateformat不匹配。 如何配置objectmapper或注释我的模型类以在反序列化期间解决这些问题?

我的模型类看起来像:

@JsonInclude(JsonInclude.Include.NON_NULL)
public class Item {
    public String title;
    @JsonFormat(shape= JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss")
    public Date expires;
}

这是一个Android应用程序,所以我无法控制webservice。提前致谢

3 个答案:

答案 0 :(得分:1)

如果您使用自定义Deserializer,则可以执行此操作,但我认为无法使用标准注释。

借用和修改http://www.baeldung.com/jackson-deserialization中的一些代码:

public class ItemDeserializer extends JsonDeserializer<Item> {

    @Override
    public Item deserialize(JsonParser jp, DeserializationContext ctxt)
      throws IOException, JsonProcessingException {
        JsonNode node = jp.getCodec().readTree(jp);
        String title = null;
        TextNode titleNode = (TextNode)node.get("title");
        if ( ! titleNode.toString().equals("null")) {
            title = titleNode.toString();
        }

        Date expires = null;
        // similar logic for expires

        return new Item(title, expires);
    }
}

答案 1 :(得分:1)

不确定是否需要,但如果您使用的是ObjectMapper,则可以执行以下操作:

1)删除@JsonFormat(shape= JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss")。我还为您显示输入数据的方式添加了@JsonRootName

@JsonRootName("item")
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Item {
    public String title;
    public Date expires;
    @Override
    public String toString() {
        return "Item{" +
           "title='" + title + '\'' +
           ", expires=" + expires +
          '}';
    }
}

2)并使用您要使用的DateFormat配置ObjectMapper:

mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:s"));

以下是我测试的完整示例:

public class Test {
    private static final String T1 = "{\n"+
            "    \"item\" : {\n"+
            "        \"title\": \"Some title\",\n"+
            "        \"expires\": \"2014-11-02 00:00:00\"\n"+
            "    }\n"+
            "}";
    private static final String T2 = "{\n" +
            "    \"item\" : {\n" +
            "        \"title\": \"null\",\n" +
            "        \"expires\": \"2014-11-02 00:00:00\"\n" +
            "    }\n" +
            "}";
    private static final String T3 = "{\n" +
            "    \"item\" : {\n" +
            "        \"title\": \"Some title\",\n" +
            "        \"expires\": \"null\"\n" +
            "    }\n" +
            "}";

    public static void main(String[] args) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
        mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:s"));
        Item t1 = mapper.readValue(T1, Item.class);
        Item t2 = mapper.readValue(T2, Item.class);
        Item t3 = mapper.readValue(T3, Item.class);
        System.out.println(t1);
        System.out.println(t2);
        System.out.println(t3);
        System.out.println(mapper.writeValueAsString(t1));
        System.out.println(mapper.writeValueAsString(t2));
        System.out.println(mapper.writeValueAsString(t3));
    }
}

结果。上次打印输出显示@JsonInclude如何影响输出,以及如何使用此配置完成输入字符串&#39; null&#39; 的序列化:

Item{title='Some title', expires=Sun Nov 02 00:00:00 PDT 2014}
Item{title='null', expires=Sun Nov 02 00:00:00 PDT 2014}
Item{title='Some title', expires=null}
{"title":"Some title","expires":"2014-11-02 00:00:0"}
{"title":"null","expires":"2014-11-02 00:00:0"}
{"title":"Some title"}

答案 2 :(得分:1)

someone asked this question again几分钟以来,我进行了一些研究,认为我找到了一个很好的解决此问题的方法(在处理字符串时)。

您必须创建一个自定义JsonDeserializer类,如下所示:

class NullStringJsonDeserializer extends JsonDeserializer<String> {
    @Override
    public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        String result = StringDeserializer.instance.deserialize(p, ctxt);
        return result!=null && result.toLowerCase().equals(null+"") ? null : result;
    }
}

最后但并非最不重要的,您要做的就是告诉您的ObjectMapper它应该使用自定义的json字符串反序列化器。 这取决于您使用ObjectMapper的方式和位置,但是看起来像这样:

ObjectMapper objectMapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(String.class, new NullStringJsonDeserializer());
objectMapper.registerModule(module);
相关问题