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)の定義は以下の通り。
- DateTimeFormatではいろいろな定義の仕方がある。
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)のほうが正しそうなのであとでサーバサイドで変換するように直す(;´Д`)
対策は以下参照
まとめ
いい感じにできたのかよくわかっていない(´・ω・`)