Comment utiliser le mappeur Jackson JSON avec Java 8 LocalDateTime?
org.codehaus.jackson.map.JsonMappingException: impossible d'instancier la valeur de type [type simple, classe Java.time.LocalDateTime] à partir de JSON String; pas de méthode constructeur/chaîne à chaîne unique (via la chaîne de référence: MyDTO ["field1"] -> SubDTO ["date"])
Il n'est pas nécessaire d'utiliser des sérialiseurs/désérialiseurs personnalisés ici. Utilisez le module datetime de jackson-modules-Java8 :
Module de type de données permettant à Jackson de reconnaître les types de données de l'API Date et heure de Java 8 (JSR-310).
Ce module ajoute le support pour pas mal de classes:
Mise à jour: laisser cette réponse pour des raisons historiques, mais je ne le recommande pas. Veuillez voir la réponse acceptée ci-dessus.
Dites à Jackson de mapper à l'aide de vos classes de sérialisation [de] personnalisées:
@JsonSerialize(using = LocalDateTimeSerializer.class)
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
private LocalDateTime ignoreUntil;
fournir des classes personnalisées:
public class LocalDateTimeSerializer extends JsonSerializer<LocalDateTime> {
@Override
public void serialize(LocalDateTime arg0, JsonGenerator arg1, SerializerProvider arg2) throws IOException {
arg1.writeString(arg0.toString());
}
}
public class LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {
@Override
public LocalDateTime deserialize(JsonParser arg0, DeserializationContext arg1) throws IOException {
return LocalDateTime.parse(arg0.getText());
}
}
fait aléatoire: si je niche au-dessus des classes et ne les rend pas statiques, le message d'erreur est étrange: org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/json;charset=UTF-8' not supported
Si vous utilisez la classe ObjectMapper de plus rapide, Par défaut, ObjectMapper ne comprend pas la classe LocalDateTime, vous devez donc ajouter une autre dépendance à votre classe/maven:
compile 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.7.3'
Vous devez maintenant enregistrer le support de types de données offert par cette bibliothèque dans votre objet objectmapper. Pour ce faire, procédez comme suit:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.findAndRegisterModules();
Maintenant, dans votre jsonString, vous pouvez facilement insérer votre champ Java.LocalDateTime comme suit:
{
"user_id": 1,
"score": 9,
"date_time": "2016-05-28T17:39:44.937"
}
En procédant ainsi, la conversion de votre fichier Json en objet Java fonctionnera correctement. Vous pouvez le lire en procédant comme suit:
objectMapper.readValue(jsonString, new TypeReference<List<User>>() {
});
Cette dépendance maven va résoudre votre problème:
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.6.5</version>
</dependency>
Une chose que j'ai eu du mal à faire est que pour le fuseau horaire ZonedDateTime qui a été changé en GMT pendant la désérialisation….
Jackson2ObjectMapperBuilder.json()
.featuresToDisable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE)
J'ai eu un problème similaire lors de l'utilisation de Spring Boot . Avec Spring Boot 1.5.1.RELEASE, tout ce que j'avais à faire est d'ajouter une dépendance:
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
Si vous utilisez Jersey, vous devez ajouter la dépendance Maven (jackson-datatype-jsr310) comme les autres suggestions et enregistrer votre instance de mappeur d'objets de la manière suivante:
@Provider
public class JacksonObjectMapper implements ContextResolver<ObjectMapper> {
final ObjectMapper defaultObjectMapper;
public JacksonObjectMapper() {
defaultObjectMapper = createDefaultMapper();
}
@Override
public ObjectMapper getContext(Class<?> type) {
return defaultObjectMapper;
}
private static ObjectMapper createDefaultMapper() {
final ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
return mapper;
}
}
Lorsque vous enregistrez Jackson dans vos ressources, vous devez ajouter ce mappeur comme suit:
final ResourceConfig rc = new ResourceConfig().packages("<your package>");
rc
.register(JacksonObjectMapper.class)
.register(JacksonJaxbJsonProvider.class);
Si vous ne pouvez pas utiliser jackson-modules-Java8
pour une raison quelconque, vous pouvez (dés) sérialiser le champ instant tant que vous utilisez @JsonIgnore
et @JsonGetter
& @JsonSetter
:
public class MyBean {
private Instant time = Instant.now();
@JsonIgnore
public Instant getTime() {
return this.time;
}
public void setTime(Instant time) {
this.time = time;
}
@JsonGetter
private long getEpochTime() {
return this.time.toEpochMilli();
}
@JsonSetter
private void setEpochTime(long time) {
this.time = Instant.ofEpochMilli(time);
}
}
Exemple:
@Test
public void testJsonTime() throws Exception {
String json = new ObjectMapper().writeValueAsString(new MyBean());
System.out.println(json);
MyBean myBean = new ObjectMapper().readValue(json, MyBean.class);
System.out.println(myBean.getTime());
}
les rendements
{"epochTime":1506432517242}
2017-09-26T13:28:37.242Z
Si quelqu'un rencontre un problème lors de l'utilisation de SpringBoot
, voici comment j'ai résolu le problème sans ajouter de nouvelle dépendance.
Dans Spring 2.1.3
, Jackson s'attend à ce que la chaîne de date 2019-05-21T07:37:11.000
de ce format yyyy-MM-dd HH:mm:ss.SSS
soit désérialisée en LocalDateTime
. Assurez-vous que la chaîne de date sépare la date et l'heure avec T
pas avec space
. secondes (ss
) et millisecondes (SSS
) peuvent être omis.
@JsonProperty("last_charge_date")
public LocalDateTime lastChargeDate;
Pour ceux qui utilisent Spring Boot 2.x
Aucune des opérations ci-dessus n’est nécessaire: Java 8 LocalDateTime est sérialisé/désérialisé par défaut. Je devais faire tout ce qui précède dans 1.x, mais avec Boot 2.x, cela fonctionne de manière transparente.
Voir aussi cette référence - Format JSON Java 8 LocalDateTime dans Spring Boot
Vous pouvez définir ceci dans votre fichier application.yml
pour résoudre Instant Time, qui est Date API in Java8:
spring.jackson.serialization.write-dates-as-timestamps=false
Si vous utilisez Spring Boot et avez ce problème avec OffsetDateTime, vous devez utiliser les registerModules comme indiqué ci-dessus par @greperror (répondu le 28 mai 16 à 13:04), mais notez qu'il existe une différence. La dépendance mentionnée n'a pas besoin d'être ajoutée car je suppose que cette botte de printemps l'a déjà. J'avais ce problème avec le démarrage de printemps et cela a fonctionné pour moi sans ajouter cette dépendance.
Si vous envisagez d’utiliser fastjson, vous pouvez résoudre votre problème en notant la version.
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.56</version>
</dependency>