Java EE 7でのJSON処理

Java EE 7でのJSON処理

1. 概要

この記事では、JerseyやJacksonなどのサードパーティの依存関係を使用せずに、コアJava EEのみを使用してJSONを処理する方法を示します。 使用するほとんどすべてがjavax.jsonパッケージによって提供されます。

2. JSONStringへのオブジェクトの書き込み

JavaオブジェクトをJSONStringに変換するのは非常に簡単です。 単純なPersonクラスがあるとしましょう。

public class Person {
    private String firstName;
    private String lastName;
    private Date birthdate;

    // getters and setters
}

そのクラスのインスタンスをJSONStringに変換するには、最初にJsonObjectBuilderのインスタンスを作成し、add()メソッドを使用してプロパティと値のペアを追加する必要があります。

JsonObjectBuilder objectBuilder = Json.createObjectBuilder()
  .add("firstName", person.getFirstName())
  .add("lastName", person.getLastName())
  .add("birthdate", new SimpleDateFormat("DD/MM/YYYY")
  .format(person.getBirthdate()));

add()メソッドにはいくつかのオーバーロードされたバージョンがあることに注意してください。 2番目のパラメーターとして、ほとんどのプリミティブ型(およびボックス化されたオブジェクト)を受け取ることができます。

プロパティの設定が完了したら、オブジェクトをStringに書き込む必要があります。

JsonObject jsonObject = objectBuilder.build();

String jsonString;
try(Writer writer = new StringWriter()) {
    Json.createWriter(writer).write(jsonObject);
    jsonString = writer.toString();
}

以上です! 生成されたStringは次のようになります。

{"firstName":"Michael","lastName":"Scott","birthdate":"06/15/1978"}

2.1. JsonArrayBuilderを使用した配列の構築

ここで、例をもう少し複雑にするために、Personクラスが変更されて、電子メールアドレスのリストを含むemailsという新しいプロパティが追加されたと仮定します。

public class Person {
    private String firstName;
    private String lastName;
    private Date birthdate;
    private List emails;

    // getters and setters

}

そのリストのすべての値をJsonObjectBuilderに追加するには、JsonArrayBuilderの助けが必要です。

JsonArrayBuilder arrayBuilder = Json.createArrayBuilder();

for(String email : person.getEmails()) {
    arrayBuilder.add(email);
}

objectBuilder.add("emails", arrayBuilder);

JsonArrayBuilderオブジェクトを2番目のパラメーターとして受け取るadd()メソッドのさらに別のオーバーロードバージョンを使用していることに注意してください。

それでは、2つの電子メールアドレスを持つPersonオブジェクトに対して生成された文字列を見てみましょう。

{"firstName":"Michael","lastName":"Scott","birthdate":"06/15/1978",
 "emails":["[email protected]","[email protected]"]}

2.2. PRETTY_PRINTINGで出力をフォーマットする

これで、Javaオブジェクトを有効なJSONStringに正常に変換できました。 ここで、次のセクションに進む前に、出力をより「JSONのよう」で読みやすくするために、いくつかの簡単なフォーマットを追加しましょう。

前の例では、単純なJson.createWriter()静的メソッドを使用してJsonWriterを作成しました。 生成されたStringをより細かく制御するために、Java 7のJsonWriterFactory機能を利用して、特定の構成のライターを作成します。

Map config = new HashMap<>();

config.put(JsonGenerator.PRETTY_PRINTING, true);

JsonWriterFactory writerFactory = Json.createWriterFactory(config);

String jsonString;

try(Writer writer = new StringWriter()) {
    writerFactory.createWriter(writer).write(jsonObject);
    jsonString = writer.toString();
}

コードは少し冗長に見えるかもしれませんが、実際にはあまり効果がありません。

まず、構成マップをコンストラクターに渡すJsonWriterFactoryのインスタンスを作成します。 マップには、PRETTY_PRINTINGプロパティをtrueに設定するエントリが1つだけ含まれています。 次に、Json.createWriter()を使用する代わりに、そのファクトリインスタンスを使用してライターを作成します。

新しい出力には、JSONStringを特徴付ける特徴的な改行と表が含まれます。

{
    "firstName":"Michael",
    "lastName":"Scott",
    "birthdate":"06/15/1978",
    "emails":[
        "[email protected]",
        "[email protected]"
    ]
}

3. StringからJavaObjectを構築する

次に、反対の操作を実行します。JSONStringをJavaオブジェクトに変換します。

変換プロセスの主要部分は、JsonObjectを中心に展開されます。 このクラスのインスタンスを作成するには、静的メソッドJson.createReader()の後にreadObject()を使用します。

JsonReader reader = Json.createReader(new StringReader(jsonString));

JsonObject jsonObject = reader.readObject();

createReader()メソッドは、パラメーターとしてInputStreamを取ります。 この例では、JSONがStringオブジェクトに含まれているため、StringReader,を使用していますが、これと同じメソッドを使用して、たとえばFileInputStreamを使用してファイルからコンテンツを読み取ることができます。 s。

