Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/315.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java “如何告诉杰克逊去反序列化”;空";字符串转换为空文本?_Java_Json_Jackson_Deserialization - Fatal编程技术网

Java “如何告诉杰克逊去反序列化”;空";字符串转换为空文本?

Java “如何告诉杰克逊去反序列化”;空";字符串转换为空文本?,java,json,jackson,deserialization,Java,Json,Jackson,Deserialization,我有一个Web服务,它将“null”打印为任何属性的字符串,而不是null文本。它几乎对所有数据类型(字符串或日期)都这样做。例如,在理想情况下,它返回 { "item" : { "title": "Some title", "expires": "2014-11-02 00:00:00" } } 但有时它会回来: { "item" : { "title": "null", "expires": "2014

我有一个Web服务,它将“null”打印为任何属性的字符串,而不是null文本。它几乎对所有数据类型(字符串或日期)都这样做。例如,在理想情况下,它返回

{
    "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应用程序,所以我无法控制Web服务。提前感谢

如果您使用自定义的反序列化程序,您可以这样做,但我认为使用标准注释是不可用的

从以下位置借用和修改某些代码:

公共类ItemDeserializer扩展JsonDeserializer{
@凌驾
公共项反序列化(JsonParser jp,反序列化上下文ctxt)
抛出IOException、JsonProcessingException{
JsonNode节点=jp.getCodec().readTree(jp);
字符串标题=null;
TextNode titleNode=(TextNode)node.get(“title”);
如果(!titleNode.toString().equals(“null”)){
title=titleNode.toString();
}
到期日期=空;
//expires的类似逻辑
返回新项目(标题、过期);
}
}

不确定是否需要,但如果使用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
如何影响输出,以及输入字符串'null'的序列化是如何使用此配置完成的:

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"}
几分钟前,我做了一些研究,认为我找到了解决这个问题的好方法(在处理字符串时)

您必须创建自定义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;
    }
}

JSON表示该值是一个字符串,没有解析器会将其视为其他值。您所能做的就是添加代码,然后将字符串与“null”进行比较然后相应地采取行动。只为接受JsonNode或任何东西的项编写构造函数可能更简单。也许-但我已经在用序列化注释来注释应用程序域对象时有点畏缩了-将反序列化逻辑直接添加到POJO构造函数中让我真的很畏缩--依我看,这真的是关注点分离不好。我在Item类中有大约30个属性,而在我的项目中几乎没有其他类似的类。这对我来说不是一个可接受的解决方案。我在寻找一个更通用的解决方案。可能是豆豆改良剂?还是自定义零检测器?当我看到杰克逊风格的东西时,我会畏缩。实际上会扭曲JSON和类,而接受映射的构造函数则非常直接和合理。如果您使用一个JSON工具包来提供映射而不是自定义JSON对象,那么它根本不会将您与JSON(“混合关注点”)联系起来。@HotLicks,Jackson数据绑定以什么方式扭曲JSON?此外,与从构造函数内部的映射中提取项相比,编写一个自定义反序列化程序从JsonParser中提取节点并将其传递给构造函数只需付出很少的努力,并且不会让您感到必须彻底记录和清理映射键的不愉快。当您需要在松散类型(例如JSON)和静态类型数据之间进行转换时,请将其保存在自己的层中——这会使您的生活变得更好,尽管会更加冗长。
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 objectMapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(String.class, new NullStringJsonDeserializer());
objectMapper.registerModule(module);