webentwicklung-frage-antwort-db.com.de

Jackson serialisiert eine ZonedDateTime falsch in Spring Boot

Ich habe eine einfache Anwendung mit Spring Boot und Jetty. Ich habe einen einfachen Controller, der ein Objekt mit Java 8 ZonedDateTime zurückgibt:

public class Device {
  // ...
  private ZonedDateTime lastUpdated;

  public Device(String id, ZonedDateTime lastUpdated, int course, double latitude, double longitude) {
    // ...
    this.lastUpdated = lastUpdated;
    // ...
  }

  public ZonedDateTime getLastUpdated() {
    return lastUpdated;
  }
}

In meiner RestController habe ich einfach: 

@RequestMapping("/devices/")
public @ResponseBody List<Device> index() {
  List<Device> devices = new ArrayList<>();
  devices.add(new Device("321421521", ZonedDateTime.now(), 0, 39.89011333, 24.438176666));

  return devices;
}

Ich hatte erwartet, dass die ZonedDateTime entsprechend dem ISO-Format formatiert wird, aber stattdessen bekomme ich einen vollständigen JSON-Dump der Klasse:

"lastUpdated":{"offset":{"totalSeconds":7200,"id":"+02:00","rules":{"fixedOffset":true,"transitionRules":[],"transitions":[]}},"zone":{"id":"Europe/Berlin","rules":{"fixedOffset":false,"transitionRules":[{"month":"MARCH","timeDefinition":"UTC","standardOffset":{"totalSeconds":3600,"id":"+01:00","rules":{"fixedOffset":true,"transitionRules":[],"transitions":[]}},"offsetBefore":{"totalSeconds":3600,"id":"+01:00","rules":{"fixedOffset":true,"transitionRules":[],"transitions":[]}},"offsetAfter":{"totalSeconds":7200,"id":"+02:00", ...

Ich habe nur eine spring-boot-starter-web-Anwendung mit spring-boot-starter-jetty und ausschließlich spring-boot-starter-Tomcat.

Warum verhält sich Jackson in Spring Boot so?

** UPDATE **

Für diejenigen, die eine vollständige Schritt-für-Schritt-Anleitung zur Lösung dieses Problems suchen, habe ich diese gefunden, nachdem ich die Frage gestellt hatte: http://lewandowski.io/2016/02/formatting-Java-time-with-spring-boot -using-json/

19
jbx

Es gibt eine Bibliothek jackson-datatype-jsr310 . Versuch es.

Diese Bibliothek deckt die neue datetime-API ab und enthält auch Serialisierer für ZonedDateTime.

Sie müssen lediglich JavaTimeModule hinzufügen:

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());

UPDATE

Um datetime in ISO-8601 string zu konvertieren, sollten Sie die WRITE_DATES_AS_TIMESTAMPS -Funktion deaktivieren. Sie können dies einfach tun, indem Sie entweder ObjectMapper bean überschreiben oder application properties verwenden:

spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS = false
30
vsminkov

Wenn Sie sich nicht auf die Funktion zur automatischen Konfiguration von SpringBoot verlassen, geben Sie die spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS = false -Eigenschaft nicht in Ihre Konfigurationsdatei ein. Aus irgendeinem Grund erstellen Sie die ObjectMapper-Instanz manuell. Sie können diese Funktion programmatisch wie folgt deaktivieren:

ObjectMapper m = new ObjectMapper();
m.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

dies ist für Jackson 2.8.7

0
bpawlowski

Die Antwort wurde bereits oben erwähnt, aber ich glaube, es fehlen einige Informationen. Für diejenigen, die Java 8-Zeitstempel in vielen Formen analysieren möchten (nicht nur ZonedDateTime). Sie benötigen eine aktuelle Version von jackson-datatype-jsr310 in Ihrem POM und haben das folgende Modul registriert:

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule());
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);

Um diesen Code zu testen

@Test
void testSeliarization() throws IOException {
    String expectedJson = "{\"parseDate\":\"2018-12-04T18:47:38.927Z\"}";
    MyPojo pojo = new MyPojo(ZonedDateTime.parse("2018-12-04T18:47:38.927Z"));

    // serialization
    assertThat(objectMapper.writeValueAsString(pojo)).isEqualTo(expectedJson);

    // deserialization
    assertThat(objectMapper.readValue(expectedJson, MyPojo.class)).isEqualTo(pojo);
}

Beachten Sie, dass Sie Ihre Objektzuordnung global in Spring oder Dropwizard konfigurieren können, um dies zu erreichen. Ich habe noch keine saubere Methode gefunden, um dies als Anmerkung zu einem Feld zu tun, ohne einen benutzerdefinierten (de) Serialisierer zu registrieren.

0
UltimaWeapon