Формат JSON Java 8 LocalDateTime у весняному завантаженні


112

У мене є невелика проблема з форматуванням Java 8 LocalDateTime у моєму додатку Spring Boot. З "нормальними" датами у мене немає проблем, але поля LocalDateTime перетворюються на наступні:

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

Хоча я хотів би перетворити його на щось на кшталт:

"startDate": "2015-01-01"

Мій код виглядає приблизно так:

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

Але будь-яке з вищезазначених приміток не працює, дата продовжує формуватися як вище. Пропозиції Ласкаво просимо!

Відповіді:


135

оновлення : Spring Boot 2.x більше не потребує цієї конфігурації. Тут я написав більш сучасну відповідь .


(Це спосіб зробити це до Spring Boot 2.x, це може бути корисно людям, які працюють на більш старій версії Spring Boot)

Я нарешті знайшов тут, як це зробити. Щоб виправити це, мені потрібна була ще одна залежність:

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

Включивши цю залежність, Spring автоматично зареєструє для неї перетворювач, як описано тут . Після цього вам потрібно додати наступне до application.properties:

spring.jackson.serialization.write_dates_as_timestamps=false

Це забезпечить правильний перетворювач, а дати надрукуються у форматі 2016-03-16T13:56:39.492

Анотації потрібні лише в тому випадку, якщо ви хочете змінити формат дати.


24
Напевно, варто включити таку анотацію - @JsonSerialize(using = LocalDateTimeSerializer.class)...
Нік Грілі

3
Напевно, краще просто використати application.propertiesзапис, як підказує відповідь @patelb.
члени звуку

Не працює. Але відповідь patelib просто працює з вікна!
Михайло Копитоненко

Як голова вгору, нашим потрібна @JsonSerializeанотація, яку згадав Нік, щоб працювати.
pennstatephil

92

Я додав com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.6.1залежність і почав отримувати дату в такому форматі:

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

що не те, чого я хотів, але я наближався. Потім я додав наступне

spring.jackson.serialization.write_dates_as_timestamps=false

до файла application.properties, який дав мені потрібний мені потрібний формат.

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

2
Опрацьовано з коробки, включаючи jackson-datatype-jsr310залежність. Це має бути прийнятою відповіддю.
члени звуку

6
Як FYI, частину application.properties можна виконати через конфігурацію Java, якщо ви налаштовуєте ObjectMapper за допомогою:mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
justin

31

Тут він знаходиться в Maven, з властивістю, щоб ви могли вижити між весняними оновленнями завантаження

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

1
Скористайтеся цим рішенням з коментарем @NickGrealy: Мабуть, варто включити таку примітку -@JsonSerialize(using = LocalDateTimeSerializer.class)
HairOfTheDog

19

1) залежність

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

2) Анотація з форматом дати та часу.

public class RestObject {

    private LocalDateTime timestamp;

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

3) Налаштування весни.

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

2
Дуже дякую. @JsonFormat - це той, хто вирішив це для мене. Жоден з наведених вище рішень не працював для мене з якоїсь - то причини
theprogrammer

7

Я знайшов інше рішення, яке ви можете перетворити на будь-який формат, який ви хочете, і застосувати до всіх типів даних LocalDateTime, і вам не потрібно вказувати @JsonFormat вище кожного типу даних LocalDateTime. спочатку додайте залежність:

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

Додайте наступну квасолю:

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

у свій конфігураційний файл додайте наступне:

@Import(Java8DateTimeConfiguration.class)

Це дозволить серіалізувати та де-серіалізувати всі властивості LocalDateTime та ZonedDateTime до тих пір, поки ви використовуєте objectMapper, створений весною.

Формат, який ви отримали для ZonedDateTime, такий: "2017-12-27T08: 55: 17.317 + 02: 00 [Азія / Єрусалим]" для LocalDateTime такий: "2017-12-27T09: 05: 30.523"


Probabaly вам потрібно замінити val bean на SimpleModule bean = новий SimpleModule ();
Абхішек Галода

Це для Java 9?
Даніель Дай

@DanielDai Це на Java 8.
Іда Аміт

@Abhi, SimpleModuleрозширюється Module. Moduleє абстрактним. val bean = new SimpleModule(); працює ідеально.
Айда Аміт

для SpringBoot версії 1.5.3.RELEASE не потрібно було додавати залежність jackson-datatype-jsr310.
Місяць13,

7

Написання цієї відповіді як нагадування і для мене.

Я поєднав тут кілька відповідей, і врешті-решт мій працював із чимось подібним. (Я використовую SpringBoot 1.5.7 та 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;

}

1
ви можете додати імпорт DateTimeFormatта інші.
prayagupd

4

Це добре працює:

Додайте залежність:

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

Додайте примітку:

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

Тепер ви повинні отримати правильний формат.

Щоб використовувати картографічний об'єкт, потрібно зареєструвати JavaTime

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

1

Як вже було сказано, весняний завантажувач отримає все, що вам потрібно (як для веб-так і для веб-потоку для початківців).

Але що ще краще - вам не потрібно самостійно реєструвати жодні модулі. Погляньте тут . Оскільки @SpringBootApplicationвикористання @EnableAutoConfigurationпід кришкою, це означає, що JacksonAutoConfigurationбуде додано до контексту автоматично. Тепер, якщо ви заглянете всередину JacksonAutoConfiguration, ви побачите:

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

Ця команда буде викликана в процесі ініціалізації та отримає всі модулі, які вона може знайти на classpath. (Я використовую Spring Boot 2.1)


1

Я використовую Springboot 2.0.6, і чомусь зміни у програмі yml не працювали. А також у мене було більше вимог.

Я спробував створити ObjectMapper і позначив його як первинний, але весняний завантажувач поскаржився, що у мене вже є jacksonObjectMapper як позначений як основний !!

Так це я і зробив. Я вніс зміни у внутрішній картограф.

Мій серіалізатор та десеріалізатор є спеціальними - вони мають справу з "дд / ММ / РРРР"; і де-серіалізуючи - намагається використовувати 3-4 популярні формати, щоб переконатися, що у мене є 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

@JsonDeserialize(using= LocalDateDeserializer.class) не працює для мене із наведеною нижче залежністю.

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

Я використовував наведений нижче конвертер коду, щоб десеріалізувати дату в 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

просто використовуйте:

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

або ви можете використовувати шаблон, як вам подобається, наприклад: ('-' in place of '/')


Ця відповідь ділилася раніше, але потім із правильним синтаксисом.
Ерік Прагт

0

Я використовую Spring Boot 2.1.8. Я імпортував

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-json</artifactId>
</dependency>

який включає в себе jackson-datatype-jsr310 .

Потім мені довелося додати ці анотації

@JsonSerialize(using = LocalDateTimeSerializer.class)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonProperty("date")
LocalDateTime getDate();

і це працює. JSON виглядає так:

"date": "2020-03-09 17:55:00"

Підказка: в тому числі spring-boot-starter-jsonпотрібно лише у разі spring-boot-starter-webвідсутності.
judomu
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.