Bagaimana cara membuat serial Joda DateTime dengan prosesor Jackson JSON?

118

Bagaimana cara membuat Jackson membuat serialisasi objek Joda DateTime saya menurut pola sederhana (seperti "dd-MM-yyyy")?

Saya sudah mencoba:

@JsonSerialize(using=DateTimeSerializer.class)
private final DateTime date;

Saya juga mencoba:

ObjectMapper mapper = new ObjectMapper()
    .getSerializationConfig()
    .setDateFormat(df);

Terima kasih!

Haywood Jablomey
sumber
Kedua hal di atas seharusnya juga berfungsi (@JsonSerialize seharusnya menyiratkan bahwa bidang tersebut akan diserialisasi; dan format tanggal juga harus diterapkan secara ideal ke Joda), jadi Anda mungkin ingin melaporkan bug Jira di jira.codehaus.org/browse/JACKSON .
StaxMan
Saya menyadari pertanyaan ini dari beberapa waktu lalu, tetapi untuk referensi di masa mendatang, objectMapper.getSerializationConfig (). SetDateFormat (df) sekarang sudah usang. objectMapper.setDateFormat (df) sekarang disarankan.
Patrick

Jawaban:

146

Ini menjadi sangat mudah dengan Jackson 2.0 dan modul Joda.

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

Ketergantungan Maven:

<dependency>
  <groupId>com.fasterxml.jackson.datatype</groupId>
  <artifactId>jackson-datatype-joda</artifactId>
  <version>2.1.1</version>
</dependency>  

Kode dan dokumentasi: https://github.com/FasterXML/jackson-datatype-joda

Binari: http://repo1.maven.org/maven2/com/fasterxml/jackson/datatype/jackson-datatype-joda/

