なみひらブログ

学んだことを日々記録する。~ since 2012/06/24 ~

Spring MVC+Jacksonで日付文字列をLocalDateTimeにマッピングする

背景

spring-webmvcを使ったWebAPIで、Java8で追加されたLocalDateTimeに対応したときのメモです。

ゴール

以下のようなJSONをLocalDateTimeのパラメータにマッピングします。 (日時のフォーマットは一例です)

  • リクエスト
{
  "name" : "test", 
  "createdAt" : "2016-08-06T9:30:00.000"
}
  • クラス
public class UserDto {
    private String name;
    private LocalDateTime createdAt;
}

対応

JacksonのJSR310ライブラリを取り込む

Java8で追加されたTime & Date型関連はJacksonの別ライブラリとして提供されているのでそれを取り込む。
GitHub - FasterXML/jackson-datatype-jsr310: JSR-310 datatypes (Java 8 java.time.temporal.*)

Datatype module to make Jackson (http://jackson.codehaus.org) recognize Java 8 Date & Time API data types (JSR-310).

  • mavenの例
  • バージョンは2016/08/06時点の最新
(略)
<dependency>
  <groupId>com.fasterxml.jackson.datatype</groupId>
  <artifactId>jackson-datatype-jsr310</artifactId>
  <version>2.8.1</version>
</dependency>
(略)

関連モジュールのSpringへの登録はSpringが自動でやってくれるので、Spring側に特に設定は不要。

Some well known Jackson modules are automatically registered if they are detected on the classpath:
- jackson-datatype-jsr310: Java 8 Date & Time API data types

APIで受け取るクラスにアノテーションを付与する

以下のようなコントローラがあった場合、

@RestController
public class UserApiController {

    @RequestMapping(value = "/users", method = POST)
    public UserDto post(@RequestBody UserDto user) {
        /* do something */
    }

}

受け取るクラス(UserDto)の定義は以下の通り。

import java.time.LocalDateTime;

import lombok.Data;

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

@Data
public class UserDto {

    private String name;

    @DateTimeFormat(iso = ISO.DATE_TIME)
    private LocalDateTime createdAt;
}

ハマった場所

ISO.DATE_TIMEは「yyyy-MM-dd'T'HH:mm:ss.SSSZ」というフォーマットだけれども、Zにあたるタイムゾーンを付与してリクエストを投げるとパースエラーになる(;´Д`)LocalDateTimeはタイムゾーン不要の概念の型なので。

"message":"Could not read document: Can not deserialize value of type java.time.LocalDateTime from String
 \"2016-08-06T9:30:00.000+09:00\": Text '2016-08-06T9:30:00.000+09:00' could not be parsed, unparsed
 text found at index 23\n at [Source: java.io.PushbackInputStream@5930ccd3; line: 1, column: 18]
(以下略)

ZonedDateTime型を変更すればエラー回避できますが、DBとの兼ね合いのあるのでLocalDateTime型で定義しておきたいところ(;´Д`)←今回はここまで。
が、APIを標準によせるとJSR310形式(ISO-8601)のほうが正しそうなのであとでサーバサイドで変換するように直す(;´Д`)

対策は以下参照

まとめ

いい感じにできたのかよくわかっていない(´・ω・`)