JSONは外部のAPIや他システムと連携する際のデータフォーマットとしてよく用いられるフォーマットです。
プログラム内では受け取ったJSONデータをシステム内に取り込んだり、その逆を行ったりすることがあるため、JSONデータの操作が必要となります。
本記事では、JavaにおけるJSONデータの操作についてまとめます。
プログラミング初心者の方の学習や、忘れてしまった方の復習として、参考にしていただければ幸いです。
記載しているプログラムは、Java11を使って動作確認をしています。
JavaのJSON操作
JavaのJSON操作として以下の内容を採り上げます。
- JSONを扱うライブラリ
- JSONファイルの読み込み
- JSONデータの参照
- JSONデータの追加
- JSONデータの削除
- 文字列からJSONオブジェクトへの変換
- JSONオブジェクトから文字列への変換
JSONを扱うライブラリ
JavaでJSONデータを扱うには、多くの場合において外部のライブラリを使用することになります。
有名なものとしては以下があります。
- Jackson:処理が速くJavaに最適なJSONパーサーとして知られています。
- [Github]
- [Mavenリポジトリ]
- Gson:Google製のライブラリです。
- [Github]
- [Mavenリポジトリ]
ライブラリを使うには各リポジトリからダウンロードしてインポートするか、MavenやGradle等のビルドツールを使って利用可能な状態にする必要があります。
本記事では上記2つのライブラリを比較しながら解説をしていきます。
なお、JSONデータを扱う際には、Javaのクラスにマッピングさせる方法とさせない方法があります。
今回はマッピングさせずに、自由にデータを追加や削除する方式で進めていきます。
JSONファイルの読み込み
本記事では、以下のJSONデータを扱います。
{ "string": "文字列", "int": 2020, "bool": true, "null": null, "array": [ {"no": 1, "name": "JavaScript"}, {"no": 2, "name": "Python"} ], "object": { "no": 3, "name": "Java" } }
この内容を data.json というファイルで保存し、プログラムから読み込みます。
Jacksonを使った読み込み
ファイルから読み込んでJsonNode型に変換します。
Jacksonでは、Jsonの値が文字列でも配列でもオブジェクトでも、すべてJsonNode型として表すことができます。
ObjectMapper objectMapper = new ObjectMapper(); JsonNode json = objectMapper.readTree(Paths.get("./data.json").toFile()); System.out.println(json); // -> (上記のJSONの内容が1行で表示される)
上記のプログラムでは、ObjectMapperのreadTreeを使ってファイルを読み込み、JsonNode型のJSONオブジェクトを作成しています。
作成されたJsonNodeを表示させると、読み込んだJSON情報が表示されます。
Gsonを使った読み込み
ファイルから文字列として読み込んで、JsonObject型に変換します。
Gsonでは、Jsonの値が文字列でも配列でもオブジェクトでも、すべてJsonObject型として表すことができます。
Gson gson = new Gson(); JsonObject json = gson.fromJson(Files.readString(Paths.get("./data.json")), JsonObject.class); System.out.println(json); // -> (上記のJSONの内容が1行で表示される)
上記のプログラムでは、GsonのfromJsonを使ってファイルの文字列を、JsonObject型のJSONオブジェクトを作成しています。
作成されたJsonObjectを表示させると、読み込んだJSON情報が表示されます。
JSONデータの参照
JSONオブジェクトのデータを参照するには、データの形式に従ってアクセスします。
Jacksonを使った参照
文字列や整数の参照は、getメソッドに直接キー名を指定することで値を取得することができます。
System.out.println(json.get("string")); // -> "文字列" System.out.println(json.get("int")); // -> 2020 System.out.println(json.get("bool")); // -> true System.out.println(json.get("null")); // -> null
配列の参照は、キー名で参照した後にインデックスを指定して値を参照することができます。
System.out.println(json.get("array").get(0).get("no")); // -> 1 System.out.println(json.get("array").get(0).get("name")); // -> "JavaScript" System.out.println(json.get("array").get(1).get("no")); // -> 2 System.out.println(json.get("array").get(1).get("name")); // -> "Python"
配列なので、ループによる参照も可能です。
配列の中もJsonNode型になっています。
for (JsonNode node : json.get("array")) { System.out.println(node.get("no")); // -> 1 -> 2 System.out.println(node.get("name")); // -> "JavaScript" -> "Python" }
オブジェクトの参照は、ネストするオブジェクトのキー名を指定して値を取得することができます。
オブジェクトの中もJsonNode型になっているので、メソッドチェーンによる呼出しが可能となります。
System.out.println(json.get("object").get("no")); // -> 3 System.out.println(json.get("object").get("name")); // -> "Java"
Gsonを使った参照
文字列や整数の参照は、getメソッドに直接キー名を指定することで値を取得することができます。
System.out.println(json.get("string")); // -> "文字列" System.out.println(json.get("int")); // -> 2020 System.out.println(json.get("bool")); // -> true System.out.println(json.get("null")); // -> null
配列の参照は、キー名で参照した後に、一旦配列を表すJsonArray型に変換し、インデックスを指定して値を参照することができます。
System.out.println(json.get("array").getAsJsonArray().get(0).getAsJsonObject().get("no")); // -> 1 System.out.println(json.get("array").getAsJsonArray().get(0).getAsJsonObject().get("name")); // -> "JavaScript" System.out.println(json.get("array").getAsJsonArray().get(1).getAsJsonObject().get("no")); // -> 2 System.out.println(json.get("array").getAsJsonArray().get(1).getAsJsonObject().get("name")); // -> "Python"
配列なので、ループによる参照も可能です。
配列の中はJsonElement型として取得されます。
for (JsonElement element : json.get("array").getAsJsonArray()) { System.out.println(element.getAsJsonObject().get("no")); // -> 1 -> 2 System.out.println(element.getAsJsonObject().get("name")); // -> "JavaScript" -> "Python" }
オブジェクトの参照は、ネストするオブジェクトのキー名を指定して値を取得することができます。
配列と同じく、一旦JsonObject型として変換後に取得する必要があります。
System.out.println(json.get("object").getAsJsonObject().get("no")); // -> 3 System.out.println(json.get("object").getAsJsonObject().get("name")); // -> "Java"
JSONデータの追加
JSONオブジェクトにデータを追加するには、データの型によって追加方法が異なります。
Jacksonを使った追加
文字列や整数値の追加は、jsonオブジェクトに直接キーと値を指定します。
追加する際にはObjectNode型へキャストしてputを使います。
((ObjectNode) json).put("string2", "文字列2"); ((ObjectNode) json).put("int2", 2021); ((ObjectNode) json).put("bool2", false); ((ObjectNode) json).putNull("null2");
配列への追加は、ArrayNode型に変換して追加します。
配列の中身は予め作成しておきます。
ObjectNode ob1 = objectMapper.createObjectNode(); ob1.put("no", 4); ob1.put("name", "Ruby"); ((ArrayNode) json.path("array")).add(ob1);
オブジェクトへの追加は、ObjectNodeのsetを使って行います。
ObjectNode ob2 = objectMapper.createObjectNode(); ob2.put("no", 5); ob2.put("name", "Go"); ((ObjectNode) json.get("object")).set("object2", ob2);
上記で追加したJSONオブジェクト全体を表示させると以下のようになります。
{ "string" : "文字列", "int" : 2020, "bool" : true, "null" : null, "array" : [ { "no" : 1, "name" : "JavaScript" }, { "no" : 2, "name" : "Python" }, { "no" : 4, "name" : "Ruby" } ], "object" : { "no" : 3, "name" : "Java", "object2" : { "no" : 5, "name" : "Go" } }, "string2" : "文字列2", "int2" : 2021, "bool2" : false, "null2" : null }
Gsonを使った追加
文字列や整数値の追加は、addPropertyを使ってキーと値を指定します。
json.addProperty("string2", "文字列2"); json.addProperty("int2", 2021); json.addProperty("bool2", false); json.add("null2", null);
配列への追加は、JsonArray型に変換して追加します。
配列の中身は予め作成しておきます。
JsonObject jo1 = new JsonObject(); jo1.addProperty("no", 4); jo1.addProperty("name", "Ruby"); json.get("array").getAsJsonArray().add(jo1);
オブジェクトへの追加は、JsonObject型に変換して追加します。
JsonObject jo2 = new JsonObject(); jo2.addProperty("no", 5); jo2.addProperty("name", "Go"); json.get("object").getAsJsonObject().add("object2", jo2);
上記で追加したJSONオブジェクト全体を表示させると以下のようになります。
{ "string": "文字列", "int": 2020, "bool": true, "null": null, "array": [ { "no": 1, "name": "JavaScript" }, { "no": 2, "name": "Python" }, { "no": 4, "name": "Ruby" } ], "object": { "no": 3, "name": "Java", "object2": { "no": 5, "name": "Go" } }, "string2": "文字列2", "int2": 2021, "bool2": false, "null2": null }
JSONデータの削除
Jacksonを使った削除
JSONオブジェクトからデータを削除するには、removeを使います。
それぞれObjectNode型やArrayNode型へキャストする必要があります。
((ObjectNode) json).remove("string2"); ((ObjectNode) json).remove("int2"); ((ObjectNode) json).remove("bool2"); ((ObjectNode) json).remove("null2"); ((ArrayNode) json.path("array")).remove(2); ((ObjectNode) json.get("object")).remove("object2");
上記で削除した結果のJSONオブジェクト全体を表示させると以下のようになります。
(追加した分が削除されて、元の状態に戻っています)
{ "string" : "文字列", "int" : 2020, "bool" : true, "null" : null, "array" : [ { "no" : 1, "name" : "JavaScript" }, { "no" : 2, "name" : "Python" } ], "object" : { "no" : 3, "name" : "Java" } }
Gsonを使った削除
JSONオブジェクトからデータを削除するには、removeを使います。
配列の場合はJsonArray型、オブジェクトの場合はJsonObject型へ一旦変換する必要があります。
json.remove("string2"); json.remove("int2"); json.remove("bool2"); json.remove("null2"); json.get("array").getAsJsonArray().remove(2); json.get("object").getAsJsonObject().remove("object2");
上記で削除した結果のJSONオブジェクト全体を表示させると以下のようになります。
(追加した分が削除されて、元の状態に戻っています)
{ "string": "文字列", "int": 2020, "bool": true, "null": null, "array": [ { "no": 1, "name": "JavaScript" }, { "no": 2, "name": "Python" } ], "object": { "no": 3, "name": "Java" } }
文字列からJSONオブジェクトへの変換
プログラムの中で文字列として作成したJSONをオブジェクトへ変換するには、以下のように実施します。
Jacksonを使った変換
Jacksonの場合は、ObjectMapperのreadTreeで変換します。
String s = "{\"text\": \"テキスト\", \"num\": 1}"; JsonNode jsonNode = objectMapper.readTree(s);
Gsonを使った変換
Gsonの場合は、GsonのfromJsonで変換します。
String s = "{\"text\": \"テキスト\", \"num\": 1}"; JsonObject jsonObject = gson.fromJson(s, JsonObject.class);
JSONオブジェクトから文字列への変換
JSONオブジェクトから文字列へ変換するには、以下のように実施します
Jacksonを使った変換
toStringで1行のJSON文字列を取得することができます。
toPrettyStringを使用すると、改行された見やすいJSON文字列を取得することができます。
System.out.println(jsonNode.toString()); System.out.println(jsonNode.toPrettyString());
Gsonを使った変換
toStringで1行のJSON文字列を取得することができます。
GsonBuilderにsetPrettyPrintingを設定して改めてJSONを構築することで、改行された見やすいJSON文字列を取得することができます。
System.out.println(jsonObject.toString()); System.out.println(new GsonBuilder().setPrettyPrinting().serializeNulls().create().toJson(jsonObject));
JSONデータを自由に扱えるようになろう
最近では、JSON形式のデータをプログラム内だけではなく、ログやインフラ等の設定情報、保存用データなど様々な部分で使われることが増えてきました。
プログラマブルなデータフォーマットとして保存することで、プログラムで自由に解析をしやすくする意図があります。
ちょっとしたJSON解析プログラムを作ることで、今までExcelで集計していた業務を効率化することが出来たり、プログラムによってチェックすることで作業ミスを防止することも出来ます。
こうした日頃の作業をプログラマブルに出来ないか考えてみるのも良いと思います。
今回はJavaのJSON操作についてまとめました。
以上、参考になれば幸いです。
コメント