2つのJSONオブジェクトをGsonと比較する
1. 概要
JSONはデータの文字列表現です。 アルゴリズムまたはテストでこのデータを比較したい場合があります。 また、JSONを含む文字列を比較することは可能ですが、文字列の比較は、コンテンツではなく、表現の違いに敏感です。
これを克服し、JSONデータを意味的に比較するには、空白などの影響やオブジェクトのキーの順序の影響を受けないメモリ内の構造にデータをロードする必要があります。
この短いチュートリアルでは、 Gson を使用してこれを解決します。これは、JSONオブジェクト間の詳細な比較を実行できるJSONシリアル化\逆シリアル化ライブラリです。
2. 異なる文字列で意味的に同一のJSON
私たちが解決しようとしている問題を詳しく見てみましょう。
同じJSONデータを表す2つの文字列があると仮定しますが、そのうちの1つには最後に余分なスペースがあります。
String string1 = "{\"fullName\": \"Emily Jenkins\", \"age\": 27 }";
String string2 = "{\"fullName\": \"Emily Jenkins\", \"age\": 27}";
JSONオブジェクトの内容は同じですが、上記を文字列として比較すると、違いがわかります。
assertNotEquals(string1, string2);
JSONは通常これに敏感ではありませんが、オブジェクト内のキーの順序が変更された場合も同じことが起こります。
String string1 = "{\"fullName\": \"Emily Jenkins\", \"age\": 27}";
String string2 = "{\"age\": 27, \"fullName\": \"Emily Jenkins\"}";
assertNotEquals(string1, string2);
これが、JSONデータを比較するためにJSON処理ライブラリを使用することでメリットが得られる理由です。
3. Mavenの依存関係
Gsonを使用するには、最初にGsonMaven依存関係を追加しましょう。
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
4. JSONをGsonオブジェクトに解析する
オブジェクトの比較に入る前に、GsonがJavaでJSONデータをどのように表現するかを見てみましょう。
JavaでJSONを操作する場合、最初にJSON文字列をJavaオブジェクトに変換する必要があります。 Gsonは、ソースJSONをJsonElementツリーに解析するJsonParserを提供します。
JsonParser parser = new JsonParser();
String objectString = "{\"customer\": {\"fullName\": \"Emily Jenkins\", \"age\": 27 }}";
String arrayString = "[10, 20, 30]";
JsonElement json1 = parser.parse(objectString);
JsonElement json2 = parser.parse(arrayString);
JsonElement は抽象クラスであり、JSONの要素を表します。 parse メソッドは、JsonElementの実装を返します。 JsonObject、JsonArray、JsonPrimitiveまたはJsonNull:のいずれか
assertTrue(json1.isJsonObject());
assertTrue(json2.isJsonArray());
これらの各サブクラス( JsonObject、JsonArray、など)は、Object.equalsメソッドをオーバーライドし、効果的な詳細なJSON比較を提供します。
5. Gson比較のユースケース
5.1. 2つの単純なJSONオブジェクトを比較する
キーの順序が異なる単純なJSONオブジェクトを表す2つの文字列があるとします。
最初のオブジェクトは、ageより前のfullNameを持っています。
{
"customer": {
"id": 44521,
"fullName": "Emily Jenkins",
"age": 27
}
}
2番目は順序を逆にします:
{
"customer": {
"id": 44521,
"age": 27,
"fullName": "Emily Jenkins"
}
}
それらを簡単に解析して比較できます。
assertEquals(parser.parse(string1), parser.parse(string2));
この場合、JsonParserはJsonObjectを返しますが、そのequals実装はorder-sensitiveではありません。
5.2. 2つのJSON配列を比較する
JSON配列の場合、JsonParserはJsonArray。を返します。
1つの順序で1つの配列がある場合:
[10, 20, 30]
assertTrue(parser.parse(string1).isJsonArray());
別の順序で比較できます。
[20, 10, 30]
JsonObject とは異なり、 JsonArrayのequalsメソッドは順序依存であるため、これらの配列は等しくありません。これは意味的に正しいです。
assertNotEquals(parser.parse(string1), parser.parse(string2));
5.3. 2つのネストされたJSONオブジェクトを比較する
前に見たように、JsonParserはJSONのツリーのような構造を解析できます。 各JsonObjectおよびJsonArrayには、他の JsonElement オブジェクトが含まれています。これらのオブジェクトは、それ自体がJsonObjectまたはJsonArrayタイプである可能性があります。
equals を使用すると、すべてのメンバーが再帰的に比較されます。つまり、ネストされたオブジェクトも比較可能です:
これがstring1の場合:
{
"customer": {
"id": "44521",
"fullName": "Emily Jenkins",
"age": 27,
"consumption_info": {
"fav_product": "Coke",
"last_buy": "2012-04-23"
}
}
}
そして、このJSONはstring2です。
{
"customer": {
"fullName": "Emily Jenkins",
"id": "44521",
"age": 27,
"consumption_info": {
"last_buy": "2012-04-23",
"fav_product": "Coke"
}
}
}
次に、equalsメソッドを使用してそれらを比較できます。
assertEquals(parser.parse(string1), parser.parse(string2));
6. 結論
この短い記事では、JSONをStringとして比較する際の課題について説明しました。 Gsonを使用して、これらの文字列を解析して、比較をサポートするオブジェクト構造にする方法を見てきました。
いつものように、上記の例のソースコードはGitHubにあります。