web-dev-qa-db-fra.com

Format JSON Java 8 LocalDateTime dans Spring Boot

J'ai un petit problème avec le formatage d'un Java 8 LocalDateTime dans mon application de démarrage Spring. Avec les dates «normales», je n'ai aucun problème, mais les champs LocalDateTime sont convertis comme suit:

"startDate" : {
    "year" : 2010,
    "month" : "JANUARY",
    "dayOfMonth" : 1,
    "dayOfWeek" : "FRIDAY",
    "dayOfYear" : 1,
    "monthValue" : 1,
    "hour" : 2,
    "minute" : 2,
    "second" : 0,
    "nano" : 0,
    "chronology" : {
      "id" : "ISO",
      "calendarType" : "iso8601"
    }
  }

Bien que je voudrais le convertir en quelque chose comme:

"startDate": "2015-01-01"

Mon code ressemble à ceci:

@JsonFormat(pattern="yyyy-MM-dd")
@DateTimeFormat(iso = DateTimeFormat.ISO.TIME)
public LocalDateTime getStartDate() {
    return startDate;
}

Mais les annotations ci-dessus ne fonctionnent pas, la date continue à être formatée comme ci-dessus. Suggestions bienvenues!

84
Erik Pragt

update: Spring Boot 2.x ne nécessite plus cette configuration. J'ai écrit une réponse plus à jour ici .


(C'est la façon de le faire avant Spring Boot 2.x, cela pourrait être utile pour les personnes travaillant sur une ancienne version de Spring Boot))

J'ai enfin trouvé ici comment le faire. Pour résoudre ce problème, j'avais besoin d'une autre dépendance:

compile("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.4.0")

En incluant cette dépendance, Spring enregistre automatiquement un convertisseur, comme décrit ici . Après cela, vous devez ajouter ce qui suit au fichier application.properties:

spring.jackson.serialization.write_dates_as_timestamps=false

Cela garantira l'utilisation d'un convertisseur correct et que les dates seront imprimées au format 2016-03-16T13:56:39.492.

Les annotations ne sont nécessaires que si vous souhaitez modifier le format de la date.

108
Erik Pragt

J'ai ajouté le com.fasterxml.jackson.datatype: jackson-datatype-jsr310: 2.6.1 dépendance et j'ai commencé à obtenir la date au format suivant:

"birthDate": [
    2016,
    1,
    25,
    21,
    34,
    55
  ]

ce qui n'est pas ce que je voulais mais je me rapprochais. J'ai ensuite ajouté ce qui suit

spring.jackson.serialization.write_dates_as_timestamps=false

au fichier application.properties qui m’a donné le format correct dont j’avais besoin.

"birthDate": "2016-01-25T21:34:55"
77
patelb

Ici, il est dans Maven, avec la propriété afin que vous puissiez survivre entre les mises à niveau de démarrage du printemps

<dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        <artifactId>jackson-datatype-jsr310</artifactId>
        <version>${jackson.version}</version>
</dependency>
26
Matt Broekhuis

1) la dépendance

 compile group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310', version: '2.8.8' 

2) Annotation au format date-heure.

public class RestObject {

    private LocalDateTime timestamp;

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    public LocalDateTime getTimestamp() {
        return timestamp;
    }
}

3) Config de printemps.

@Configuration
public class JacksonConfig {

    @Bean
    @Primary
    public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
        System.out.println("Config is starting.");
        ObjectMapper objectMapper = builder.createXmlMapper(false).build();
        objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        return objectMapper;
    }
}
10
Yan Khonski

J'ai trouvé une autre solution que vous pouvez convertir au format de votre choix et appliquer à tous les types de données LocalDateTime. Il n'est pas nécessaire de spécifier @JsonFormat au-dessus de chaque type de données LocalDateTime. Ajoutez d'abord la dépendance: 

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

Ajoutez le haricot suivant: 

@Configuration
public class Java8DateTimeConfiguration {
    /**
     * Customizing
     * http://docs.spring.io/spring-boot/docs/current/reference/html/howto-spring-mvc.html
     *
     * Defining a @Bean of type Jackson2ObjectMapperBuilder will allow you to customize both default ObjectMapper and XmlMapper (used in MappingJackson2HttpMessageConverter and MappingJackson2XmlHttpMessageConverter respectively).
     */
    @Bean
    public Module jsonMapperJava8DateTimeModule() {
        val bean = new SimpleModule();

        bean.addDeserializer (ZonedDateTime.class, new JsonDeserializer<ZonedDateTime>() {
            @Override
            public ZonedDateTime deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
                return ZonedDateTime.parse(jsonParser.getValueAsString(), DateTimeFormatter.ISO_ZONED_DATE_TIME);
            }
        });

