Jsoniterの紹介
1. 序章
JavaScript Object Notation(JSON)は、近年、データ交換形式として多くの人気を博しています。 Jsoniter は、他の利用可能なパーサーよりも柔軟でパフォーマンスの高いJSON解析を提供することを目的とした新しいJSON解析ライブラリです。
このチュートリアルでは、JavaのJsoniterライブラリを使用してJSONオブジェクトを解析する方法を説明します。
2. 依存関係
Jsoniter の最新バージョンは、MavenCentralリポジトリーから見つけることができます。
pom.xmlに依存関係を追加することから始めましょう。
<dependency>
<groupId>com.jsoniter<groupId>
<artifactId>jsoniter</artifactId>
<version>0.9.23</version>
</dependency>
同様に、build.gradleファイルに依存関係を追加できます。
compile group: 'com.jsoniter', name: 'jsoniter', version: '0.9.23'
3. Jsoniterを使用したJSON解析
Jsoniterは、JSONドキュメントを解析するための3つのAPIを提供します。
- バインドAPI
- 任意のAPI
- イテレータAPI
上記の各APIを見てみましょう。
3.1. BindAPIを使用したJSON解析
bind APIは、JSONドキュメントをJavaクラスにバインドする従来の方法を使用します。
学生の詳細を含むJSONドキュメントについて考えてみましょう。
{"id":1,"name":{"firstName":"Joe","surname":"Blogg"}}
次に、上記のJSONを表すStudentおよびNameschemaクラスを定義しましょう。
public class Student {
private int id;
private Name name;
// standard setters and getters
}
public class Name {
private String firstName;
private String surname;
// standard setters and getters
}
バインドAPIを使用してJSONをJavaオブジェクトに逆シリアル化するのは非常に簡単です。 JsonIteratorのdeserializeメソッドを使用します。
@Test
public void whenParsedUsingBindAPI_thenConvertedToJavaObjectCorrectly() {
String input = "{\"id\":1,\"name\":{\"firstName\":\"Joe\",\"surname\":\"Blogg\"}}";
Student student = JsonIterator.deserialize(input, Student.class);
assertThat(student.getId()).isEqualTo(1);
assertThat(student.getName().getFirstName()).isEqualTo("Joe");
assertThat(student.getName().getSurname()).isEqualTo("Blogg");
}
The 学生スキーマクラスは id の int データ・タイプ
{"id":"1","name":{"firstName":"Joe","surname":"Blogg"}}
今回は、JSONの idが文字列値“ 1”であることに注意してください。 Jsoniterは、このシナリオに対処するために多分デコーダーを提供します。
3.2. たぶんデコーダー
JSON要素のデータ型があいまいな場合にJsoniterの多分デコーダーが便利です。 student.id フィールドのデータ型はあいまいです— Stringまたはintのいずれかです。 これを処理するには、 MaybeStringIntDecoder を使用して、スキーマクラスのidフィールドに注釈を付ける必要があります。
public class Student {
@JsonProperty(decoder = MaybeStringIntDecoder.class)
private int id;
private Name name;
// standard setters and getters
}
idの値がStringの場合でも、JSONを解析できるようになりました。
@Test
public void givenTypeInJsonFuzzy_whenFieldIsMaybeDecoded_thenFieldParsedCorrectly() {
String input = "{\"id\":\"1\",\"name\":{\"firstName\":\"Joe\",\"surname\":\"Blogg\"}}";
Student student = JsonIterator.deserialize(input, Student.class);
assertThat(student.getId()).isEqualTo(1);
}
同様に、Jsoniterは、MaybeStringLongDecoderやMaybeEmptyArrayDecoderなどの他のデコーダーを提供します。
ここで、 Student の詳細を含むJSONドキュメントを受け取ることを期待していたが、代わりに次のドキュメントを受け取ると想像してみましょう。
{"error":404,"description":"Student record not found"}
ここで何が起こったのですか? Student データで成功応答を期待していましたが、エラー応答を受け取りました。 これは非常に一般的なシナリオですが、これをどのように処理しますか?
1つの方法は、 null チェックを実行して、Studentデータを抽出する前にエラー応答を受信したかどうかを確認することです。 ただし、 null チェックを行うと、コードが読みづらくなる可能性があり、マルチレベルのネストされたJSONがある場合は問題がさらに悪化します。
AnyAPIを使用したJsoniterの解析が役に立ちます。
3.3. AnyAPIを使用したJSON解析
JSON構造自体が動的である場合、JSONのスキーマレス解析を提供するJsoniterのAnyAPIを使用できます。 これは、JSONを解析して地図
以前と同じようにStudent JSONを解析しますが、今回は AnyAPIを使用します。
@Test
public void whenParsedUsingAnyAPI_thenFieldValueCanBeExtractedUsingTheFieldName() {
String input = "{\"id\":1,\"name\":{\"firstName\":\"Joe\",\"surname\":\"Blogg\"}}";
Any any = JsonIterator.deserialize(input);
assertThat(any.toInt("id")).isEqualTo(1);
assertThat(any.toString("name", "firstName")).isEqualTo("Joe");
assertThat(any.toString("name", "surname")).isEqualTo("Blogg");
}
この例を理解しましょう。 まず、 JsonIterator.deserialize(..)を使用してJSONを解析します。 ただし、この場合、スキーマクラスは指定しません。 結果はタイプです
次に、フィールド名を使用してフィールド値を読み取ります。 Any.toIntメソッドを使用して「id」フィールド値を読み取ります。 toInt メソッドは、「id」値を整数に変換します。 同様に、 toString メソッドを使用して、「name.firstName」および「name.surname」フィールド値を文字列値として読み取ります。
Any APIを使用して、要素がJSONに存在するかどうかを確認することもできます。要素を検索し、検索結果のvalueTypeを調べることでこれを行うことができます。 要素がJSONに存在しない場合、valueTypeはINVALIDになります。
例えば:
@Test
public void whenParsedUsingAnyAPI_thenFieldValueTypeIsCorrect() {
String input = "{\"id\":1,\"name\":{\"firstName\":\"Joe\",\"surname\":\"Blogg\"}}";
Any any = JsonIterator.deserialize(input);
assertThat(any.get("id").valueType()).isEqualTo(ValueType.NUMBER);
assertThat(any.get("name").valueType()).isEqualTo(ValueType.OBJECT);
assertThat(any.get("error").valueType()).isEqualTo(ValueType.INVALID);
}
「id」フィールドと「name」フィールドはJSONに存在するため、それらのvalueTypeはそれぞれNUMBERとOBJECTです。 ただし、JSON入力には「error」という名前の要素がないため、valueTypeはINVALIDです。
前のセクションの最後で説明したシナリオに戻ると、受け取ったJSON入力が成功かエラー応答かを検出する必要があります。 「error」要素のvalueTypeを調べることにより、エラー応答を受信したかどうかを確認できます。
String input = "{\"error\":404,\"description\":\"Student record not found\"}";
Any response = JsonIterator.deserialize(input);
if (response.get("error").valueType() != ValueType.INVALID) {
return "Error!! Error code is " + response.toInt("error");
}
return "Success!! Student id is " + response.toInt("id");
実行すると、上記のコードは
次に、IteratorAPIを使用してJSONドキュメントを解析する方法を見ていきます。
3.4. IteratorAPIを使用したJSON解析
バインディングを手動で実行する場合は、JsoniterのIteratorAPIを使用できます。JSONについて考えてみましょう。
{"firstName":"Joe","surname":"Blogg"}
以前に使用したNameスキーマクラスを使用して、 IteratorAPIを使用してJSONを解析します。
@Test
public void whenParsedUsingIteratorAPI_thenFieldValuesExtractedCorrectly() throws Exception {
Name name = new Name();
String input = "{\"firstName\":\"Joe\",\"surname\":\"Blogg\"}";
JsonIterator iterator = JsonIterator.parse(input);
for (String field = iterator.readObject(); field != null; field = iterator.readObject()) {
switch (field) {
case "firstName":
if (iterator.whatIsNext() == ValueType.STRING) {
name.setFirstName(iterator.readString());
}
continue;
case "surname":
if (iterator.whatIsNext() == ValueType.STRING) {
name.setSurname(iterator.readString());
}
continue;
default:
iterator.skip();
}
}
assertThat(name.getFirstName()).isEqualTo("Joe");
assertThat(name.getSurname()).isEqualTo("Blogg");
}
上記の例を理解しましょう。 まず、JSONドキュメントをイテレータとして解析します。 結果のJsonIteratorインスタンスを使用して、JSON要素を反復処理します。
- まず、 readObject メソッドを呼び出して、次のフィールド名を返します(または、ドキュメントの最後に達した場合は null )。
- フィールド名に関心がない場合は、skipメソッドを使用してJSON要素をスキップします。 それ以外の場合は、whatIsNextメソッドを使用して要素のデータ型を検査します。 whatIsNext メソッドの呼び出しは必須ではありませんが、フィールドのデータ型が不明な場合に役立ちます。
- 最後に、readStringメソッドを使用してJSON要素の値を抽出します。
4. 結論
この記事では、JSONドキュメントをJavaオブジェクトとして解析するためにJsoniterが提供するさまざまなアプローチについて説明しました。
最初に、スキーマクラスを使用してJSONドキュメントを解析する標準的な方法を確認しました。
次に、MaybeデコーダーとAnyデータ型をそれぞれ使用してJSONドキュメントを解析する際のファジーデータ型と動的構造の処理について説明しました。
最後に、JSONをJavaオブジェクトに手動でバインドするための IteratorAPIを確認しました。
いつものようにソース この記事で使用されている例のコードは、GitHubでから入手できます。