JSON Java 8 format LocalDateTime di Spring Boot

112

Saya mengalami masalah kecil dengan memformat Java 8 LocalDateTime di Aplikasi Spring Boot saya. Dengan tanggal 'normal' saya tidak memiliki masalah, tetapi bidang LocalDateTime diubah menjadi berikut ini:

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

Sementara saya ingin mengubahnya menjadi seperti:

"startDate": "2015-01-01"

Kode saya terlihat seperti ini:

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

Tetapi salah satu anotasi di atas tidak berfungsi, tanggal terus berformat seperti di atas. Saran diterima!

Erik Pragt
sumber

Jawaban:

135

memperbarui : Spring Boot 2.x tidak memerlukan konfigurasi ini lagi. Saya telah menulis jawaban yang lebih mutakhir di sini .


(Ini adalah cara melakukannya sebelum Spring Boot 2.x, ini mungkin berguna bagi orang yang mengerjakan Spring Boot versi lama)

Saya akhirnya menemukan di sini bagaimana melakukannya. Untuk memperbaikinya, saya membutuhkan ketergantungan lain:

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

Dengan menyertakan ketergantungan ini, Spring akan secara otomatis mendaftarkan konverter untuknya, seperti yang dijelaskan di sini . Setelah itu, Anda perlu menambahkan berikut ini ke application.properties:

spring.jackson.serialization.write_dates_as_timestamps=false

Ini akan memastikan bahwa konverter yang benar digunakan, dan tanggal akan dicetak dalam format 2016-03-16T13:56:39.492

Anotasi hanya diperlukan jika Anda ingin mengubah format tanggal.

Erik Pragt
sumber
24
Mungkin layak termasuk penjelasan berikut - @JsonSerialize(using = LocalDateTimeSerializer.class)...
Nick Grealy
3
Mungkin lebih baik hanya menggunakan application.propertiesentri, seperti yang disarankan oleh jawaban @patelb.
Memberound
Tidak bekerja. Tetapi jawaban patelib berhasil di luar kotak!
Mykhaylo Kopytonenko
Sebagai pendahuluan, kami membutuhkan @JsonSerializeanotasi yang disebutkan Nick agar berfungsi.
pennstatephil
92

Saya menambahkan com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.6.1ketergantungan dan mulai mendapatkan tanggal dalam format berikut:

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

yang bukan yang saya inginkan tetapi saya semakin dekat. Saya kemudian menambahkan yang berikut ini

spring.jackson.serialization.write_dates_as_timestamps=false

ke file application.properties yang memberi saya format yang benar yang saya butuhkan.

"birthDate": "2016-01-25T21:34:55"
patelb
sumber
2
Berhasil di luar kotak saat menyertakan jackson-datatype-jsr310ketergantungan. Ini harus menjadi jawaban yang diterima.
membersound
6
Sebagai FYI, bagian application.properties dapat dilakukan melalui konfigurasi Java jika Anda mengkonfigurasi ObjectMapper dengan:mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
justin
31

Ini dia di maven, dengan properti sehingga Anda dapat bertahan di antara peningkatan sepatu bot musim semi

<dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        <artifactId>jackson-datatype-jsr310</artifactId>
        <version>${jackson.version}</version>
</dependency>
Matt Broekhuis
sumber
1
Gunakan solusi ini dengan komentar @NickGrealy: Mungkin layak termasuk anotasi berikut -@JsonSerialize(using = LocalDateTimeSerializer.class)
HairOfTheDog
19

1) Ketergantungan

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

2) Anotasi dengan format tanggal-waktu.

public class RestObject {

    private LocalDateTime timestamp;

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

3) Konfigurasi Musim Semi.

@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;
    }
}
Yan Khonski
sumber
2
Terima kasih banyak. @JsonFormat adalah salah satu yang memecahkannya untuk saya. Tak satu pun dari solusi di atas berhasil untuk saya karena suatu alasan
pemrogram
7

Saya menemukan solusi lain yang dapat Anda ubah ke format apa pun yang Anda inginkan dan terapkan ke semua tipe data LocalDateTime dan Anda tidak perlu menentukan @JsonFormat di atas setiap tipe data LocalDateTime. pertama tambahkan ketergantungan:

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

Tambahkan kacang berikut:

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

di file konfigurasi Anda tambahkan yang berikut ini:

