JavaによるJSONバインディングAPI(JSR 367)の紹介

1概要

長い間、JavaにおけるJSON処理の標準はありませんでした。 JSON処理に使用される最も一般的なライブラリはJacksonとGsonです。

最近、Java EE 7には、JSONを解析および生成するためのAPIが付属していました(https://www.jcp.org/en/jsr/detail?id=353[JSR 353:JSON処理用のJava API])。

そして最後に、JEE 8のリリースで、標準化されたAPIがあります(https://jcp.org/en/jsr/detail?id=367[JSR 367:JSONバインディングのためのJava API(JSON-B)])。

今のところ、その主な実装はhttps://github.com/eclipse/yasson[Eclipse Yasson(RI)]とhttps://johnzon.apache.org/[Apache Johnzon]です。

2 JSON-B API

2.1. Mavenの依存関係

必要な依存関係を追加することから始めましょう。

多くの場合、選択した実装への依存関係を含めるだけで十分であり、 javax.json.bind-api が推移的に含まれることになります。

<dependency>
    <groupId>javax.json.bind</groupId>
    <artifactId>javax.json.bind-api</artifactId>
    <version>1.0</version>
</dependency>

最新版はhttps://search.maven.org/classic/#search%7Cga%7C1%7Cjavax.json.bind-api[Maven Central]で見つけることができます。

3 Eclipse Yasson を使う

  • Eclipse YassonはJSONバインディングAPIの公式参照実装** です(https://jcp.org/en/jsr/detail?id=367[JSR-367])。

3.1. Mavenの依存関係

これを使用するには、Mavenプロジェクトに以下の依存関係を含める必要があります。

<dependency>
    <groupId>org.eclipse</groupId>
    <artifactId>yasson</artifactId>
    <version>1.0.1</version>
</dependency>
<dependency>
    <groupId>org.glassfish</groupId>
    <artifactId>javax.json</artifactId>
    <version>1.1.2</version>
</dependency>

最新版はhttps://search.maven.org/classic/#search%7Cga%7C1%7Ca%3A%22yasson%22[Maven Central。]で見つけることができます。

4 Apache Johnzon を使用する

私たちが使用できるもう1つの実装は、JSON-P(JSR-353)およびJSON-B(JSR-367)APIに準拠したApache Johnzonです。

4.1. Mavenの依存関係

これを使用するには、Mavenプロジェクトに以下の依存関係を含める必要があります。

<dependency>
    <groupId>org.apache.geronimo.specs</groupId>
    <artifactId>geronimo-json__1.1__spec</artifactId>
    <version>1.0</version>
</dependency>
<dependency>
    <groupId>org.apache.johnzon</groupId>
    <artifactId>johnzon-jsonb</artifactId>
    <version>1.1.4</version>
</dependency>

最新版はhttps://search.maven.org/classic/#search%7Cga%7C1%7Ca%3A%22johnzon-jsonb%22[Maven Central。]にあります。

5 APIの機能

APIは、シリアライゼーション/デシリアライゼーションをカスタマイズするためのアノテーションを提供します。

単純なクラスを作成して、設定例がどのように見えるかを見てみましょう。

public class Person {

    private int id;

    @JsonbProperty("person-name")
    private String name;

    @JsonbProperty(nillable = true)
    private String email;

    @JsonbTransient
    private int age;

    @JsonbDateFormat("dd-MM-yyyy")
    private LocalDate registeredDate;

    private BigDecimal salary;

    @JsonbNumberFormat(locale = "en__US", value = "#0.0")
    public BigDecimal getSalary() {
        return salary;
    }

   //standard getters and setters
}

直列化後、このクラスのオブジェクトは次のようになります。

{
   "email":"[email protected]",
   "id":1,
   "person-name":"Jhon",
   "registeredDate":"07-09-2019",
   "salary":"1000.0"
}

ここで使用されている注釈は次のとおりです。

  • @ JsonbProperty - カスタムフィールド名を指定するために使用されます

  • @ JsonbTransient - 中にフィールドを無視したい場合

デシリアライゼーション/シリアライゼーション ** @ JsonbDateFormat - の表示フォーマットを定義したいとき

日付 ** @ JsonbNumberFormat - 数値の表示形式を指定します

値 ** @ JsonbNillable - null値のシリアル化を有効にする

5.1. シリアライゼーションとデシリアライゼーション

まず最初に、オブジェクトのJSON表現を取得するために、 JsonbBuilder クラスとその__toJson()メソッドを使用する必要があります。

はじめに、次のような単純な Person オブジェクトを作成しましょう。

Person person = new Person(
  1,
  "Jhon",
  "[email protected]",
  20,
  LocalDate.of(2019, 9, 7),
  BigDecimal.valueOf(1000));

そして、 Jsonb クラスをインスタンス化します。

Jsonb jsonb = JsonbBuilder.create();

それから、 toJson メソッドを使います。

String jsonPerson = jsonb.toJson(person);

次のJSON表現を取得するには

{
    "email":"[email protected]",
    "id":1,
    "person-name":"Jhon",
    "registeredDate":"07-09-2019",
    "salary":"1000.0"
}

別の方法で変換をしたい場合は、 fromJson メソッドを使用できます。

Person person = jsonb.fromJson(jsonPerson, Person.class);

当然、コレクションを処理することもできます。

List<Person> personList = Arrays.asList(...);
String jsonArrayPerson = jsonb.toJson(personList);

次のJSON表現を取得するには

----[
    {
      "email":"[email protected]",
      "id":1,
      "person-name":"Jhon",
      "registeredDate":"09-09-2019",
      "salary":"1000.0"
    },
    {
      "email":"[email protected]",
      "id":2,
      "person-name":"Jhon",
      "registeredDate":"09-09-2019",
      "salary":"1500.0"
    },
    ...]----

JSON配列から List に変換するには、 fromJson APIを使用します。

List<Person> personList = jsonb.fromJson(
  personJsonArray,
  new ArrayList<Person>(){}.getClass().getGenericSuperclass()
);

5.2. JsonbConfig によるカスタムマッピング

JsonbConfig クラスを使用すると、すべてのクラスのマッピングプロセスをカスタマイズできます。

たとえば、デフォルトの命名方法やプロパティの順序を変更できます。

それでは、 LOWER CASE WITH UNDERSCORES__戦略を使用します。

JsonbConfig config = new JsonbConfig().withPropertyNamingStrategy(
  PropertyNamingStrategy.LOWER__CASE__WITH__UNDERSCORES);
Jsonb jsonb = JsonbBuilder.create(config);
String jsonPerson = jsonb.toJson(person);

次のJSON表現を取得するには

{
   "email":"[email protected]",
   "id":1,
   "person-name":"Jhon",
   "registered__date":"07-09-2019",
   "salary":"1000.0"
}

それでは、 REVERSE 戦略を使用してプロパティの順序を変更します。この戦略を使用すると、プロパティの順序は辞書式順序と逆の順序になります。アノテーション__@JsonbPropertyOrderを使用して、コンパイル時にこれを設定することもできます。

JsonbConfig config
  = new JsonbConfig().withPropertyOrderStrategy(PropertyOrderStrategy.REVERSE);
Jsonb jsonb = JsonbBuilder.create(config);
String jsonPerson = jsonb.toJson(person);

次のJSON表現を取得するには

{
    "salary":"1000.0",
    "registeredDate":"07-09-2019",
    "person-name":"Jhon",
    "id":1,
    "email":"[email protected]"
}

5.3. アダプタを使用したカスタムマッピング

アノテーションと JsonbConfig クラスが十分でない場合は、アダプタを使用できます。

それらを使用するには、以下のメソッドを定義する JsonbAdapter インターフェースを実装する必要があります。

  • adaptToJson - この方法では、カスタム変換ロジックを使用できます。

シリアル化プロセスのため。

  • adaptFromJson - このメソッドを使うとカスタム変換ロジックを使うことができます。

逆シリアル化プロセスのため。

Person クラスの id 属性と name 属性を処理するための PersonAdapter を作成しましょう。

public class PersonAdapter implements JsonbAdapter<Person, JsonObject> {

    @Override
    public JsonObject adaptToJson(Person p) throws Exception {
        return Json.createObjectBuilder()
          .add("id", p.getId())
          .add("name", p.getName())
          .build();
    }

    @Override
    public Person adaptFromJson(JsonObject adapted) throws Exception {
        Person person = new Person();
        person.setId(adapted.getInt("id"));
        person.setName(adapted.getString("name"));
        return person;
    }
}

さらに、アダプタを JsonbConfig インスタンスに割り当てます。

JsonbConfig config = new JsonbConfig().withAdapters(new PersonAdapter());
Jsonb jsonb = JsonbBuilder.create(config);

そして、次のようなJSON表現が得られます。

{
    "id":1,
    "name":"Jhon"
}

6. 結論

このチュートリアルでは、利用可能な実装を使用してJSON-B APIとJavaアプリケーションを統合する方法の例と、コンパイル時と実行時の両方でのシリアライゼーションとデシリアライゼーションのカスタマイズ例を示しました。

完全なコードは、いつもどおり、https://github.com/eugenp/tutorials/tree/master/json[over on Github]から入手できます。