Java “如何告诉杰克逊去反序列化”;空";字符串转换为空文本?
我有一个Web服务,它将“null”打印为任何属性的字符串,而不是null文本。它几乎对所有数据类型(字符串或日期)都这样做。例如,在理想情况下,它返回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
{
"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);