        bean.addDeserializer(LocalDateTime.class, new JsonDeserializer<LocalDateTime>() {
            @Override
            public LocalDateTime deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
                return LocalDateTime.parse(jsonParser.getValueAsString(), DateTimeFormatter.ISO_LOCAL_DATE_TIME);
            }
        });

        bean.addSerializer(ZonedDateTime.class, new JsonSerializer<ZonedDateTime>() {
            @Override
            public void serialize(
                    ZonedDateTime zonedDateTime, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
                    throws IOException {
                jsonGenerator.writeString(DateTimeFormatter.ISO_ZONED_DATE_TIME.format(zonedDateTime));
            }
        });

        bean.addSerializer(LocalDateTime.class, new JsonSerializer<LocalDateTime>() {
            @Override
            public void serialize(
                    LocalDateTime localDateTime, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
                    throws IOException {
                jsonGenerator.writeString(DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(localDateTime));
            }
        });

        return bean;
    }
}

dans votre fichier de configuration, ajoutez ce qui suit: 

@Import(Java8DateTimeConfiguration.class)

Cela sérialisera et désérialise toutes les propriétés LocalDateTime et ZonedDateTime tant que vous utilisez objectMapper créé par spring.

Le format que vous avez obtenu pour ZoneDateTime est: "2017-12-27T08: 55: 17: 37 + 02: 00 [Asie/Jérusalem]" Pour LocalDateTime est: "2017-12-27T09: 05: 30.523"

6
Ida Amit

Cela fonctionne bien:

Ajoutez la dépendance:

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jdk8</artifactId>
</dependency>

Ajouter l'annotation:

@JsonFormat(pattern="yyyy-MM-dd")

Maintenant, vous devez obtenir le bon format.

Pour utiliser le mappeur d'objets, vous devez enregistrer JavaTime.

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
2
Manuel Velasquez

Écrire cette réponse comme rappel pour moi aussi.

J'ai combiné plusieurs réponses ici et à la fin, le mien a travaillé avec quelque chose comme ceci .. (J'utilise SpringBoot 1.5.7 et Lombok 1.16.16)

@Data
public Class someClass {

   @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
   @JsonSerialize(using = LocalDateTimeSerializer.class)
   @JsonDeserialize(using = LocalDateTimeDeserializer.class)
   private LocalDateTime someDate;

}
2
JWiryo

Comme déjà mentionné, spring-boot ira chercher tout ce dont vous avez besoin (à la fois pour Web et pour Webflux Starter).

Mais ce qui est encore mieux - vous n'avez pas besoin d'enregistrer vous-même les modules . Regardez ici . Puisque @SpringBootApplication utilise @EnableAutoConfiguration sous le capot, cela signifie que JacksonAutoConfiguration sera automatiquement ajouté au contexte . Maintenant, si vous regardez à l'intérieur de JacksonAutoConfiguration, vous verrez:

    private void configureModules(Jackson2ObjectMapperBuilder builder) {
        Collection<Module> moduleBeans = getBeans(this.applicationContext,
                Module.class);
        builder.modulesToInstall(moduleBeans.toArray(new Module[0]));
    }

Ce type sera appelé en cours d'initialisation et récupérera tous les modules qu'il peut trouver dans le classpath . (J'utilise Spring Boot 2.1)

0
yuranos87

@JsonDeserialize(using= LocalDateDeserializer.class) ne fonctionne pas pour moi avec la dépendance ci-dessous.

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

J'ai utilisé le convertisseur de code ci-dessous pour désérialiser la date en un Java.sql.Date.

import javax.persistence.AttributeConverter;
import javax.persistence.Converter;


@SuppressWarnings("UnusedDeclaration")
@Converter(autoApply = true)
public class LocalDateConverter implements AttributeConverter<Java.time.LocalDate, Java.sql.Date> {


    @Override
    public Java.sql.Date convertToDatabaseColumn(Java.time.LocalDate attribute) {

        return attribute == null ? null : Java.sql.Date.valueOf(attribute);
    }

    @Override
    public Java.time.LocalDate convertToEntityAttribute(Java.sql.Date dbData) {

        return dbData == null ? null : dbData.toLocalDate();
    }
}
0
Ram

J'utilise Springboot 2.0.6 et, pour une raison quelconque, les modifications apportées à l'application yml n'ont pas fonctionné. Et aussi j'avais plus d'exigences.

J'ai essayé de créer ObjectMapper et de le marquer comme Primary, mais Spring Boot s'est plaint du fait que j'ai déjà jacksonObjectMapper comme marqué Primary!

Donc c'est ce que j'ai fait. J'ai apporté des modifications au mappeur interne.

Mon sérialiseur et mon désérialiseur sont spéciaux - ils traitent avec 'jj/mm/aaaa'; et lors de la désérialisation - il fait de son mieux pour utiliser 3-4 formats populaires afin de m'assurer que je dispose de LocalDate.

@Autowired
    ObjectMapper mapper;

    @PostConstruct
    public ObjectMapper configureMapper() {
        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        mapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);

        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        mapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true);

        mapper.configure(MapperFeature.ALLOW_COERCION_OF_SCALARS, true);
        mapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true);

        SimpleModule module = new SimpleModule();
        module.addDeserializer(LocalDate.class, new LocalDateDeserializer());
        module.addSerializer(LocalDate.class, new LocalDateSerializer());
        mapper.registerModule(module);

        return mapper;
    }
0
Kalpesh Soni

simplement utiliser:

@JsonFormat(pattern="10/04/2019")

ou vous pouvez utiliser un motif comme vous le souhaitez, par exemple: ('-' in place of '/')

0
Ashish Dwivedi