web-dev-qa-db-ja.com

JacksonMapperでJava 8 LocalDateTimeをデシリアライズします

SOでJava.time.LocalDateTimeとJSONプロパティの間のシリアル化とデシリアル化に関するいくつかの質問とその回答を読んだことがありますが、機能していないようです。

希望する形式(YYY-MM-dd HH:mm)で日付を返すようにSpring Bootアプリケーションを設定できましたが、この形式の値をJSONで受け入れるのに問題があります。

これらは私がこれまでに行ったすべてのことです:

jsr310のMaven依存関係を追加しました:

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

私のデータベースでは、この日付を2016-12-01T23:00:00+00:00という形式でTIMESTAMPとして保存します。

コントローラ経由でこのエンティティにアクセスすると、正しい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リクエストPayalod:

{
  "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;
}
25
Smajl

渡す日時は、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 timeモジュールの登録中にフォーマッターを設定してみることができます。

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

これは、正常に機能する脱塩剤を使用したテストケースです。 DateTimeFormatアノテーションを完全に削除しようとする場合があります。

@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;
    }
}
31
user2683814

行の年に間違った大文字小文字を使用しました:

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

する必要があります:

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

この変更により、すべてが期待どおりに機能します。

17

JsonSerializerを実装できます

見る:

Beanのプロパティ

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

}

投稿結果の後にこれを試してください。

2

更新:

への変更:

@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
LeandroPL

これは私のために働いた:

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;
0
Alferd Nobel