Works by

Ren's blog

@rennnosuke_rk 技術ブログです

【Java】Jacksonで任意形式のJSONをパースする

Jackson

Jacksonについては以下の記事を参照。

rennnosukesann.hatenablog.com

多様なJSONの構造

前回の記事で、JSONをMapオブジェクトにする記事を書きました。

rennnosukesann.hatenablog.com

JacksonではJSONファイルやStringオブジェクトとしてのJSONJavaクラスのオブジェクトに簡単にマッピングしてくれます。
この記事のように、JSONをMapオブジェクトに変換することも可能です。

しかし、各プロパティの値が階層的にオブジェクトになっている場合は、Map<String, Object>でごまかすか、 Map<String,Object>Map<String, Map<String, Object>>>のようにわかる範囲までジェネリクス型を明示してあげる必要があります。
更に後者の場合、各プロパティの階層レベルがすべて等しくなければパースに失敗します。

コンテナとなるJavaクラスを定義することでもパースが可能ですが、JSONのパターンの数だけJavaクラスを定義しなければならなくなり、面倒です (新しいパターンが増えたらまたクラスを定義する必要もあります)。

任意の構造を持つJSONを読み込む

Jacksonでは、ObjectMapperクラスのメソッドreadTree()を用いることでこの問題を解決できます。

String json = "{ ... }"; // JSON形式文字列
ObjectMapper mapper = new ObjectMapper();
JsonNode root = mapper.readTree(json);

readTree()JsonNodeオブジェクトを返します。
JsonNodeJSON木構造に見立てたときのノード(枝)として振る舞い、ノードに格納された値を参照したり、小ノードを参照することができます。

Source

JSON
{
  "hoge": {
    "fuga": 1,
    "piyo": 2
  },
  "foo": ["bar", "bow"]
}
Source
package com.company;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import jdk.nashorn.internal.runtime.regexp.JoniRegExp;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.security.spec.ECParameterSpec;

public class Main {

    public static void main(String[] args) {

        String json = readJsonAsString("res/hoge.json");

        if (json != null) {
            try {
                readJsonNode(json);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     *
     * readTree()でJsonNodeインスタンスを作成
     *
     */
    private static void readJsonNode(String json) throws IOException {
        ObjectMapper mapper = new ObjectMapper();

        // JSON文字列を読み込み、JsonNodeオブジェクトに変換(Fileやbyte[]も引数に取れる)
        JsonNode root = mapper.readTree(json);

        // get()で指定したキーに対応するJsonNodeを取得できる
        System.out.println(root.get("hoge")); // {"fuga":1,"piyo":2}

        // 階層的にアクセス可能
        System.out.println(root.get("hoge").get("fuga")); // 1

        // 配列にアクセスするときは添字をわたす
        System.out.println(root.get("foo").get(0)); // "bar"

        // 値を特定の基本型に変換して取得可能
        System.out.println(root.get("hoge").get("piyo").asInt()); // 2
        System.out.println(root.get("hoge").get("piyo").asDouble()); // 2.0
        System.out.println(root.get("hoge").get("piyo").asBoolean()); // true

        // toString()でJSON全体を文字列として取得
        System.out.println(root.toString()); // {"hoge":{"fuga":1,"piyo":2},"foo":["bar","bow"]}

    }


    /**
     *
     * JSONファイルを一つの文字列オブジェクトとして読み込み
     *
     */
    private static String readJsonAsString(String filename) {
        ObjectMapper mapper = new ObjectMapper();
        try {
            BufferedReader reader = new BufferedReader(new FileReader(new File(filename)));
            String line = null;
            StringBuilder builder = new StringBuilder();
            while ((line = reader.readLine()) != null) {
                builder.append(line);
            }
            return builder.toString();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}

参考

github.com