Jacksonを使ったJavaとJSONの相互変換

Ryosuke Honya
6 min readMay 12, 2019

--

はじめに

最近のフレームワークはどれも便利で、特に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 は以下のようになりました。

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の基本的な機能はあるので少しづつ勉強して行きたいと思います。

--

--