JsonObjectのインスタンスが手元にある場合、getString()メソッドを使用してプロパティを読み取り、取得した値をPersonクラスの新しく作成されたインスタンスに割り当てることができます。

Person person = new Person();

person.setFirstName(jsonObject.getString("firstName"));
person.setLastName(jsonObject.getString("lastName"));
person.setBirthdate(dateFormat.parse(jsonObject.getString("birthdate")));

3.1. JsonArrayを使用してList値を取得する

JsonObjectからリスト値を抽出するには、JsonArrayという特別なクラスを使用する必要があります。

JsonArray emailsJson = jsonObject.getJsonArray("emails");

List emails = new ArrayList<>();

for (JsonString j : emailsJson.getValuesAs(JsonString.class)) {
    emails.add(j.getString());
}

person.setEmails(emails);

それでおしまい! JsonStringからPersonの完全なインスタンスを作成しました。

4. 値のクエリ

ここで、JSONString内にある非常に特定のデータに関心があると仮定します。

ペットショップのクライアントを表す以下のJSONを検討してください。 なんらかの理由で、ペットリストから3番目のペットの名前を取得する必要があるとします。

{
    "ownerName": "Robert",
    "pets": [{
        "name": "Kitty",
        "type": "cat"
    }, {
        "name": "Rex",
        "type": "dog"
    }, {
        "name": "Jake",
        "type": "dog"
    }]
}

単一の値を取得するためだけにテキスト全体をJavaオブジェクトに変換することは、あまり効率的ではありません。 それでは、変換の試練全体を経ることなく、JSONStringsをクエリするためのいくつかの戦略を確認しましょう。

4.1. オブジェクトモデルAPIを使用したクエリ

JSON構造内の既知の場所でプロパティの値をクエリするのは簡単です。 前の例で使用したのと同じクラスのJsonObject,のインスタンスを使用できます。

JsonReader reader = Json.createReader(new StringReader(jsonString));

JsonObject jsonObject = reader.readObject();

String searchResult = jsonObject
  .getJsonArray("pets")
  .getJsonObject(2)
  .getString("name");

ここでの落とし穴は、get*()メソッドの正しいシーケンスを使用してjsonObjectプロパティをナビゲートすることです。

この例では、最初にgetJsonArray()_ which returns a list with 3 records. Then, we use _getJsonObject()メソッドを使用して「ペット」リストへの参照を取得します。このメソッドは、インデックスをパラメーターとして受け取り、の3番目の項目を表す別のJsonObjectを返します。リスト。 最後に、getString()を使用して、探している文字列値を取得します。

4.2. ストリーミングAPIを使用したクエリ

JSONStringで正確なクエリを実行する別の方法は、メインクラスとしてJsonParserを持つストリーミングAPIを使用することです。

JsonParserは、JSへの非常に高速な読み取り専用の転送アクセスを提供しますが、オブジェクトモデルよりもいくらか複雑であるという欠点があります。

JsonParser jsonParser = Json.createParser(new StringReader(jsonString));

int count = 0;
String result = null;

while(jsonParser.hasNext()) {
    Event e = jsonParser.next();

    if (e == Event.KEY_NAME) {
        if(jsonParser.getString().equals("name")) {
            jsonParser.next();

            if(++count == 3) {
                result = jsonParser.getString();
                break;
            }
        }
    }
}

この例では、前の例と同じ結果が得られます。 petsリストの3番目のペットからnameを返します。

Json.createParser()を使用してJsonParserを作成したら、イテレータ(したがって、JsonParserの「フォワードアクセス」の性質)を使用して、プロパティに到達するまでJSONトークンをナビゲートする必要があります。 (またはプロパティ)私たちが探しています。

イテレータをステップスルーするたびに、JSONデータの次のトークンに移動します。 そのため、現在のトークンに期待されるタイプがあるかどうかを注意深くチェックする必要があります。 これは、next()呼び出しによって返されたEventをチェックすることによって行われます。

トークンにはさまざまな種類があります。 この例では、プロパティの名前を表すKEY_NAMEタイプに関心があります(例: 「ownerName」、「pets」、「name」、「type」)。 値が「name」のKEY_NAMEトークンを3回ステップスルーすると、次のトークンには、リストの3番目のペットの名前を表す文字列値が含まれることがわかります。

これは、特に複雑なJSON構造の場合、Object Model APIを使用するよりも明らかに困難です。 どちらか一方を選択することは、いつものように、対処する特定のシナリオによって異なります。

5. 結論

Java EE JSON Processing APIの多くの基礎を、いくつかの簡単な例で説明しました。 JSON処理に関するその他の優れた点については、series of Jackson articlesを確認してください。

この記事で使用されているクラスのソースコードと、いくつかの単体テストをGitHub repositoryで確認してください。