Подтвердить что ты не робот

Сериализация/десериализация java 8 java.time с помощью Jackson JSON mapper

Как использовать утилиту Jackson JSON с Java 8 LocalDateTime?

org.codehaus.jackson.map.JsonMappingException: не удается создать значение типа [simple type, class java.time.LocalDateTime] из JSON String; нет метода одиночного String/ factory (через цепочку ссылок: MyDTO [ "field1" ] → SubDTO [ "date" ])

4b9b3361

Ответ 1

Здесь нет необходимости использовать пользовательские сериализаторы/десериализаторы. Используйте модуль datetime jackson-modules-java8:

Модуль Datatype, чтобы заставить Джексон распознавать типы данных API Java 8 Дата и время (JSR-310).

Этот модуль добавляет поддержку для нескольких классов:

  • Продолжительность
  • Мгновенный
  • LocalDateTime
  • LocalDate
  • LocalTime
  • MONTHDAY
  • OffsetDateTime
  • OffsetTime
  • Период
  • Год
  • годМесяц
  • ZonedDateTime
  • ZoneId
  • ZoneOffset

Ответ 2

Обновление: оставив этот ответ по историческим причинам, но я не рекомендую его. Пожалуйста, смотрите принятый ответ выше.

Скажите Джексону, чтобы он отображал, используя ваши пользовательские классы сериализации:

@JsonSerialize(using = LocalDateTimeSerializer.class)
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
private LocalDateTime ignoreUntil;

предоставить пользовательские классы:

public class LocalDateTimeSerializer extends JsonSerializer<LocalDateTime> {
    @Override
    public void serialize(LocalDateTime arg0, JsonGenerator arg1, SerializerProvider arg2) throws IOException {
        arg1.writeString(arg0.toString());
    }
}

public class LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {
    @Override
    public LocalDateTime deserialize(JsonParser arg0, DeserializationContext arg1) throws IOException {
        return LocalDateTime.parse(arg0.getText());
    }
}

случайный факт: если я вкладываю классы выше и не делаю их статичными, сообщение об ошибке выглядит странно: org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/json;charset=UTF-8' not supported

Ответ 3

Если вы используете класс ObjectMapper для quickxml, по умолчанию ObjectMapper не понимает класс LocalDateTime, поэтому вам нужно добавить другую зависимость в gradle/maven:

compile 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.7.3'

Теперь вам нужно зарегистрировать поддержку типа данных, предлагаемую этой библиотекой, в объект objectmapper, это можно сделать следующим образом:

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.findAndRegisterModules();

Теперь, в вашей jsonString, вы можете легко поместить свое поле java.LocalDateTime следующим образом:

{
    "user_id": 1,
    "score": 9,
    "date_time": "2016-05-28T17:39:44.937"
}

Выполняя все это, ваш Json файл для преобразования объектов Java будет работать нормально, вы можете прочитать файл, выполнив следующие действия:

objectMapper.readValue(jsonString, new TypeReference<List<User>>() {
            });

Ответ 4

Эта зависимость от maven решит вашу проблему:

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

Одна вещь, с которой я боролся, - это то, что часовой пояс ZonedDateTime изменяется на GMT во время десериализации. Оказалось, что по умолчанию Джексон заменяет его одним из контекста.. Чтобы сохранить зону, необходимо отключить эту функцию

Jackson2ObjectMapperBuilder.json()
    .featuresToDisable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE)

Ответ 5

У меня была аналогичная проблема при использовании Spring загрузки. С помощью Spring boot 1.5.1.RELEASE все, что мне нужно было сделать, это добавить зависимость:

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

Ответ 6

Если вы используете Джерси, вам нужно добавить зависимость Maven (jackson-datatype-jsr310), как и другие, и зарегистрировать экземпляр mapper объекта таким образом:

@Provider
public class JacksonObjectMapper implements ContextResolver<ObjectMapper> {

  final ObjectMapper defaultObjectMapper;

  public JacksonObjectMapper() {
    defaultObjectMapper = createDefaultMapper();
  }

  @Override
  public ObjectMapper getContext(Class<?> type) {
    return defaultObjectMapper;
  }

  private static ObjectMapper createDefaultMapper() {
    final ObjectMapper mapper = new ObjectMapper();    
    mapper.registerModule(new JavaTimeModule());
    return mapper;
  }
}

При регистрации Jackson в ваших ресурсах вам нужно добавить этот mapper так:

