Je travaille sur la conversion de certains modèles dans une application d'API REST spring-boot pour qu'ils utilisent le code Java.time.LocalDateTime
de Java 8 au lieu du paramètre DateTime
de joda. Je souhaite que les horodatages renvoyés par l'appel de l'API adhèrent au format ISO_8601
. La motivation doit être compatible avec le temps de Java 8 ( plus ici ).
La partie qui s'avère difficile concerne la sérialisation d'un objet contenant LocalDateTime
en JSON.
Par exemple, j'ai l'entité suivante:
// ... misc imports
import Java.time.LocalDateTime;
import Java.time.ZoneOffset;
@Data
@Entity
@Table(name = "users")
public class User {
@Id @Column
private String id;
@Column
private String name;
@Column
private String email;
@Column
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss", timezone = "UTC")
private Java.time.LocalDateTime createdAt;
public User(String name, String email) {
this.id = Utils.generateUUID();
this.createdAt = LocalDateTime.now(ZoneOffset.UTC);
}
}
J'ai également défini mon application.properties
pour désactiver les dates en tant qu'option timestamp jackson:
spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS = false
Mon maven deps:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>1.3.6.RELEASE</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.8.1</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.0.1.Final</version>
</dependency>
Enfin, j'essaie de récupérer la représentation JSON via le contrôleur:
@RequestMapping("/users")
@RestController
public class UserController {
private UserService userService;
@Autowired
public UserController(UserService userService) {
this.userService = userService;
}
@RequestMapping(
value = "/{id}",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_UTF8_VALUE
)
public User getUser(@PathVariable("id") String id) {
return userService.findById(id);
}
}
Lorsque je passe un appel à ce noeud final, j'obtiens l'exception suivante:
Java.lang.NoSuchMethodError:
com.fasterxml.jackson.datatype.jsr310.ser.JSR310FormattedSerializerBase.findFormatOverrides(Lcom/fasterxml/jackson/databind/SerializerProvider;Lcom/fasterxml/jackson/databind/BeanProperty;Ljava/lang/Class;)Lcom/fasterxml/jackson/annotation/JsonFormat$Value;
Alternativement, j'ai également configuré la variable ObjectMapper
de l'application dans la classe de configuration:
@Configuration
public class ServiceConfiguration {
@Bean
public ObjectMapper getJacksonObjectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule());
objectMapper.configure(
com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,
false
);
return objectMapper;
}
}
Toute piste sera grandement appréciée.
Il s'avère que c'était une incompatibilité de version entre la version Jackson de Spring Boot et celle que j'avais dans mon pom.xml
. Comme Miloš et Andy l'ont proposé, une fois que j'ai défini la version correcte et exécuté l'application avec spring.jackson.serialization.write_dates_as_timestamps=true
, le problème a été résolu, sans qu'il soit nécessaire de configurer ObjectMapper
ni d'ajouter des annotations sur mes champs de modèle LocalDateTime
.
...
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.3.6.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>1.3.6.RELEASE</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
</dependency>
</dependencies>
La NoSuchMethodError
est due au fait que vous mélangez des versions de Jackson. Spring Boot 1.3.6 utilise Jackson 2.6.7 et vous utilisez 2.8.1 de jackson-datatype-jsr310
.
Spring Boot fournit une gestion des dépendances pour Jackson, y compris jackson-datatype-jsr310
. Vous devez donc supprimer la version de votre pom. Si vous souhaitez utiliser une version différente de Jackson, vous devez redéfinir la propriété jackson.version
:
<properties>
<jackson.version>2.8.1</jackson.version>
</properties>
Cela garantira que toutes vos dépendances de Jackson auront la même version, évitant ainsi les problèmes de versions incompatibles.
Vous pouvez également, si vous le souhaitez, supprimer votre code Java configurant la variable ObjectMapper
. Le module Java Time sera automatiquement enregistré quand il se trouvera dans le chemin de classe et les dates d'écriture car les horodatages peuvent être configurés dans application.properties
:
spring.jackson.serialization.write-dates-as-timestamps=false
Votre bean ObjectMapper
doit être marqué @Primary
pour pouvoir être récupéré avant le printemps. Sinon, vous pouvez simplement créer un bean JavaTimeModule
et il sera sélectionné par Spring et ajouté au mappeur d'objets par défaut.
Vous l'avez probablement déjà vu mais jetez un coup d'œil à la documentation officielle .
L'erreur se produit parce que vous mélangez des versions de Jackson. Vous utilisez la version 1.3.6.RELEASE
de Spring Boot. Si vous souhaitez migrer vers la version Spring de démarrage 2.x.x.RELEASE
, vous pouvez remplacer la dépendance com.fasterxml.jackson.datatype
par une dépendance spring-boot-starter-json
. De cette façon, vous laissez Spring Boot s’occuper de la bonne version de Jackson.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
</dependency>