Як серіалізувати Joda DateTime за допомогою процесора Jackson JSON?


118

Як змусити Джексона серіалізувати мій об'єкт Joda DateTime за простою схемою (наприклад, "dd-MM-yyyy")?

Я спробував:

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

Я також спробував:

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

Дякую!


І те, і інше насправді також має працювати (@JsonSerialize має означати, що поле має бути серіалізовано; а формат дати також ідеально застосовуватиметься до Joda), тому ви, можливо, захочете подати помилку Jira на адресу jira.codehaus.org/browse/JACKSON .
StaxMan

Я усвідомлюю, що це питання час від часу повертається, але для подальшого ознайомлення об'єктMapper.getSerializationConfig (). SetDateFormat (df) тепер застарілий. Тепер пропонується objectMapper.setDateFormat (df).
Патрік

Відповіді:


146

Це стало дуже просто завдяки Jackson 2.0 та модулю Joda.

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

Залежна залежність:

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

Код та документація: https://github.com/FasterXML/jackson-datatype-joda

Бінарні файли: http://repo1.maven.org/maven2/com/fasterxml/jackson/datatype/jackson-datatype-joda/


13
Чи можете ви розширити цю проблему? Куди йде цей код і як використовується екземпляр ObjectMapper?
Пол

Вам слід задати конкретні запитання щодо використання яблучного апарата Джексона та Мейвена. Куди йде код, залежить від того, використовуєте які-небудь рамки / як ви завантажуєте додаток.
Кімбл

4
коли я додаю, що я отримую помилку компіляції "несумісні типи: JodaModule не може бути перетворений на модуль" - метод очікує, що org.codehaus.jackson.map.Module, але JodaModule не має цього в своїй спадкоємності, так як це могло працювати?
Мартін Чарльзворт

4
Обіцяючий, але наразі майже марний, оскільки ми не можемо вказати формат дати для розбору :(
Vincent Mimoun-Prat

10
Вам потрібно відключити серіалізацію як часові позначки objectMapper.disable (SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
MarekM

74

В об’єкті, який ви картаєте:

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

У 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
Як зареєструвати CustomDateSerializer навесні mvc 3?
digz6666

1
Я не знаю про Spring MVC3, але ви можете додати спеціальний серіалізатор до об’єкта картографу Джексона. Дивіться цей запис у Jackson. Вам потрібно створити простий модуль для цього SimpleModule isoDateTimeModule = новий SimpleModule ("ISODateTimeModule", нова версія (1, 0, 0, null)); isoDateTimeModule.addSerializer (новий JsonISODateTimeFormatSerializer ()); mapper.registerModule (isoDateTimeModule);
Гійом Белроуз

1
@ digz6666 дивіться мою відповідь на весну MVC 3: stackoverflow.com/questions/7854030/…
Арам Кочарян

Примітка - обов'язково використовуйте вищевказані класи, org.codehaus.jacksonа не com.fasterxml.jackson.core. Використання другого пакету для мене не вийшло. Насправді мій додаток Джерсі навіть не поважав @JsonSerializedанотацію.
Кевін Мередіт

Відповідь спрацювала для мене. Але це вимагатиме цього анотації на всіх полях. Чи існує якась глобальна конфігурація для цього, яка працює з Джексоном?
Тахер

26

Як сказав @Kimble, для Jackson 2 використовувати форматування за замовчуванням дуже просто; просто зареєструйтесь JodaModuleна своєму ObjectMapper.

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

Для користувацької серіалізації / де-серіалізації DateTimeвам потрібно реалізувати власний StdScalarSerializerта StdScalarDeserializer; це доволі перекручено, але все одно.

Наприклад, ось DateTimeсеріалізатор, який використовує ISODateFormatчасовий пояс 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);
    }
}

І відповідний де-серіалізатор:

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

Потім зв’яжіть їх разом з модулем:

public class DateTimeModule extends SimpleModule {

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

Потім зареєструйте модуль у вашому ObjectMapper:

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

десярильований об'єкт DatatIme знаходиться в часовому поясі UTC або в іншому випадку веб-переглядачі, будь ласка, допоможіть мені
user3354457

Чи реєструє це картограф (і модулі) у всьому світі?
raffian

16

Просте рішення

Я зіткнувся з подібною проблемою, і моє рішення набагато чіткіше, ніж вище.

Я просто використав шаблон в @JsonFormat анотації

В основному в моєму класі є DateTimeполе, тож я поміщаю примітку навколо геттера:

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

Я серіалізую клас с 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);
    }

Ми використовуємо Джексона 2.5.4


15

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

Хоча ви можете помістити примітку до кожного поля дати, краще зробити глобальну конфігурацію для вашого картографічного об'єкта. Якщо ви використовуєте jackson, ви можете налаштувати свою весну так:

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

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

Для 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)"));
    }
}

Звичайно, SimpleDateFormat може використовувати будь-який потрібний вам формат.


4
setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssz"));зробив трюк для мене, thx
Konsumierer

8

Тим часом Джексон автоматично реєструє модуль Joda, коли JodaModule перебуває у класі. Я щойно додав Джевена Джексона-тип-joda до Maven, і він працював миттєво.

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

Вихід JSON:

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

6

Для тих, хто має Spring Boot, ви повинні додати модуль до свого контексту, і він буде доданий до вашої конфігурації.

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

І якщо ви хочете використовувати новий часовий модуль java8 jsr-310.

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

3

Здається, що для Джексона 1.9.12 не існує такої можливості за замовчуванням через:

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

Цей клас серіалізує дані за допомогою методу toString () Joda DateTime.

Підхід, запропонований Расті Кунцем, ідеально підходить для моєї справи.


Ви все ще можете зареєструвати спеціальний серіалізатор та десеріалізатор, і вони матимуть перевагу перед типовою реалізацією.
StaxMan

2

Я використовую Java 8, і це працювало для мене.

Додайте залежність від pom.xml

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

і додайте JodaModule у свій ObjectMapper

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JodaModule());
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.