final ResourceConfig rc = new ResourceConfig().packages("<your package>");
rc
  .register(JacksonObjectMapper.class)
  .register(JacksonJaxbJsonProvider.class);

Ответ 7

Если вы не можете использовать jackson-modules-java8 по каким-либо причинам, вы можете (de-) сериализовать мгновенное поле до long @JsonIgnore и @JsonGetter & @JsonSetter:

public class MyBean {

    private Instant time = Instant.now();

    @JsonIgnore
    public Instant getTime() {
        return this.time;
    }

    public void setTime(Instant time) {
        this.time = time;
    }

    @JsonGetter
    private long getEpochTime() {
        return this.time.toEpochMilli();
    }

    @JsonSetter
    private void setEpochTime(long time) {
        this.time = Instant.ofEpochMilli(time);
    }
}

Пример:

@Test
public void testJsonTime() throws Exception {
    String json = new ObjectMapper().writeValueAsString(new MyBean());
    System.out.println(json);
    MyBean myBean = new ObjectMapper().readValue(json, MyBean.class);
    System.out.println(myBean.getTime());
}

доходность

{"epochTime":1506432517242}
2017-09-26T13:28:37.242Z

Ответ 8

Я использую этот формат времени: "{birthDate": "2018-05-24T13:56:13Z}" для десериализации из json в java.time.Instant (см. Снимок экрана)

enter image description here

Ответ 9

Это всего лишь пример того, как использовать его в модульном тесте, который я взломал для устранения этой проблемы. Ключевые ингредиенты

  • mapper.registerModule(new JavaTimeModule());
  • maven зависимость <artifactId>jackson-datatype-jsr310</artifactId>

Код:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.testng.Assert;
import org.testng.annotations.Test;

import java.io.IOException;
import java.io.Serializable;
import java.time.Instant;

class Mumu implements Serializable {
    private Instant from;
    private String text;

    Mumu(Instant from, String text) {
        this.from = from;
        this.text = text;
    }

    public Mumu() {
    }

    public Instant getFrom() {
        return from;
    }

    public String getText() {
        return text;
    }

    @Override
    public String toString() {
        return "Mumu{" +
                "from=" + from +
                ", text='" + text + '\'' +
                '}';
    }
}
public class Scratch {


    @Test
    public void JacksonInstant() throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(new JavaTimeModule());

        Mumu before = new Mumu(Instant.now(), "before");
        String jsonInString = mapper.writeValueAsString(before);


        System.out.println("-- BEFORE --");
        System.out.println(before);
        System.out.println(jsonInString);

        Mumu after = mapper.readValue(jsonInString, Mumu.class);
        System.out.println("-- AFTER --");
        System.out.println(after);

        Assert.assertEquals(after.toString(), before.toString());
    }

}

Ответ 10

Вы можете установить это в своем файле application.yml для разрешения моментального времени, которое является API Date в java8:

spring.jackson.serialization.write-dates-as-timestamps=false

Ответ 11

Если вы используете загрузку Spring и имеете эту проблему с OffsetDateTime, тогда вам нужно использовать registerModules, как было сказано выше @greperror (отвечено 28 мая '16 в 13:04), но обратите внимание, что есть одно отличие. Упомянутая зависимость не нуждается в добавлении, так как я предполагаю, что у весенней загрузки она уже есть. У меня была эта проблема с загрузкой Spring, и она работала для меня без добавления этой зависимости.

Ответ 12

Для тех, кто использует Spring Boot 2.x

Нет необходимости делать что-либо из вышеперечисленного - Java 8 LocalDateTime сериализуется/десериализуется из коробки. Мне нужно было сделать все вышеперечисленное в 1.x, но с Boot 2.x все работает без проблем.

Смотрите также эту ссылку JSON Java 8 LocalDateTime формат в Spring Boot

Ответ 13

Если вы решили использовать fastjson, вы можете решить свою проблему, обратите внимание на версию

 <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.56</version>
 </dependency>

Ответ 14

Если у кого-то возникли проблемы при использовании SpringBoot вот как я исправил проблему, не добавляя новую зависимость.

Spring 2.1.3 Джексон ожидает, что строка даты 2019-05-21T07:37:11.000 в этом формате yyyy-MM-dd HH:mm:ss.SSS в LocalDateTime. Убедитесь, что строка даты разделяет дату и время с T не с space. секунд (ss) и миллисекунды (SSS) могут быть пропущены.

@JsonProperty("last_charge_date")
public LocalDateTime lastChargeDate;