web-dev-qa-db-fra.com

Jackson sérialise mal ZonedDateTime dans Spring Boot

J'ai une application simple avec Spring Boot et Jetty. J'ai un contrôleur simple qui retourne un objet qui a une Java 8 ZonedDateTime:

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

Dans ma RestController j'ai simplement: 

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

Je m'attendais à ce que la ZonedDateTime soit formatée conformément au format ISO, mais au lieu de cela, je reçois un dump JSON complet de la classe comme suit:

"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", ...

Je viens d'avoir une application spring-boot-starter-web, en utilisant spring-boot-starter-jetty et en excluant spring-boot-starter-Tomcat.

Pourquoi Jackson se comporte-t-il de la sorte dans Spring Boot?

** METTRE À JOUR **

Pour ceux qui recherchent un guide complet étape par étape sur la façon de résoudre ce problème, j'ai trouvé ceci après avoir posé la question: http://lewandowski.io/2016/02/formatting-Java-time-spring- boot-using-json /

19
jbx

Il existe une bibliothèque jackson-datatype-jsr310 . Essayez-le.

Cette bibliothèque couvre la nouvelle API datetime et inclut des sérialiseurs pour ZonedDateTime.

Tout ce dont vous avez besoin est simplement d’ajouter JavaTimeModule:

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

METTRE &AGRAVE; JOUR

Pour convertir date/heure en ISO-8601 string, vous devez désactiver WRITE_DATES_AS_TIMESTAMPS feature. Vous pouvez facilement le faire en remplaçant le bean ObjectMapper ou en utilisant propriétés de l'application :

spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS = false
30
vsminkov

Si vous ne vous fiez pas à la fonctionnalité de configuration automatique de SpringBoot - vous ne fournissez pas la propriété spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS = false dans votre fichier de configuration - ou pour une raison quelconque, vous créez manuellement une instance ObjectMapper. Vous pouvez désactiver cette fonctionnalité par programme comme suit:

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

ceci est pour jackson 2.8.7

0
bpawlowski

La réponse a déjà été mentionnée ci-dessus, mais je pense qu'il manque des informations. Pour ceux qui cherchent à analyser les horodatages Java 8 sous de nombreuses formes (pas seulement ZonedDateTime). Vous avez besoin d'une version récente de jackson-datatype-jsr310 dans votre POM et le module suivant est enregistré:

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

Pour tester ce code

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

Notez que vous pouvez configurer votre mappeur d’objets globalement dans Spring ou dans l’assistant dropwizard pour y parvenir. Je n'ai pas encore trouvé de moyen propre de le faire en tant qu'annotation sur un champ sans enregistrer un (dés) sérialiseur personnalisé.

0
UltimaWeapon