@Import(Java8DateTimeConfiguration.class)

Ini akan membuat serial dan de-serialisasi semua properti LocalDateTime dan ZonedDateTime selama Anda menggunakan objectMapper yang dibuat oleh spring.

Format yang Anda dapatkan untuk ZonedDateTime adalah: "2017-12-27T08: 55: 17.317 + 02: 00 [Asia / Yerusalem]" untuk LocalDateTime adalah: "2017-12-27T09: 05: 30.523"

Ida Amit
sumber
Mungkin Anda perlu mengganti val bean ke SimpleModule bean = new SimpleModule ();
Abhishek Galoda
Apakah ini untuk Java 9?
Daniel Dai
@DanielDai Ini ada di Jawa 8.
Ida Amit
@Abhi, SimpleModulemeluas Module. Moduleadalah abstrak. val bean = new SimpleModule(); bekerja dengan sempurna.
Ida Amit
untuk SpringBoot versi 1.5.3. RELEASE tidak perlu menambahkan dependensi jackson-datatype-jsr310.
Bulan13
7

Menulis jawaban ini sebagai pengingat untuk saya juga.

Saya menggabungkan beberapa jawaban di sini dan pada akhirnya jawaban saya bekerja dengan sesuatu seperti ini. (Saya menggunakan SpringBoot 1.5.7 dan 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;

}
JWiryo
sumber
1
Anda mungkin ingin menambahkan impor untuk DateTimeFormatdan lainnya.
prayagupd
4

Ini bekerja dengan baik:

Tambahkan ketergantungan:

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

Tambahkan anotasi:

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

Sekarang, Anda harus mendapatkan format yang benar.

Untuk menggunakan pemeta objek, Anda perlu mendaftarkan JavaTime

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
Manuel Antonio
sumber
1

Seperti yang telah disebutkan, spring-boot akan mengambil semua yang Anda butuhkan (untuk web dan webflux starter).

Tetapi yang lebih baik lagi - Anda tidak perlu mendaftarkan modul apa pun sendiri. Coba lihat di sini . Karena @SpringBootApplicationdigunakan di @EnableAutoConfigurationbawah tenda, artinya JacksonAutoConfigurationakan ditambahkan ke konteks secara otomatis. Sekarang, jika Anda melihat ke dalam JacksonAutoConfiguration, Anda akan melihat:

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

Orang ini akan dipanggil dalam proses inisialisasi dan akan mengambil semua modul yang dapat ditemukannya di classpath. (Saya menggunakan Spring Boot 2.1)

yuranos
sumber
1

Saya menggunakan Springboot 2.0.6 dan karena alasan tertentu, perubahan aplikasi yml tidak berfungsi. Dan juga saya memiliki lebih banyak persyaratan.

Saya mencoba membuat ObjectMapper dan menandainya sebagai Primer tetapi boot musim semi mengeluh bahwa saya sudah memiliki jacksonObjectMapper sebagai ditandai Utama !!

Jadi inilah yang saya lakukan. Saya membuat perubahan pada mapper internal.

Serializer dan Deserializer saya spesial - berhubungan dengan 'dd / MM / YYYY'; dan saat de-serializing - mencoba yang terbaik untuk menggunakan 3-4 format populer untuk memastikan saya memiliki 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;
}
Kalpesh Soni
sumber
0

@JsonDeserialize(using= LocalDateDeserializer.class) tidak bekerja untuk saya dengan ketergantungan di bawah ini.

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

Saya telah menggunakan konverter kode di bawah ini untuk deserialize tanggal menjadi 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();
    }
}
Ram
sumber
0

cukup gunakan:

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

atau Anda dapat menggunakan pola sesuka Anda misalnya: ('-' in place of '/')

Ashish Dwivedi
sumber
Jawaban ini telah dibagikan sebelumnya, tetapi kemudian dengan sintaks yang benar.
Erik Pragt
0

Saya menggunakan Spring Boot 2.1.8. Saya telah mengimpor

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

yang mencakup jackson-datatype-jsr310 .

Kemudian, saya harus menambahkan anotasi ini

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

dan berhasil. JSON terlihat seperti ini:

"date": "2020-03-09 17:55:00"
Tomas Lukac
sumber
Petunjuk: penyertaan spring-boot-starter-jsonhanya diperlukan jika spring-boot-starter-webhilang.
judomu