🦁

JavaでJsonNodeを活用してJSONからデータを取り出す方法

2024/03/07に公開

はじめに

APIで取得した値で、意図した階層の値を取得したいのだが、どうやったら取得できるのかがわからなかったので色々調べてみた。

この記事でわかること

  1. Jacksonを使ってJsonからデータを取り出す方法

結局こんな感じ

外部APIから値を取得する(今回はホットペッパーAPIより)

//HTTPクライアントの作成
OkHttpClient client = new OkHttpClient();

//APIキー
String apiKey = "********";
//検索条件で住所を設定
String address = "新宿";
//URLに検索条件を含める
String url = "http://webservice.recruit.co.jp/hotpepper/gourmet/v1/?key=" + apiKey +
            "&address=" + address +
            "&format=json";

//GetRequestを作る
Request request = new Request.Builder()
                .url(url)
                .build();

//リクエストを送りレスポンスを受け取る
Response response = client.newCall(request).execute();            

//レスポンスボディを文字列に置換する                    
String jsonStr = response.body().string();

Jacksonを使ってみる

文字列だけでは、Jsonのデータを扱うことはできず、取得したい値が自由に取り出せません。
そこで便利なのがJacsonというライブラリです。
Json文字列をJsonNodeというJson文字列をツリー状に変換しメソッドを使いながら情報を操作できるオブジェクトへ変換(パース)します。

ライブラリの導入

Maven

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.17.0</version>
</dependency>

Gradle

// https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
implementation group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.17.0'

サンプルで確認

例:JSON

{
  "name": "John Doe",
  "age": 30,
  "address": {
    "street": "123 Main St",
    "city": "Anytown",
    "state": "CA"
  },
  "phoneNumbers": [
    {"type": "home", "number": "123-456-7890"},
    {"type": "mobile", "number": "456-789-0123"}
  ]
}

例:Json文字列

String jsonStr = "{\n" +
"  \"name\": \"John Doe\",\n" +
"  \"age\": 30,\n" +
"  \"address\": {\n" +
"    \"street\": \"123 Main St\",\n" +
"    \"city\": \"Anytown\",\n" +
"    \"state\": \"CA\"\n" +
"  },\n" +
"  \"phoneNumbers\": [\n" +
"    {\n" +
"      \"type\": \"home\",\n" +
"      \"number\": \"123-456-7890\"\n" +
"    },\n" +
"    {\n" +
"      \"type\": \"mobile\",\n" +
"      \"number\": \"456-789-0123\"\n" +
"    }\n" +
"  ]\n" +
"}";

例:上記Json文字列をJsonNodeでツリー構造化したもの

- ルートノード(オブジェクト)
  - name: "John Doe"(文字列)
  - age: 30(数値)
  - address: オブジェクトノード
    - street: "123 Main St"(文字列)
    - city: "Anytown"(文字列)
    - state: "CA"(文字列)
  - phoneNumbers: 配列ノード
    - [0]: オブジェクトノード
      - type: "home"(文字列)
      - number: "123-456-7890"(文字列)
    - [1]: オブジェクトノード
      - type: "mobile"(文字列)
      - number: "456-789-0123"(文字列)

ここで、ルートノードはJSONオブジェクト全体を表しており、
name、
age、
address、
phoneNumbersというキーを持つ子ノードを持っています。
addressとphoneNumbersはさらに自分自身の子ノードを持っており、
これらの子ノードも同様に自分のプロパティや配列の要素を持つことができます。
このように、JsonNodeを使うことで、JSONデータの階層的な構造をツリー状に表現し、
各ノードへのアクセスやデータの操作が容易になります。
例えば、Stringからname値を取り出したい場合は、
こんな感じで取得します。

// JSON文字列
String jsonStr = "{\n" +
"  \"name\": \"John Doe\",\n" +
"  \"age\": 30,\n" +
"  \"address\": {\n" +
"    \"street\": \"123 Main St\",\n" +
"    \"city\": \"Anytown\",\n" +
"    \"state\": \"CA\"\n" +
"  },\n" +
"  \"phoneNumbers\": [\n" +
"    {\n" +
"      \"type\": \"home\",\n" +
"      \"number\": \"123-456-7890\"\n" +
"    },\n" +
"    {\n" +
"      \"type\": \"mobile\",\n" +
"      \"number\": \"456-789-0123\"\n" +
"    }\n" +
"  ]\n" +
"}";

// ObjectMapperインスタンスの作成
ObjectMapper mapper = new ObjectMapper();

// JSON文字列をJsonNodeオブジェクトにパース
JsonNode rootNode = mapper.readTree(jsonStr);

// "name"キーに対応する値の取得
String name = rootNode.get("name").asText();

// nameを出力
System.out.println(name);

こんな感じでJson文字列をJsonオブジェクトに変換(パース)すると、
getメソッドを使って少しずつ階層を辿ることができ欲しい情報を取得することができる。

店名を取得してみる

先ほど

String jsonStr = response.body().string();

で欲しいJSON文字列は取得できたので、
ツリー構造かつ、データ操作が可能なJsonNodeオブジェクトにパースしていく。
ObjectMapperは今回は、JsonNodeにパースするためのオブジェクトだと思ってたら大丈夫そう。

// ObjectMapperインスタンスの生成
ObjectMapper mapper = new ObjectMapper();

// JSON文字列をJsonNodeオブジェクトにパース
JsonNode rootNode = mapper.readTree(jsonStr);

// 必要なデータの取得
JsonNode shopsNode = rootNode.get("results").get("shop").get(0);
String name = shopsNode.get("name").asText();
String nameKana = shopNode.get("name_kana").asText();
System.out.println("name: " + name);
System.out.println("name_kana: " + nameKana);
name: KOBE YAKITORI STAND 野乃鳥 新宿店
name_kana: こうべやきとりすたんどののとりしんじゅくてん

ってな感じで取得できました。

参考サイト

https://fasterxml.github.io/jackson-databind/javadoc/2.7/

https://tech.excite.co.jp/entry/2021/12/22/163906

https://www.bold.ne.jp/engineer-club/java-json#:~:text=JsonNodeは、JSONを読み取っ,からJsonNodeを作り出します。

https://www.delftstack.com/ja/howto/java/java-convert-string-to-json-object/#jackson-を用いて文字列を-json-オブジェクトに変換する

Discussion