JSON-B のご紹介

この記事は Java EE Advent Calendar 2017 の 15 日目です。今日はちゃんと技術的なことを書きます。

Java EE 8 から JSON-B (JSON Binding) という、JAXB の JSON 版のような API が新たに加わりました。これまでも Jackson や EclipseLink MOXy 等のライブラリが JAXB に加え独自の JSON バインディング機能を持っていましたが、それを標準化するべく誕生したのが JSON-B (JSR-367) です。最初に聞いた時のリファレンス実装は EclipseLink MOXy だったので、MOXy の JSON バインディング機能をそのまま採用するのかと思いきや、気付いたらリファレンス実装が Yasson というライブラリに変わっていて、JAXB とは似ても似つかない API に仕上がっていました。なお、Yasson は EE4J 発足直後に参加を表明しています。

JSON-B は Java EE 8 準拠のサーバーであればすぐに使用できますが、Java SE から呼び出して使うことも可能です。その時に必要となるライブラリの Maven 依存関係を以下に示します。

<!-- JSON-P API -->
<dependency>
  <groupId>javax.json</groupId>
  <artifactId>javax.json-api</artifactId>
  <version>1.1</version>
</dependency>

<!-- JSON-P RI -->
<dependency>
  <groupId>org.glassfish</groupId>
  <artifactId>javax.json</artifactId>
  <version>1.1</version>
</dependency>

<!-- JSON-B API -->
<dependency>
  <groupId>javax.json.bind</groupId>
  <artifactId>javax.json.bind-api</artifactId>
  <version>1.0</version>
</dependency>

<!-- Yasson (JSON-B RI) -->
<dependency>
  <groupId>org.eclipse</groupId>
  <artifactId>yasson</artifactId>
  <version>1.0.1</version>
</dependency>

依存関係に JSON-P 1.1 (Java EE 7 の JSON-P 1.0 ではない) が含まれていることに注目してください。JSON-B/Yasson は単独で動作する API ではなく、JSON-P 1.1 の存在を前提として作られています。可能な限り JSON-P のコードを生かそうとする設計思想が伺えます。

Java EE 7 上では JSON-P の新旧バージョンが重複して存在することになるため、できれば使用しない方がいいと思われます。お使いのアプリケーション・サーバーのクラス・ローダーに関して専門的な知識を有していて、その上で自己責任で行うのであれば話は別ですが。

これは JSR-367 の仕様書にも記載されていることですが、JSON-B は RFC 7159 に従って JSON のシリアライズ・デシリアライズとデータ・バインディングを行います。ただし、JSON の規格にない日付型の変換がサポートされている (JSON 側は ISO 8601 準拠で扱う) など、独自色も少しあります。Date and Time API にも完全対応です!

基本的な使い方は、以下のようになります。

  1. JsonbBuilder.create() メソッドから Jsonb オブジェクトを取得する (この時に null の扱いやフォーマット等のオプションを設定できる)
  2. Jsonb.toJson() メソッドで JSON に変換、Jsonb.fromJson() メソッドで JSON をパース

メソッドは IDE のサジェスト機能だけで全容をほぼ把握できる程度です。バインディング対象の Java クラスも、基本的にはアノテーション不要です。

マッピングを明示する場合 (Java 側と JSON 側で異なる名前のマッピングを含む) は @JsonbProperty アノテーション、マッピングから除外する場合は @JsonbTransient アノテーションをそれぞれフィールド、getter、setter のいずれかに付けます。フィールドにアノテーションを付加した場合はシリアライズ・デシリアライズ両方、getter はシリアライズのみ、setter はデシリアライズのみ、それぞれ作用するようになります。

最初はサンプルを載せようかと思って途中まで用意したのですが、あまりにシンプルでむしろ pom.xml に依存関係を追記する方が大変なくらいだったので、そこは各自にお任せします。GlassFish 8、Payara 5、あるいは Java SE で試してみてください。

なお、Java SE で試す場合、Yasson のバージョンは 1.0.1 にしてください。バージョン 1.0 はたぶんバグだと思うのですが JsonbBuilder.create() のタイミングで ClassNotFoundException がスローされます (しかも見つからないと言っているクラスは存在している謎)。