Kimble
sumber
13
Bisakah Anda memperluas ini? Ke mana perginya kode ini dan bagaimana contoh ObjectMapper digunakan?
Paul
Anda harus mengajukan pertanyaan khusus tentang penggunaan api Jackson dan Maven. Ke mana kodenya bergantung pada apakah Anda menggunakan framework apa pun / bagaimana Anda mem-bootstrap aplikasi Anda.
Kimble
4
ketika saya menambahkan bahwa saya mendapatkan kesalahan kompilasi "jenis yang tidak kompatibel: JodaModule tidak dapat dikonversi ke Modul" - metode ini mengharapkan org.codehaus.jackson.map.Module tetapi JodaModule tidak memiliki ini dalam pusaka jadi bagaimana ini bisa bekerja?
Martin Charlesworth
4
Menjanjikan tetapi saat ini hampir tidak berguna karena kami tidak dapat menentukan format tanggal yang akan diurai :(
Vincent Mimoun-Prat
10
Anda perlu menonaktifkan serialisasi sebagai cap waktu objectMapper.disable (SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
MarekM
74

Di objek yang Anda petakan:

@JsonSerialize(using = CustomDateSerializer.class)
public DateTime getDate() { ... }

Di CustomDateSerializer:

public class CustomDateSerializer extends JsonSerializer<DateTime> {

    private static DateTimeFormatter formatter = 
        DateTimeFormat.forPattern("dd-MM-yyyy");

    @Override
    public void serialize(DateTime value, JsonGenerator gen, 
                          SerializerProvider arg2)
        throws IOException, JsonProcessingException {

        gen.writeString(formatter.print(value));
    }
}
Rusty Kuntz
sumber
4
Bagaimana cara mendaftar CustomDateSerializer di musim semi mvc 3?
digz6666
1
Saya tidak tahu tentang Spring MVC3, tetapi Anda dapat menambahkan serializer khusus ke objek mapper Jackson. Lihat entri ini di Jackson Anda perlu membuat modul sederhana untuk SimpleModule itu isoDateTimeModule = new SimpleModule ("ISODateTimeModule", new Version (1, 0, 0, null)); isoDateTimeModule.addSerializer (baru JsonISODateTimeFormatSerializer ()); mapper.registerModule (isoDateTimeModule);
Guillaume Belrose
1
@ digz6666 lihat jawaban saya di sini untuk Spring MVC 3: stackoverflow.com/questions/7854030/…
Aram Kocharyan
Catatan - pastikan untuk menggunakan kelas di atas dari org.codehaus.jacksondaripada com.fasterxml.jackson.core. Menggunakan paket kedua tidak berhasil untuk saya. Faktanya, aplikasi Jersey saya bahkan tidak menghormati @JsonSerializedanotasi tersebut.
Kevin Meredith
Jawabannya berhasil untuk saya. Tapi itu akan membutuhkan anotasi ini di semua bidang. Apakah ada konfigurasi global untuk ini yang berfungsi dengan Jackson?
Taher
26

Seperti yang dikatakan @Kimble, dengan Jackson 2, menggunakan pemformatan default sangatlah mudah; cukup mendaftar JodaModuledi ObjectMapper.

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

Untuk serialisasi / de-serialisasi kustom DateTime, Anda perlu mengimplementasikan sendiri StdScalarSerializerdan StdScalarDeserializer; itu cukup berbelit-belit, tapi bagaimanapun juga.

Misalnya, inilah DateTimeserializer yang menggunakan ISODateFormatdengan zona waktu UTC:

public class DateTimeSerializer extends StdScalarSerializer<DateTime> {

    public DateTimeSerializer() {
        super(DateTime.class);
    }

    @Override
    public void serialize(DateTime dateTime,
                          JsonGenerator jsonGenerator,
                          SerializerProvider provider) throws IOException, JsonGenerationException {
        String dateTimeAsString = ISODateTimeFormat.withZoneUTC().print(dateTime);
        jsonGenerator.writeString(dateTimeAsString);
    }
}

Dan de-serializer yang sesuai:

public class DateTimeDesrializer extends StdScalarDeserializer<DateTime> {

    public DateTimeDesrializer() {
        super(DateTime.class);
    }

    @Override
    public DateTime deserialize(JsonParser jsonParser,
                                DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
        try {
            JsonToken currentToken = jsonParser.getCurrentToken();
            if (currentToken == JsonToken.VALUE_STRING) {
                String dateTimeAsString = jsonParser.getText().trim();
                return ISODateTimeFormat.withZoneUTC().parseDateTime(dateTimeAsString);
            }
        } finally {
            throw deserializationContext.mappingException(getValueClass());
        }
    }

Kemudian ikat ini menjadi satu dengan modul:

public class DateTimeModule extends SimpleModule {

    public DateTimeModule() {
        super();
        addSerializer(DateTime.class, new DateTimeSerializer());
        addDeserializer(DateTime.class, new DateTimeDeserializer());
    }
}

Kemudian daftarkan modul di ObjectMapper:

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new DateTimeModule());
oggmonster
sumber
objek DatatIme deserilazed berada di zona waktu UTC atau zona waktu browser lain tolong bantu saya
user3354457
Apakah ini mendaftarkan mapper (dan modul) secara global?
rafia
16

Solusi mudahnya

Saya mengalami masalah serupa dan solusi saya jauh lebih jelas daripada di atas.

Saya hanya menggunakan pola dalam @JsonFormat anotasi

Pada dasarnya kelas saya memiliki DateTimebidang, jadi saya memberi anotasi di sekitar getter:

@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
public DateTime getDate() {
    return date;
}

Saya membuat serial kelas dengan ObjectMapper

    ObjectMapper mapper = new ObjectMapper();
    mapper.registerModule(new JodaModule());
    mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
    ObjectWriter ow = mapper.writer();
    try {
        String logStr = ow.writeValueAsString(log);
        outLogger.info(logStr);
    } catch (IOException e) {
        logger.warn("JSON mapping exception", e);
    }

Kami menggunakan Jackson 2.5.4

Atais
sumber
15

https://stackoverflow.com/a/10835114/1113510

Meskipun Anda dapat meletakkan anotasi untuk setiap bidang tanggal, lebih baik melakukan konfigurasi global untuk pemeta objek Anda. Jika Anda menggunakan jackson, Anda dapat mengkonfigurasi pegas Anda sebagai berikut:

<bean id="jacksonObjectMapper" class="com.company.CustomObjectMapper" />

<bean id="jacksonSerializationConfig" class="org.codehaus.jackson.map.SerializationConfig"
    factory-bean="jacksonObjectMapper" factory-method="getSerializationConfig" >
</bean>

Untuk CustomObjectMapper:

public class CustomObjectMapper extends ObjectMapper {

    public CustomObjectMapper() {
        super();
        configure(Feature.WRITE_DATES_AS_TIMESTAMPS, false);
        setDateFormat(new SimpleDateFormat("EEE MMM dd yyyy HH:mm:ss 'GMT'ZZZ (z)"));
    }
}

Tentu saja, SimpleDateFormat dapat menggunakan format apa pun yang Anda butuhkan.

Moesio
sumber
4
setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssz"));melakukan trik untuk saya, thx
Konsumierer
8

Sementara itu Jackson mendaftarkan modul Joda secara otomatis saat JodaModule ada di classpath. Saya baru saja menambahkan jackson-datatype-joda ke Maven dan langsung bekerja.

<dependency>
  <groupId>com.fasterxml.jackson.datatype</groupId>
  <artifactId>jackson-datatype-joda</artifactId>
  <version>2.8.7</version>
</dependency>

Keluaran JSON:

{"created" : "2017-03-28T05:59:27.258Z"}
Stephan
sumber
6

Bagi mereka dengan Spring Boot Anda harus menambahkan modul ke konteks Anda dan itu akan ditambahkan ke konfigurasi Anda seperti ini.

@Bean
public Module jodaTimeModule() {
    return new JodaModule();
}

Dan jika Anda ingin menggunakan modul waktu java8 baru jsr-310.

@Bean
public Module jodaTimeModule() {
    return new JavaTimeModule();
}
jgeerts
sumber
3

Tampaknya untuk Jackson 1.9.12 tidak ada kemungkinan seperti itu secara default, karena:

public final static class DateTimeSerializer
    extends JodaSerializer<DateTime>
{
    public DateTimeSerializer() { super(DateTime.class); }

    @Override
    public void serialize(DateTime value, JsonGenerator jgen, SerializerProvider provider)
        throws IOException, JsonGenerationException
    {
        if (provider.isEnabled(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS)) {
            jgen.writeNumber(value.getMillis());
        } else {
            jgen.writeString(value.toString());
        }
    }

    @Override
    public JsonNode getSchema(SerializerProvider provider, java.lang.reflect.Type typeHint)
    {
        return createSchemaNode(provider.isEnabled(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS)
                ? "number" : "string", true);
    }
}

Kelas ini membuat serial data menggunakan metode toString () dari Joda DateTime.

Pendekatan yang diusulkan oleh Rusty Kuntz bekerja sempurna untuk kasus saya.

ydrozhdzhal
sumber
Anda masih dapat mendaftarkan serializer dan deserializer kustom, dan itu akan didahulukan daripada implementasi default.
StaxMan
2

Saya menggunakan Java 8 dan ini berhasil untuk saya.

Tambahkan ketergantungan pada pom.xml

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

dan tambahkan JodaModule di file ObjectMapper

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JodaModule());
Luciana Campello
sumber