2016-11-18 11 views
0

Ich lese JSON-Daten von einer API mit Jackson und die meiste Zeit bekomme ich eine Reihe von Objekten, die alle ziemlich Standard in ihrer Implementierung sind. Das einzige Problem ist, dass Daten manchmal im Format "yyyy-MM-dd'T'HH: mm: ss.SSS'Z '" und manchmal im Format "yyyy-MM-dd" vorliegen, so dass der JSON aussieht dies:Parsing Json Termine mit unterschiedlichen Standards

[ 
    { 
     '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' 
    } 
] 

Jedes Mal, wenn ich zu diesem zweiten Datum komme, bekomme ich einen Parserfehler, weil es nicht im selben Format ist. Ich habe versucht, eine Klasse zu schreiben, die ein zweites DateFormat verwenden wird, wenn das erste fehlschlägt, aber jetzt bekomme ich nur eine 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; 
    } 
} 

Sein ist der Fehler Ich erhalte:

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) 

Dies ist der Code in Zeile 56:

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

Wer weiß, wie ich entweder meine aktuellen Code festsetzt keinen Null-Zeiger bekommen oder zwei Datenformate in Jackson verwenden?

Antwort

1

Ich habe Probleme, genau zu sagen, was Ihr Problem ist, aber ich konnte Dinge mit dem Code arbeiten, den Sie haben. Zuerst habe ich ein POJO erstellt, das das Objekt darstellt, das Sie deserialisieren möchten. Ich bin eine Art vorausgesetzt, Sie bereits ein Äquivalent haben, aber das war meins:

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

Dann habe ich eine benutzerdefinierte Deserializer mit dem Objekt-Mapper. Die Klasse ist nicht zu schwierig zu implementieren. Ich habe Ihre BackupDateFormat Innenseite des Deserializer:

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; 
    } 

} 

Danach, registrieren Sie Ihre Serializer mit dem ObjectMapper:

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

Schließlich können Sie sehen, dass die Daten in geeigneter Weise aus diesem Snippet analysiert wurden und dessen Ausgang :

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

Wenn Sie etwas finden, das in Jackson eingebaut ist, das das tut, ermutige ich Sie, es zu benutzen, aber manchmal brauchen Sie die zusätzliche Stufe der Anpassung, die diese Methode bietet. Ich hoffe es hilft.

Überprüfen Sie auch die Frage unten. Es ist ähnlich, aber nicht mit mehreren Formaten. Die akzeptierte Antwort verwendet den benutzerdefinierten Deserializer ebenfalls.

Referenzen:

Similar SO Question

Getting started with deserializers