[jackson] Jackson JSON 매퍼로 java 8 java.time 직렬화 / 직렬화 해제

Java 8 LocalDateTime에서 Jackson JSON 매퍼를 어떻게 사용합니까?

org.codehaus.jackson.map.JsonMappingException : JSON 문자열에서 [단순 유형, 클래스 java.time.LocalDateTime] 유형의 값을 인스턴스화 할 수 없습니다. 단일 문자열 생성자 / 공장 메소드 없음 (참조 체인을 통해 : MyDTO [ “field1”]-> SubDTO [ “date”])



답변

여기서는 사용자 정의 시리얼 라이저 / 디시리얼라이저를 사용할 필요가 없습니다. jackson-modules-java8의 datetime 모듈을 사용하십시오 .

Jackson이 Java 8 날짜 및 시간 API 데이터 유형 (JSR-310)을 인식하도록하는 데이터 유형 모듈.

이 모듈은 몇 가지 클래스에 대한 지원을 추가합니다.

  • 지속
  • 즉시
  • LocalDateTime
  • 현지 날짜
  • 현지 시각
  • 월 일
  • 오프셋 날짜
  • 오프셋 시간
  • 기간
  • YearMonth
  • ZonedDateTime
  • ZoneId
  • ZoneOffset

답변

업데이트 : 역사적인 이유로이 답변을 남기지 만 권장하지 않습니다. 위의 허용 된 답변을 참조하십시오.

Jackson에게 사용자 정의 직렬화 클래스를 사용하여 맵핑하도록 지시하십시오.

@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


답변

fasterxml의 ObjectMapper 클래스를 사용하는 경우 기본적으로 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>>() {
            });


답변

이 maven 종속성은 문제를 해결합니다.

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

내가 어려움을 겪은 한 가지는 직렬화 해제 중에 ZonedDateTime 시간대가 GMT로 변경된다는 것입니다. 기본적으로 jackson은이를 컨텍스트에서 하나로 대체합니다. 영역을 유지하려면이 ‘기능’을 비활성화해야합니다.

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


답변

스프링 부트 를 사용하는 동안 비슷한 문제가 발생했습니다 . Spring boot 1.5.1.RELEASE를 사용하면 종속성을 추가하기 만하면됩니다.

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


답변

Jersey를 사용하는 경우 다른 사람들이 제안한대로 Maven 종속성 (jackson-datatype-jsr310)을 추가하고 다음과 같이 객체 매퍼 인스턴스를 등록해야합니다.

@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을 등록 할 때 다음과 같이이 매퍼를 추가해야합니다.

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


답변

jackson-modules-java8어떤 이유로 든 사용할 수없는 경우 and & 를 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