JSON とバインディング

JSON とは

JSON (JavaScript Object Notation; じぇいそん) は軽量なテキストベースのデータ交換フォーマットです。 JavaScript に由来しますが、汎用的なデータ交換フォーマットとして広く利用されています。

JSON の仕様に基づき記述されたデータを JSONテキストと呼びます。 JSONテキストは、オブジェクトまたは配列からなります。 オブジェクトはフィールドとして name と value のペアを持ち、 value の値はオブジェクトや配列になり得ることから、 階層構造を表現することができます。

{
  "item": {
    "title": "The JavaScript Object Notation (JSON) Data Interchange Format",
    "link": "https://tools.ietf.org/html/rfc8259",
    "description": "JavaScript Object Notation (JSON) is a lightweight, text-based, language-independent data interchange format."
  },
  "item": {
    "title": "Information technology - The JSON data interchange syntax",
    "link": "https://www.iso.org/standard/71616.html",
    "description": "JSON is a lightweight, text-based, language-independent syntax for defining data interchange formats."
  }
}

データの例

JSON では、中括弧 { } でオブジェクト、大括弧 [ ] で配列が表現されます。

{
    "events": [
        {
            "title": "イベント1",
            "series": {
                "title": "グループA"
            }
         },
        {
            "title": "イベント2",
            "series": {
                "title": "グループB"
            }
         }
     ]
}

上の例では 3種類のオブジェクトがあります。 フィールド name と value の区切りはコロン : 、要素の区切りはカンマ , です。

プログラミング

Java で JSON を扱うライブラリが公開されています。

このページでは Jackson を使う例を取り上げます。

準備

Eclipse で使用しているプロジェクトが Maven プロジェクトであるなら、 pom.xml の dependencies 要素の中に以下の記述を追加することで利用できるようになります。

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.13.0</version>
</dependency>

Maven って何? という人で、新規プロジェクトで初めてもよいという人は、 以下のページを参照しましょう。

基本的な考え方

Jackson は JSON のオブジェクトを Java のクラスに対応付け(マッピング)します。 いくつかアプローチがあります。

  1. JSON に現れる各オブジェクトに対応するクラスを定義しておき、そのクラスにマッピングする。配列は List として扱う。
  2. JSON に現れる各オブジェクトを Map に、配列を List にマッピングする。
  3. JSON に現れる各オブジェクトや配列を汎用のクラス JsonNode にマッピングする。

このページでは 1 と 3 の例を示します。 対応するにふさわしい独自のクラスを用意したいなら 1 が、 事前準備を省力化したいなら 3 が適しています。

クラスを定義する例: connpassのイベント検索

イベント情報サイト connpass では、イベントサーチ API を提供しています。

イベントをキーワード検索する場合のリクエスト URL は以下のようになります。

    https://connpass.com/api/v1/event/?keyword=<query>

<query>の部分は検索語が入ります。

オブジェクトに対応するクラス

Response.java

Event.java

なお、使用しないフィールドの定義を省略したい場合には、クラス定義の直前に以下のように書いておきます。

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties(ignoreUnknown=true)

もしくは、プログラム本体(後述)で生成する ObjectMapper のインスタンスに、未知のフィールドを無視するよう設定します。

import com.fasterxml.jackson.databind.DeserializationFeature;

    ...

    ObjectMapper mapper = new ObjectMapper()
        .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

Connpass の API では日時が ISO-8601 形式の文字列で表されています。 文字列のままでは不便なので、 上記の Event クラスでは Java 7 で利用可能な java.util.Date に変換するメソッドを用意しています。 (なお、Java 8 以降では java.time パッケージ のクラス群を使うこともできます)

Series.java

プログラム本体

ConnpassSearcher.java

JsonNode にマッピングする例: 小説家になろうの小説検索

サイト 小説家になろう では、検索の API を提供しています。

小説をキーワード検索する場合のリクエスト URL は以下のようになります。

    https://api.syosetu.com/novelapi/api/?out=json&word=<query>

<query>の部分は検索語が入ります。

プログラミング

ObjectMapper クラスの readTree メソッドを使うと JSON テキストをツリーにマッピングし、その rootノードを JsonNode として取得することができます。

	ObjectMapper mapper = new ObjectMapper();
	JsonNode rootNode = mapper.readTree(inputStream);

JsonNode はオブジェクトの場合と配列の場合があります。 JsonNode クラスにはそれぞれの場合に用いるメソッドが共存しています。

JsonNode が配列の場合、JsonNode クラスに Iterable<JsonNode> インタフェースが実装されていますので、拡張for文が利用できます。 要素の型は JsonNode です。size(), get(index) のメソッドを使うこともできます。

JsonNode がオブジェクトの場合、get(name) メソッドでフィールド名 name に対応する value を得ることができます。 戻り値の型は JsonNode なので、value が文字列の場合は asText() メソッド, int の場合は asInt() メソッドで値を取り出します。

プログラム本体

SyosetuSearcher.java