Jacksonを使ったJavaとJSONの相互変換
はじめに
最近のフレームワークはどれも便利で、特にSpringなんかはRestControllerアノテーションを付与するとHTTPのリクエストで送られてくるJSONをKotlinへ変換してくれます。ただ、便利ものを使っているせいでJacksonの基本的な機能を学習する機会がありませんでした。という訳でJackson単体の勉強をしてみようと思ったのです。
Jacksonとは?
JacksonとはJavaとJSONの相互変換を行うライブラリです。GitHubのページには"best JSON parser for Java"と謳っているように、JavaのJSON相互変換ライブラリといったらJacksonが挙がるでしょう。また、JSONだけでなくYAMLやCSVといった形式への変換も可能みたいです。
Jacksonのコアモジュールは次にあげる3つがあります。
- Streaming : JSON特有の実装を含んだ、低レベルのストリーミングAPI
- Annotations : 基本的なJacksonのアノテーション
- Databind : データバインディング。StreamingとAnnotationに依存
ObjectMapper
ObjectMapperクラスを使うことでJavaとJSONの相互変換を行うことができます。おそらく、Jacksonの中で一番重要なクラスでしょう。ObjectMapperはDatabindモジュールに含まれています。なので、Databindモジュールをクラスパスに追加することでJavaとJSONの相互変換を行えるようになります。
Gradleでセットアップしましたが、build.gradle は以下のようになりました。
JacksonはJavaクラスのフィールドにアクセスするため、Lombokをプロジェクトに追加しgetter/setterを自動生成するようにしました。
チュートリアルサイトを参考に、JavaからJSONへ変換を行ってみます。
変換するクラスは Albumクラスです。AlbumクラスはフィールドにArtisクラスを保持しています。
JacksonのObjectMapperを使って変換を行うコードは以下のようになりました。
ObjectMapper#writeメソッドによりJavaインスタンスがJSON形式に変換されているのがわかります。リストやマップもそれぞれ対応したJSONの形式に変換されていますね。
LocalDate型のJSONへの変換
LocalDate型のdateOfBirthについては日付形式の文字列ではなく、何やら複雑なJSONオブジェクトになっています。これは、JacksonがLocalDate型のJavaインスタンスをそのままJSON形式に変換しているからです。しかし、読みやすい形式、例えば YYYY-MM-DD などに変換したい場合もあるでしょう。このような場合は JsonSerialize アノテーションを使用します。
参考にしたサイトはこちら。
JsonSerializeアノテーションをArtistのdateOfBirthフィールドに付与しました。JsonSerializeはLocalDate型だけではなく、そのほかの型にも適用できます。適用箇所はクラスやフィールドで、それらの型をどのようにシリアライズするかをコントロールすることができるようになります。
JsonSerializeアノテーションにはusing値にシリアライズ処理を委譲するクラスを指定します。上記の例ではLocalDateSerializerを指定し、LocalDate型のシリアライズ処理をそのクラスに委譲しました。using値にセットできるクラスはJsonSerializerクラスを継承したものに限られます。上記の例ではJsonSerializerクラスのデフォルト実装であるStdSerializerクラスを継承し、シリアライズ処理を実装しています。シリアライズ処理はStdSerializer#serializeメソッドをオーバーライドし実装します。
JSONからJavaへ
ここまではJavaインスタンスをJSON形式の文字列に変換する方法を見てきました。ではJSONからJavaインスタンスへの変換はどうするのでしょうか。それはObjectMapper#readValueメソッドで実行することができます。以下に例を載せます。
少し例が長くなりましたが、JavaからJSONに変換するときと大差ありません。JSONからJavaインスタンスに変換するときにはObjectMapper#readメソッドの引数にJSON文字列と変換先のJavaインスタンスを指定します。
LocalDate型のDateOfBirthフィールドには JsonDeserialize アノテーションを付与しLocalDate型のデシリアライズ処理を実装しています。これは読み込むJSONのDateOfBirthフィールドがISO形式になっており、Jacksonのデフォルトの動作ではLocalDate型に変換することができないからです。
JsonDeserializeアノテーションはJsonSerializeアノテーションとほぼ同じで、文字列を特定のJavaインスタンスの型に変換する処理を特定のクラスに委譲します。上記の例ではLocalDateDeserializerクラスを指定しています。
おわりに
今回はJacksonを使用してJavaとJSONの相互変換を行いました。また、LocalDate型の変換処理では JsonSerialize、JsonDeserializeアノテーションを使用することで特定のフォーマットで相互変換できることを確かめました。少しづつJacksonのことがわかってきた気がします。まだまだJacksonの基本的な機能はあるので少しづつ勉強して行きたいと思います。