用不同的标准解析Json日期

时间:2016-11-18 18:08:04

标签: java json date jackson format

我正在使用Jackson从API读取JSON数据,并且大部分时间我都获得了一系列对象,这些对象在其实现中都是相当标准的。唯一的问题是,有时日期将采用以下格式:&y; -y;有时格式为" yyyy-MM-dd",所以JSON看起来像这样:

[
    {
        'A':'Foo'
        'B':'2016-11-03T12:35:23.032Z'
        'C':'7'
    },
    {
        'A':'Bar'
        'B':'2016-11-06'
        'C':'4'
    },
    {
        'A':'Bla'
        'B':'2016-11-07T14:42:18.832Z'
        'C':'23'
    },
    {
        'A':'Blo'
        'B':'2016-11-07T15:12:23.439Z'
        'C':'9'
    }
]

每次到达第二个日期时,我都会收到解析器错误,因为它的格式不同。我尝试编写一个将使用第二个DateFormat的类,如果第一个失败,但现在我只得到一个NullPointerException。

public class BackupDateFormat extends DateFormat {

    private final LinkedList<DateFormat> formats;

    public BackupDateFormat(DateFormat... dfs) {
        formats = new LinkedList<>(Arrays.asList(dfs));
    }

    @Override
    public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) {
        return formats.getFirst().format(date, toAppendTo, fieldPosition);
    }

    @Override
    public Date parse(String source, ParsePosition pos) {
        return formats.getFirst().parse(source, pos);
    }

    @Override
    public Date parse(String source) throws ParseException {
        ParseException exception = null;
        for (DateFormat df : formats) {
            try {
                return df.parse(source);
            }
            catch (ParseException pe) {
                exception = pe;
            }
        }
        throw exception;
    }
}

他是我得到的错误:

com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.NullPointerException) (through reference chain: com.company.api.API$Result["result"]->java.util.ArrayList[0]->com.company.models.othercompany.Record["dateTime"])
    at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:391)
    at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:351)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.wrapAndThrow(BeanDeserializerBase.java:1597)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:278)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:140)
    at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:294)
    at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:266)
    at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:26)
    at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:485)
    at com.fasterxml.jackson.databind.deser.impl.FieldProperty.deserializeAndSet(FieldProperty.java:108)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:276)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:140)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3836)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2860)
    at com.mentoredata.api.API.get(API.java:56)

这是第56行的代码:

return mapper.<List<T>>readValue(new URL(url), mapper.getTypeFactory().constructCollectionType(List.class, type));

有没有人知道我如何修复当前代码以获取空指针或在Jackson中使用两个日期格式?

1 个答案:

答案 0 :(得分:1)

我无法确切地告诉您问题是什么,但我能够使用您拥有的代码。首先,我创建了一个POJO,表示您尝试反序列化的对象。我有点假设你已经有一个等价物,但这是我的:

class Obj {
    String A;
    Date B;
    Integer C;
    /* with getters/setters */
}

然后,我使用对象映射器创建了一个自定义反序列化器。这个课程实施起来并不困难。我在反序列化器中使用了BackupDateFormat:

class ObjDeserializer extends JsonDeserializer<Obj> {
    final BackupDateFormat backupDateFormat;

    public ObjDeserializer() {
        backupDateFormat = new BackupDateFormat(
            new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"),
            new SimpleDateFormat("yyyy-MM-dd"));
    }

    @Override
    public Obj deserialize(JsonParser p, DeserializationContext ctxt)
            throws IOException, JsonProcessingException {
        // create a POJO and populate with the fields from the JSON Object
        Obj obj = new Obj();
        JsonNode root = p.readValueAsTree();
        obj.setA(root.get("A").asText(""));
        obj.setC(root.get("C").asInt(0));
        try {
            obj.setB(backupDateFormat.parse(root.get("B").asText()));
        } catch (ParseException e) {
            throw new IOException("Could not parse date as expected.");
        }
        return obj;
    }

}   

之后,使用ObjectMapper注册序列化程序:

SimpleModule dateDeserializerModule = new SimpleModule();
// associate the custom deserializer with your POJO
dateDeserializerModule.addDeserializer(Obj.class, new ObjDeserializer());
mapper.registerModule(dateDeserializerModule);

最后,您可以看到日期已从此代码段及其输出中正确解析:

List<Obj> result = mapper.readValue(input.getBytes(), mapper.getTypeFactory().constructCollectionType(List.class, Obj.class));
result.forEach(x->System.out.println(x.getB().toString()));

Thu Nov 03 12:35:23 EDT 2016 Sun Nov 06 00:00:00 EDT 2016 Mon Nov 07 14:42:18 EST 2016 Mon Nov 07 15:12:23 EST 2016

如果您发现杰克逊内置的内容会执行此操作,我建议您使用它,但有时您最终需要此方法提供的额外级别的自定义。希望它有所帮助。

也请查看下面的问题。它类似,但不处理多种格式。接受的答案也使用自定义反序列化器。

参考文献:

Similar SO Question

Getting started with deserializers