#目的
Jacksonはjava.util.Dateやjava.util.Timeをよしなに変換してくれ出力はyyyy-MM-dd,HH:MM:ss等のフォーマットにしてくれる。
一方、Java8以降に追加されたjava.timeパッケージのLocal~クラスではうまくシリアライズしてくれず、以下のように連想配列として処理される。
(以下ソースコードは日時の取得に実行時間を利用しているので整合性がありません)
{"id":1,"name":"hoge","registrationDateTime":{"dayOfMonth":19,"dayOfWeek":"WEDNESDAY","dayOfYear":262,"month":"SEPTEMBER","monthValue":9,"year":2018,"hour":10,"minute":28,"nano":916000000,"second":37,"chronology":{"id":"ISO","calendarType":"iso8601"}}}
これでは必要のない情報も多く、受け取る側は困ってしまうので以下のようにしたい。
{"id":1,"name":"hoge","registrationDateTime":"2018/09/19 10:29:30"}
#解決
まずJacksonでjava.timeを扱えるように以下のモジュールをObjectMapperインスタンスに明示的に登録する必要がある。
- JavaTimeModule
このクラスを以下のように利用することで、java.timeをある程度わかりやすくシリアライズしてくれる。
ObjectMapper om = new ObjectMapper();
JavaTimeModule jtm = new JavaTimeModule();
om.registerModule(jtm);
これによって、以下のようにシリアライズしてくれるようになる。
{"id":1,"name":"hoge","registrationDateTime":[2018,9,19,10,24,49,73000000]}
これでもまだ扱いにくいので、デフォルトのフォーマットを変更する処理が必要だ。
以下のように任意のフォーマットを指定できる。
jtm.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss")));
これによって、以下のようにシリアライズしてくれるようになる。
{"id":1,"name":"hoge","registrationDateTime":"2018/09/19 10:29:30"}
今回はシリアライズに焦点をあてていますが、java.timeを利用したJavaObjectに日時をデシリアライズする際、yyyy/MM/ddのようなフォーマットだと例外が発生するので、Serializerを登録した手順と同様にDesirializerも以下のように登録する必要があります。
jtm.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss")));
ソースコード
説明に利用したソースコードはgitにあげてあります実際に実行してみたりしてください。