1. 概要

このクイックチュートリアルでは、 JacksonJSON処理ライブラリを使用して不変のJavaオブジェクトを逆シリアル化する2つの異なる方法を示します。

2. なぜ不変オブジェクトを使用するのですか?

不変オブジェクトは、が作成された瞬間から状態を維持するオブジェクトです。 これは、エンドユーザーがオブジェクトのどのメソッドを呼び出しても、オブジェクトは同じように動作することを意味します。

不変オブジェクトは、マルチスレッド環境で動作する必要があるシステムを設計するときに役立ちます。これは、不変が一般にスレッドの安全性を保証するためです。

一方、不変オブジェクトは、外部ソースからの入力を処理する必要がある場合に役立ちます。 たとえば、ユーザー入力やストレージからのデータなどです。 その場合、受信したデータを保存し、偶発的または意図しない変更から保護することが重要になる場合があります

不変オブジェクトを逆シリアル化する方法を見てみましょう。

3. パブリックコンストラクタ

Employeeクラス構造について考えてみましょう。 idnameの2つの必須フィールドがあるため、オブジェクトのフィールドのセットと一致する引数のセットを持つpublicall-argumentsコンストラクターを定義します。 :

public class Employee {

    private final long id;
    private final String name;

    public Employee(long id, String name) {
        this.id = id;
        this.name = name;
    }

    // getters
}

このようにして、作成時にすべてのオブジェクトのフィールドが初期化されます。 フィールドの宣言の最終修飾子では、将来的に値を変更できません。このオブジェクトを逆シリアル化するには、このコンストラクターに注釈をいくつか追加するだけです。

@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
public Employee(@JsonProperty("id") long id, @JsonProperty("name") String name) {
    this.id = id;
    this.name = name;
}

追加したアノテーションを詳しく見てみましょう。

まず、 @JsonCreator は、Jacksonデシリアライザーにデシリアライズに指定されたコンストラクターを使用するように指示します。

この注釈のパラメーターとして使用できるモードには、PROPERTIESDELEGATINGの2つがあります。

PROPERTIES は、すべて引数のコンストラクターを宣言する場合に最適ですが、 DELEGATING は、単一引数のコンストラクターに役立つ場合があります。

その後、各コンストラクター引数 @JsonProperty で注釈を付け、それぞれのプロパティの名前を注釈値として指定する必要があります。 すべてのプロパティ名は、シリアル化中に使用したものと一致する必要があるため、このステップでは十分に注意する必要があります。

Employeeオブジェクトの逆シリアル化をカバーする簡単な単体テストを見てみましょう。

String json = "{\"name\":\"Frank\",\"id\":5000}";
Employee employee = new ObjectMapper().readValue(json, Employee.class);

assertEquals("Frank", employee.getName());
assertEquals(5000, employee.getId());

4. プライベートコンストラクターとビルダー

オブジェクトにオプションのフィールドのセットがある場合があります。 オプションのageフィールドを持つ別のクラス構造Personについて考えてみましょう。

public class Person {
    private final String name;
    private final Integer age;

    // getters
}

このようなフィールドが多数ある場合、パブリックコンストラクターの作成が面倒になる可能性があります。 つまり、コンストラクターに対して多くの引数を宣言し、それぞれに@JsonPropertyアノテーションを付ける必要があります。 その結果、多くの繰り返し宣言により、コードが肥大化し、読みにくくなります。

これは、古典的なBuilderパターンが助けになる場合です。 逆シリアル化でその力をどのように利用できるか見てみましょう。 まず、プライベートなすべての引数のコンストラクターとBuilderクラスを宣言しましょう。

private Person(String name, Integer age) {
    this.name = name;
    this.age = age;
}

static class Builder {
    String name;
    Integer age;
    
    Builder withName(String name) {
        this.name = name;
        return this;
    }
    
    Builder withAge(Integer age) {
        this.age = age;
        return this;
    }
    
    public Person build() {
        return new Person(name, age);
    } 
}

JacksonデシリアライザーにこのBuilderを使用させるには、コードに2つのアノテーションを追加するだけです。 まず、クラスに @JsonDeserialize アノテーションを付け、builderパラメーターにビルダークラス完全修飾ドメイン名を渡す必要があります。

その後、ビルダークラス自体に@JsonPOJOBuilderという注釈を付ける必要があります。

@JsonDeserialize(builder = Person.Builder.class)
public class Person {
    //...
    
    @JsonPOJOBuilder
    static class Builder {
        //...
    }
}

ビルド中に使用されるメソッドの名前をカスタマイズできることに注意してください。

パラメータbuildMethodNameは、デフォルトで「 build」であり、ビルダーが新しいオブジェクトを生成する準備ができたときに呼び出すメソッドの名前を表します。

もう1つのパラメーターwithPrefixは、プロパティの設定を担当するビルダーメソッドに追加するプレフィックスを表します。 このパラメーターのデフォルト値は、“ with”です。 そのため、この例ではこれらのパラメーターを指定していません。

Personオブジェクトの逆シリアル化をカバーする簡単な単体テストを見てみましょう。

String json = "{\"name\":\"Frank\",\"age\":50}";
Person person = new ObjectMapper().readValue(json, Person.class);

assertEquals("Frank", person.getName());
assertEquals(50, person.getAge().intValue());

5. 結論

この短い記事では、Jacksonライブラリを使用して不変オブジェクトを逆シリアル化する方法を見てきました。

この記事に関連するすべてのコードは、GitHubにあります。