Làm thế nào để tuần tự hóa Joda DateTime với bộ xử lý Jackson JSON?


118

Làm cách nào để yêu cầu Jackson tuần tự hóa đối tượng Joda DateTime của tôi theo một mẫu đơn giản (như "dd-MM-yyyy")?

Tôi đã thử:

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

Tôi cũng đã thử:

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

Cảm ơn!


Cả hai điều trên thực sự cũng hoạt động (@JsonSerialize nên ngụ ý rằng trường đó phải được tuần tự hóa; và định dạng ngày cũng nên áp dụng lý tưởng cho Joda), vì vậy bạn có thể muốn gửi lỗi Jira tại jira.codehaus.org/browse/JACKSON .
StaxMan

Tôi nhận ra rằng câu hỏi này đã xuất hiện từ lâu, nhưng để tham khảo trong tương lai, objectMapper.getSerializationConfig (). SetDateFormat (df) hiện không được dùng nữa. objectMapper.setDateFormat (df) hiện được đề xuất.
Patrick

Câu trả lời:


146

Điều này đã trở nên rất dễ dàng với Jackson 2.0 và mô-đun Joda.

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

Sự phụ thuộc của Maven:

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

Mã và tài liệu: https://github.com/FasterXML/jackson-datatype-joda

Hội thảo: http://repo1.maven.org/maven2/com/fasterxml/jackson/datatype/jackson-datatype-joda/


13
Bạn có thể mở rộng về điều này được không? Đoạn mã này đi đến đâu và đối tượng ObjectMapper được sử dụng như thế nào?
Paul

Bạn nên đặt những câu hỏi cụ thể liên quan đến việc sử dụng api của Jackson và Maven. Đoạn mã đi đến đâu tùy thuộc vào việc bạn sử dụng bất kỳ khuôn khổ nào / cách bạn khởi động ứng dụng của mình.
Kimble, 29/09/13

4
khi tôi thêm rằng tôi nhận được lỗi biên dịch "các loại không tương thích: JodaModule không thể được chuyển đổi thành Mô-đun" - phương thức mong đợi một org.codehaus.jackson.map.Module nhưng JodaModule không có điều này trong hệ thống của nó, vậy làm thế nào điều này có thể hoạt động?
Martin Charlesworth

4
Hứa hẹn nhưng hiện tại gần như vô dụng vì chúng tôi không thể xác định định dạng ngày tháng để phân tích cú pháp :(
Vincent Mimoun-Prat

10
Bạn cần tắt tuần tự hóa dưới dạng dấu thời gian objectMapper.disable (SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
MarekM

74

Trong đối tượng bạn đang ánh xạ:

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

Trong 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));
    }
}

4
Làm thế nào để đăng ký CustomDateSerializer trong Spring mvc 3?
digz6666,

1
Tôi không biết về Spring MVC3, nhưng bạn có thể thêm bộ tuần tự tùy chỉnh vào đối tượng ánh xạ Jackson. Xem mục này trong Jackson Bạn cần tạo một mô-đun đơn giản cho SimpleModule đó isoDateTimeModule = new SimpleModule ("ISODateTimeModule", new Version (1, 0, 0, null)); isoDateTimeModule.addSerializer (JsonISODateTimeFormatSerializer mới ()); mapper.registerModule (isoDateTimeModule);
Guillaume Belrose 29/02/12

1
@ digz6666 xem câu trả lời của tôi ở đây cho Spring MVC 3: stackoverflow.com/questions/7854030/...
Aram Kocharyan

Lưu ý - đảm bảo sử dụng các lớp trên từ org.codehaus.jacksonthay vì com.fasterxml.jackson.core. Sử dụng gói thứ hai không hiệu quả với tôi. Trên thực tế, ứng dụng Jersey của tôi thậm chí còn không tôn trọng @JsonSerializedchú thích.
Kevin Meredith

Câu trả lời đã làm việc cho tôi. Nhưng nó sẽ yêu cầu chú thích này trên tất cả các trường. Có một số cấu hình toàn cầu cho cái này hoạt động với Jackson không?
Taher

26

Như @Kimble đã nói, với Jackson 2, việc sử dụng định dạng mặc định rất dễ dàng; chỉ cần đăng ký JodaModuletrên của bạn ObjectMapper.

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

Đối với tuần tự hóa / hủy tuần tự hóa tùy chỉnh DateTime, bạn cần triển khai StdScalarSerializerStdScalarDeserializer; nó khá phức tạp, nhưng dù sao.

Ví dụ: đây là một bộ DateTimetuần tự sử dụng ISODateFormatmúi giờ 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);
    }
}

Và bộ khử nối tiếp tương ứng:

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());
        }
    }

Sau đó, buộc chúng lại với nhau bằng một mô-đun:

public class DateTimeModule extends SimpleModule {

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

Sau đó đăng ký mô-đun trên ObjectMapper:

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

đối tượng DatatIme được mô tả nằm trong múi giờ UTC hoặc múi giờ khác của trình duyệt, vui lòng giúp tôi
user3354457

Điều này có đăng ký trình ánh xạ (và các mô-đun) trên toàn cầu không?
raffian

16

Giải pháp dễ dàng

Tôi đã gặp vấn đề tương tự và giải pháp của tôi rõ ràng hơn nhiều so với ở trên.

Tôi chỉ đơn giản là sử dụng mẫu trong @JsonFormat chú thích

Về cơ bản lớp của tôi có một DateTimetrường, vì vậy tôi đặt một chú thích xung quanh getter:

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

Tôi nối tiếp lớp học với 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);
    }

Chúng tôi sử dụng Jackson 2.5.4


15

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

Mặc dù bạn có thể đặt chú thích cho từng trường ngày tháng, nhưng tốt hơn là bạn nên thực hiện cấu hình toàn cục cho trình ánh xạ đối tượng của mình. Nếu bạn sử dụng jackson, bạn có thể cấu hình lò xo của mình như sau:

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

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

Đối với 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)"));
    }
}

Tất nhiên, SimpleDateFormat có thể sử dụng bất kỳ định dạng nào bạn cần.


4
setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssz"));đã làm các trick cho tôi, thx
Konsumierer

8

Trong khi đó Jackson đăng ký mô-đun Joda tự động khi JodaModule ở trong classpath. Tôi vừa thêm jackson-datatype-joda vào Maven và nó hoạt động ngay lập tức.

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

Đầu ra JSON:

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

6

Đối với những người có Spring Boot, bạn phải thêm mô-đun vào ngữ cảnh của mình và nó sẽ được thêm vào cấu hình của bạn như thế này.

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

Và nếu bạn muốn sử dụng mô-đun thời gian java8 mới jsr-310.

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

3

Có vẻ như đối với Jackson 1.9.12 thì không có khả năng này theo mặc định, vì:

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

Lớp này tuần tự hóa dữ liệu bằng phương thức toString () của Joda DateTime.

Phương pháp tiếp cận do Rusty Kuntz đề xuất phù hợp với trường hợp của tôi.


Bạn vẫn có thể đăng ký bộ nối tiếp và bộ giải mã tùy chỉnh, và những thứ đó sẽ được ưu tiên hơn việc triển khai mặc định.
StaxMan

2

Tôi đang sử dụng Java 8 và điều này phù hợp với tôi.

Thêm phần phụ thuộc vào pom.xml

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

và thêm JodaModule vào ObjectMapper

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JodaModule());
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.