2016-11-18 63 views
0

我正在使用Jackson读取API中的JSON数据,并且大部分时间我都得到一组对象,这些对象在其实现中都是相当标准的。唯一的问题是,有时日期格式为“yyyy-MM-dd'T'HH:mm:ss.SSS'Z'”,有时格式为“yyyy-MM-dd”,所以JSON看起来像这样的:分析不同标准的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)); 

有谁知道我怎么可以解决我当前的代码没有得到一个空指针或在杰克逊使用两个dateformats?

回答

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

如果您发现某些内置于Jackson的内容会执行此操作,我鼓励您使用它,但有时您最终需要使用此方法提供的额外级别的自定义。希望能帮助到你。

查看下面的问题。它是相似的,但不处理多种格式。接受的答案也使用自定义解串器。

参考文献:

Similar SO Question

Getting started with deserializers