2017-06-07 1 views
2

I JSON haben folgende:Jackson: Deserialisieren Epoche LOCALDATE

{ 
     "id" : "1", 
     "birthday" : 401280850089 
} 

Und POJO Klasse:

public class FbProfile { 
    long id; 
    @JsonDeserialize(using = LocalDateDeserializer.class) 
    LocalDate birthday; 
} 

Ich Jackson bin mit tun Deserialisierung:

public FbProfile loadFbProfile(File file) throws JsonParseException, JsonMappingException, IOException { 
    ObjectMapper mapper = new ObjectMapper(); 
    FbProfile profile = mapper.readValue(file, FbProfile.class); 
    return profile; 
} 

Aber es wirft eine Ausnahme:

com.fasterxml.jackson.databind.JsonMappingException: Unerwartetes Token (VALUE_NUMBER_INT), erwartet VALUE_STRING: Erwartetes Array oder Zeichenfolge.

Wie kann ich die Epoche zu LocalDate deserialisieren? Ich möchte hinzufügen, dass, wenn ich den Datentyp von LocalDate zu java.util.Date ändern, funktioniert es völlig in Ordnung. Also vielleicht ist es besser, zu java.util.Date zu deserialisieren und den Getter und Setter zu erstellen, der die Konvertierung zu/von LocalDate durchführt.

+1

Bitte beachten Sie, dass die Umwandlung von Millisekunden bis zum Datum zeitzonenabhängig ist. Zum Beispiel entspricht die Zahl in Ihrem Beispiel 1982-09-19T10: 54: 10.089Z, was wiederum gleich 1982-09-18T23: 54: 10.089-11: 00 [Pacific/Midway] ist. –

+1

Vermeiden Sie die altmodische Klasse "Date". Das einzige, was es dir gibt, dass moderne Klassen nicht Ärger sind. Wenn Sie andere Klassen als 'LocalDate' ausprobieren möchten, ist' Instant' die offensichtliche Wahl. –

+0

Haben Sie vor der Nachfrage gesucht? Ich denke, Sie finden vielleicht etwas Inspiration in [dieser Frage: Java 8 LocalDate Jackson Format] (https://stackoverflow.com/questions/28802544/java-8-localdate-jackson-format). –

Antwort

2

Ich habe es mein eigenes Deserializer schreiben tun verwaltet (danke @Ole V.V. mich Java 8 LocalDate Jackson format auf den Posten zu Punkt):

public class LocalDateTimeFromEpochDeserializer extends StdDeserializer<LocalDateTime> { 

    private static final long serialVersionUID = 1L; 

    protected LocalDateTimeFromEpochDeserializer() { 
     super(LocalDate.class); 
    } 

    @Override 
    public LocalDateTime deserialize(JsonParser jp, DeserializationContext ctxt) 
      throws IOException, JsonProcessingException { 
     return Instant.ofEpochMilli(jp.readValueAs(Long.class)).atZone(ZoneId.systemDefault()).toLocalDateTime(); 
    } 

} 

Hinweis über Zeitzone auch sehr nützlich ist. Vielen Dank!

Die noch offene Frage ist, ob es getan werden kann, ohne eigenen Deserializer schreiben?

+1

Das ist eine Vermutung: Ich rate, wenn Sie darauf bestehen, zwischen 'LocalDate' und Millisekunden seit der Epoche zu serialisieren, benötigen Sie Ihren eigenen Deserializer. Wenn Sie die langen Millisekunden durch eine formatierte Datumszeichenfolge * oder * ersetzen könnten, würden Sie akzeptieren, statt eines 'LocalDate' ein' Instant' zu erhalten, ich wäre optimistischer bei der Verwendung der integrierten Deserialisierung. Said hatte kaum die Oberfläche von Jackson gekratzt. Froh, dass du einen Weg gefunden hast. –

1

Ich habe einen Weg gefunden, es zu tun, ohne einen benutzerdefinierten Deserializer zu schreiben, aber es erfordert einige Modifikationen.

Zuerst akzeptiert die LocalDateDeserializer eine benutzerdefinierte . Also müssen wir einen Formatierer erstellen, der eine Epoche Millis akzeptiert. Ich tat dies, indem sie die INSTANT_SECONS und MILLI_OF_SECOND Felder Beitritt:

// formatter that accepts an epoch millis value 
DateTimeFormatter formatter = new DateTimeFormatterBuilder() 
    // epoch seconds 
    .appendValue(ChronoField.INSTANT_SECONDS, 1, 19, SignStyle.NEVER) 
    // milliseconds 
    .appendValue(ChronoField.MILLI_OF_SECOND, 3) 
    // create formatter, using UTC as timezone 
    .toFormatter().withZone(ZoneOffset.UTC); 

Ich habe auch die Formatierungs mit UTC-Zone, so wird es nicht von Zeitzonen und Sommerzeit-Änderungen betroffen sein.

Dann habe ich die Deserializer erstellt und registriert in meinem ObjectMapper:

ObjectMapper mapper = new ObjectMapper(); 
JavaTimeModule module = new JavaTimeModule(); 
// add the LocalDateDeserializer with the custom formatter 
module.addDeserializer(LocalDate.class, new LocalDateDeserializer(formatter)); 
mapper.registerModule(module); 

Ich musste auch die Anmerkung aus dem birthday Feld entfernen (da die Annotation die Modulkonfiguration außer Kraft zu setzen scheint):

public class FbProfile { 
    long id; 

    // remove @JsonDeserialize annotation 
    LocalDate birthday; 
} 

und jetzt die große Frage: wie die DateTimeFormatter nur String als Eingabe akzeptiert und die JSON enthält eine Reihe in birthday Feld, hatte ich das JSON zu ändern:

{ 
    "id" : "1", 
    "birthday" : "401280850089" 
} 

Bitte beachte, dass ich birthday zu einem String geändert (setzen Sie den Wert zwischen Anführungszeichen).

Damit wird die LocalDate korrekt von JSON lesen:

FbProfile value = mapper.readValue(json, FbProfile.class); 
System.out.println(value.getBirthday()); // 1982-09-19 

Hinweise:

  • ich keine Möglichkeit, die Nummer direkt an den Formatierer finden könnte passieren (Da es nur String als Eingabe benötigt), musste ich die Nummer zu einem String ändern. Wenn Sie das nicht möchten, müssen Sie sowieso einen benutzerdefinierten Konverter schreiben.
  • Sie können ZoneOffset.UTC durch eine beliebige Zeitzone ersetzen (sogar ZoneId.systemDefault()), es hängt davon ab, was Ihre Anwendung benötigt. Aber wie in @Ole V.V.'s comment erzählt, könnte die Zeitzone das Datum ändern.
+1

Leider kann ich die Struktur der JSON-Datei nicht ändern. Trotzdem danke für deine Antwort. – kpater87

+1

Gut durchdacht und recherchiert. –

Verwandte Themen