web-dev-qa-db-fra.com

Jackson désérialise la date/heure au format ISO 8601 dans Java 8 Instant

J'essaie de désérialiser une date au format ISO8601 dans Java8 Instant à l'aide de Jackson. J'ai enregistré JavaTimeModule avec ObjectMapper, désactivé WRITE_DATES_AS_TIMESTAMPS.

Cependant, si on essaie de désérialiser le 2016-03-28T19: 00: 00.000 + 01: 00, cela ne fonctionnera pas, car il semblerait que JavaTimeModule ne désérialise que les dates date formatées avec le décalage du fuseau horaire UTC (par exemple, : 00.000Z). J'ai ensuite essayé d'utiliser l'annotation @JsonFormat comme ceci:

@JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-dd'T'HH:mm:ss.SSSZ", timezone = "UTC")

Et comme ça:

@JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-dd'T'HH:mm:ss.SSSZ", timezone = JsonFormat.DEFAULT_TIMEZONE)

Cependant, ni l'un ni l'autre ne fonctionne et je reçois une exception:

com.fasterxml.jackson.databind.JsonMappingException: Unsupported field: YearOfEra (through reference chain: org.example.Article["date"])

Ce qui implique que le paramètre fuseau horaire est ignoré et que le formateur de date/heure ne sait pas comment formater un instantané sans fuseau horaire. 

Existe-t-il un moyen de désérialiser une chaîne ISO8601 qui n'est pas dans le fuseau horaire UTC décalé vers Java 8 Instant à l'aide de Jackson et de JavaTimeModule sans écrire de désérialiseur personnalisé?

25
Kresimir Nesek

Vous devez définir le fuseau horaire explicite via XXX dans votre classe de modèle:

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX")
private Date date;

(voir: https://docs.Oracle.com/javase/7/docs/api/Java/text/SimpleDateFormat.html )

23
Meiko Rachimow

Le format "Z" ne fonctionne pas avec "+01: 00" car il s'agit d'un modèle différent . JsonFormat utilise des modèles SimpleDateFormat. "Z" dans les majuscules ne représentent que la RFC 822 stricte. Vous devez utiliser une syntaxe telle que: "+0100", sans les deux points.

Voir: ISO 8601: 2004 , modèles SimpleDateFormat

Dans Jackson 2.9.8 (la version actuelle est celle où j'écris ceci), il est préférable d'utiliser Instant au lieu de Date. 

Vous devez ajouter une dépendance:

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
    <version>2.9.8</version>
</dependency> 

Enregistrez également le module et configurez SerializationFeature.WRITE_DATES_AS_TIMESTAMPS sur false.

new ObjectMapper()
                .findAndRegisterModules()
                .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);

Plus d'informations sur Jackson for Java8 ici: https://github.com/FasterXML/jackson-modules-Java8

1
zoomout

Si vous souhaitez sérialiser des objets Date dans ISO-8601, vous n'avez pas du tout besoin de spécifier un modèle - ISO-8601 est le modèle par défaut. Il est en quelque sorte mentionné dans le JsonFormat Java doc :

Les utilisations courantes incluent le choix entre des représentations alternatives - par exemple, si Date doit être sérialisé en tant que nombre (horodatage Java) ou String (telle qu'une valeur de temps compatible ISO-8601) -, ainsi que la configuration des détails exacts avec un motif () propriété.

Vous devez comprendre d'après le texte ci-dessus que spécifier shape = STRING signifierait un format ISO-8601 mais que vous pouvez choisir autre chose à l'aide de la propriété pattern.

D'après mon expérience, cela donne toujours un format de date UTC (avec le fuseau horaire affiché en tant que +0000), qui peut être le fuseau horaire par défaut de mon VM (même si l'horloge de mon système d'exploitation n'est pas définie sur UTC).

0
Guss