programing

Jackson Mapper를 사용하여 Java 8 LocalDateTime 직렬화 해제

newsource 2023. 3. 6. 21:12

Jackson Mapper를 사용하여 Java 8 LocalDateTime 직렬화 해제

나는 여기 SO에서 serialization과 deserialization 사이의 serialization에 대한 답변과 함께 몇 가지 질문을 읽었다.java.time.LocalDateTimeJSON 자산도 있는데 작동이 안 되는 것 같아요.

원하는 형식으로 날짜를 반환하도록 Spring Boot Application을 설정할 수 있었습니다.(YYY-MM-dd HH:mmJSON에서 이 형식의 값을 받아들이는 데 문제가 있습니다.

지금까지 제가 한 일은 다음과 같습니다.

maven 의존 관계 추가:jsr310:

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

명시된jsr310내 주요 수업에서:

@EntityScan(basePackageClasses = { App.class, Jsr310JpaConverters.class })

타임스탬프로서의 시리얼화를 무효로 했다.application.properties:

spring.jackson.serialization.write_dates_as_timestamps=false

다음은 datetime에 대한 엔티티 매핑입니다.

@Column(name = "start_date")
@DateTimeFormat(iso = DateTimeFormat.ISO.TIME)
@JsonFormat(pattern = "YYYY-MM-dd HH:mm")
private LocalDateTime startDate;

데이터베이스에 이 날짜를 TIMESTAMP 형식으로 저장합니다.2016-12-01T23:00:00+00:00.

컨트롤러를 통해 이 엔티티에 액세스하면 올바른 startDate 형식의 JSON이 반환됩니다.게시물을 올리려고 할 때, 그리고 역직렬화하려고 할 때,YYYY-MM-dd HH:mm포맷은 다음과 같은 예외가 있습니다.

{
  "timestamp": "2016-10-30T14:22:25.285+0000",
  "status": 400,
  "error": "Bad Request",
  "exception": "org.springframework.http.converter.HttpMessageNotReadableException",
  "message": "Could not read document: Can not deserialize value of type java.time.LocalDateTime from String \"2017-01-01 20:00\": Text '2017-01-01 20:00' could not be parsed: Unable to obtain LocalDateTime from TemporalAccessor: {MonthOfYear=1, WeekBasedYear[WeekFields[SUNDAY,1]]=2017, DayOfMonth=1},ISO resolved to 20:00 of type java.time.format.Parsed\n at [Source: java.io.PushbackInputStream@679a734d; line: 6, column: 16] (through reference chain: com.gigsterous.api.model.Event[\"startDate\"]); nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException: Can not deserialize value of type java.time.LocalDateTime from String \"2017-01-01 20:00\": Text '2017-01-01 20:00' could not be parsed: Unable to obtain LocalDateTime from TemporalAccessor: {MonthOfYear=1, WeekBasedYear[WeekFields[SUNDAY,1]]=2017, DayOfMonth=1},ISO resolved to 20:00 of type java.time.format.Parsed\n at [Source: java.io.PushbackInputStream@679a734d; line: 6, column: 16] (through reference chain: com.gigsterous.api.model.Event[\"startDate\"])",
  "path": "/api/events"
}

이 주제에 대해 많은 답이 있다는 것을 알지만, 그것들을 따라가고 몇 시간 동안 시도해도 내가 무엇을 잘못하고 있는지 알아내는 데 도움이 되지 않았기 때문에, 누군가가 내가 무엇을 놓치고 있는지를 지적해 주었으면 좋겠다.이에 대한 의견을 주셔서 감사합니다!

편집: 프로세스와 관련된 모든 클래스는 다음과 같습니다.

저장소:

@Repository
public interface EventRepository extends PagingAndSortingRepository<Event, Long> {
}

컨트롤러:

@RequestMapping(method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Event> createEvent(@RequestBody Event event) {
        return new ResponseEntity<>(eventRepo.save(event), HttpStatus.CREATED);
}

JSON 요청 유료:

{
  "name": "Test",
  "startDate": "2017-01-01 20:00"
}

이벤트:

@Entity
@Table(name = "events")
@Getter
@Setter
public class Event {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "event_id")
    private long id;

    @Column(name = "name")
    private String name;

    @Column(name = "start_date")
    @DateTimeFormat(iso = DateTimeFormat.ISO.TIME)
    @JsonFormat(pattern = "YYYY-MM-dd HH:mm")
    private LocalDateTime startDate;
}

전달 중인 날짜 시간이 ISO 로컬 날짜 시간 형식이 아닙니다.

로 변경하다

@Column(name = "start_date")
@DateTimeFormat(iso = DateTimeFormatter.ISO_LOCAL_DATE_TIME)
@JsonFormat(pattern = "YYYY-MM-dd HH:mm")
private LocalDateTime startDate;

'2011-12-03T10:15:30' 형식의 날짜 문자열을 전달합니다.

그러나 커스텀 포맷을 전달하려면 올바른 포맷터를 지정하기만 하면 됩니다.

로 변경하다

@Column(name = "start_date")
@DateTimeFormat(iso = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"))
@JsonFormat(pattern = "YYYY-MM-dd HH:mm")
private LocalDateTime startDate;

당신의 문제는 @DateTimeFormat이 전혀 효과가 없다는 것입니다.잭슨은 탈직렬화를 하고 있고 스프링 주석에 대해 아무것도 모르기 때문에 스프링 주석은 탈직렬화 컨텍스트에서 스캔할 수 없습니다.

또는 Java 타임모듈을 등록하면서 포메터를 설정해 볼 수도 있습니다.

LocalDateTimeDeserializer localDateTimeDeserializer = new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
module.addDeserializer(LocalDateTime.class, localDateTimeDeserializer);

여기 제대로 작동하는 탈염제를 사용한 테스트 케이스입니다.Date Time Format 주석을 완전히 삭제해 보십시오.

@RunWith(JUnit4.class)
public class JacksonLocalDateTimeTest {

    private ObjectMapper objectMapper;

    @Before
    public void init() {
        JavaTimeModule module = new JavaTimeModule();
        LocalDateTimeDeserializer localDateTimeDeserializer =  new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
        module.addDeserializer(LocalDateTime.class, localDateTimeDeserializer);
        objectMapper = Jackson2ObjectMapperBuilder.json()
                .modules(module)
                .featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
                .build();
    }

    @Test
    public void test() throws IOException {
        final String json = "{ \"date\": \"2016-11-08 12:00\" }";
        final JsonType instance = objectMapper.readValue(json, JsonType.class);

        assertEquals(LocalDateTime.parse("2016-11-08 12:00",DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm") ), instance.getDate());
    }
}


class JsonType {
    private LocalDateTime date;

    public LocalDateTime getDate() {
        return date;
    }

    public void setDate(LocalDateTime date) {
        this.date = date;
    }
}

몇 년 동안 잘못된 문자 대소문자를 사용하셨습니다.

@JsonFormat(pattern = "YYYY-MM-dd HH:mm")

다음 항목이어야 합니다.

@JsonFormat(pattern = "yyyy-MM-dd HH:mm")

이 변경으로 모든 것이 예상대로 작동하고 있습니다.

이 방법은 효과가 있었습니다.

 @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ", shape = JsonFormat.Shape.STRING)
 private LocalDateTime startDate;

갱신:

변경 내용:

@Column(name = "start_date")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm", iso = ISO.DATE_TIME)
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm")
private LocalDateTime startDate;

JSON 요청:

{
 "startDate":"2019-04-02 11:45"
}

코드에는 다음 두 가지 문제가 있습니다.

1. 잘못된 타입의 사용

LocalDateTime는 타임존을 지원하지 않습니다.아래는 java.time 타입의 개요이며, date-time 문자열과 일치하는 타입을 확인할 수 있습니다.2016-12-01T23:00:00+00:00OffsetDateTime이 「」이기 입니다.+00:00.

여기에 이미지 설명 입력

선언을 다음과 같이 변경합니다.

private OffsetDateTime startDate;

2. 잘못된 형식의 사용

포맷에는 다음 두 가지 문제가 있습니다.

  • '어울리다'를 써야 요.y연령)이 아닌 ()Y(전년대비).자세한 내용은 이 토론에서 확인하십시오.사실, 나는 당신이 그것을 사용하는 것을 추천한다.u신년(연식)이 아닌 (y(연령)자세한 내용은 이 답변을 참조하십시오.
  • '어울리다'를 써야 요.XXX ★★★★★★★★★★★★★★★★★」ZZZZZ 즉,은 프프부부부 should should should, 를를들음음음음음, 음음음음음음음음음음음음 for for for 이다.uuuu-MM-dd'T'HH:m:ssXXX.

매뉴얼 페이지를 확인합니다.DateTimeFormatter이러한 기호/문자에 대한 자세한 내용은 를 참조하십시오.

데모:

import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;

public class Main {
    public static void main(String[] args) {
        String strDateTime = "2019-10-21T13:00:00+02:00";
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:m:ssXXX");
        OffsetDateTime odt = OffsetDateTime.parse(strDateTime, dtf);
        System.out.println(odt);
    }
}

출력:

2019-10-21T13:00+02:00

최신 날짜 API에 대한 자세한 내용은 Trail: Date Time에서 확인하십시오.

Json Serializer를 구현할 수 있습니다.

참조:

그게 네 특질이야

@JsonProperty("start_date")
@JsonFormat("YYYY-MM-dd HH:mm")
@JsonSerialize(using = DateSerializer.class)
private Date startDate;

이 방법으로 커스텀클래스를 구현합니다.

public class DateSerializer extends JsonSerializer<Date> implements ContextualSerializer<Date> {

    private final String format;

    private DateSerializer(final String format) {
        this.format = format;
    }

    public DateSerializer() {
        this.format = null;
    }

    @Override
    public void serialize(final Date value, final JsonGenerator jgen, final SerializerProvider provider) throws IOException {
        jgen.writeString(new SimpleDateFormat(format).format(value));
    }

    @Override
    public JsonSerializer<Date> createContextual(final SerializationConfig serializationConfig, final BeanProperty beanProperty) throws JsonMappingException {
        final AnnotatedElement annotated = beanProperty.getMember().getAnnotated();
        return new DateSerializer(annotated.getAnnotation(JsonFormat.class).value());
    }

}

사후 결과 후에 시험해 보세요.

이것은 나에게 효과가 있었다:

import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.format.annotation.DateTimeFormat.ISO;

@Column(name="end_date", nullable = false)
@DateTimeFormat(iso = ISO.DATE_TIME)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm")
private LocalDateTime endDate;

나한테는 효과가 있어.

@Column(name = "lastUpdateTime")
@DateTimeFormat(iso = ISO.DATE_TIME,pattern = "yyyy-MM-dd HH:mm:ss" )   
@JsonIgnore

JSON은 이 JSON에서 할 수 있습니다.{ "pickupDate":"2014-01-01T00:00:00" }

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

언급URL : https://stackoverflow.com/questions/40327970/deserialize-java-8-localdatetime-with-jacksonmapper