1. 概要

この記事では、JaVersライブラリについて説明します。

このライブラリは、プログラマーが単純なJavaオブジェクトの状態の変化を調べて検出するのに役立ちます。 コードで可変オブジェクトを使用すると、すべてのオブジェクトがアプリケーションのさまざまな場所で変更される可能性があります。 JaVersは、これらの変更を発見して監査するのに役立ちます

2. Mavenの依存関係

開始するには、 javers-coreMaven依存関係をpom.xmlに追加しましょう。

<dependency>
    <groupId>org.javers</groupId>
    <artifactId>javers-core</artifactId>
    <version>3.1.0</version>
</dependency>

最新バージョンはMavenCentralで見つけることができます。

3. POJO状態の変化の検出

簡単なPersonクラスから始めましょう。

public class Person {
    private Integer id;
    private String name;

    // standard getters/constructors
}

アプリケーションの一部でPersonオブジェクトを作成し、コードベースの他の部分で、同じidフィールドを持つ人物の名前が変更されたとします。 それらを比較して、人物オブジェクトにどのような変更が発生したかを調べます。

JaVersクラスのcompare()メソッドを使用して、これら2つのオブジェクトを比較できます。

@Test
public void givenPersonObject_whenApplyModificationOnIt_thenShouldDetectChange() {
    // given
    Javers javers = JaversBuilder.javers().build();

    Person person = new Person(1, "Michael Program");
    Person personAfterModification = new Person(1, "Michael Java");

    // when
    Diff diff = javers.compare(person, personAfterModification);

    // then
    ValueChange change = diff.getChangesByType(ValueChange.class).get(0);

    assertThat(diff.getChanges()).hasSize(1);
    assertThat(change.getPropertyName()).isEqualTo("name");
    assertThat(change.getLeft()).isEqualTo("Michael Program");
    assertThat(change.getRight()).isEqualTo("Michael Java");
}

4. オブジェクトリストの状態変化の検出

オブジェクトのコレクションを操作している場合は、コレクション内の各要素を調べて、同様に状態の変化を調べる必要があります。 特定のオブジェクトをリストに追加またはリストから削除して、その状態を変更したい場合があります。

例を見てみましょう; オブジェクトのリストがあり、そのリストから1つのオブジェクトを削除するとします。

この変更は何らかの理由で望ましくない可能性があるため、このリストで発生した変更を監査します。 JaVersでは、 compareCollections()メソッドを使用してこれを行うことができます。

@Test
public void givenListOfPersons_whenCompare_ThenShouldDetectChanges() {
    // given
    Javers javers = JaversBuilder.javers().build();
    Person personThatWillBeRemoved = new Person(2, "Thomas Link");
    List<Person> oldList = 
      Lists.asList(new Person(1, "Michael Program"), personThatWillBeRemoved);
    List<Person> newList = 
      Lists.asList(new Person(1, "Michael Not Program"));

    // when
    Diff diff = javers.compareCollections(oldList, newList, Person.class);

    // then
    assertThat(diff.getChanges()).hasSize(3);

    ValueChange valueChange = 
      diff.getChangesByType(ValueChange.class).get(0);
 
    assertThat(valueChange.getPropertyName()).isEqualTo("name");
    assertThat(valueChange.getLeft()).isEqualTo("Michael Program");
    assertThat(valueChange.getRight()).isEqualTo("Michael Not Program");

    ObjectRemoved objectRemoved = diff.getChangesByType(ObjectRemoved.class).get(0);
    assertThat(
      objectRemoved.getAffectedObject().get().equals(personThatWillBeRemoved))
      .isTrue();

    ListChange listChange = diff.getChangesByType(ListChange.class).get(0);
    assertThat(listChange.getValueRemovedChanges().size()).isEqualTo(1);
}

5. オブジェクトグラフの比較

実際の単語のアプリケーションでは、オブジェクトグラフを扱うことがよくあります。 [X21X]Addressオブジェクトのリストを持つPersonWithAddressクラスがあり、指定された人物の新しいアドレスを追加するとします。

発生した変更の種類を簡単に見つけることができます。

@Test
public void givenListOfPerson_whenPersonHasNewAddress_thenDetectThatChange() {
    // given
    Javers javers = JaversBuilder.javers().build();

    PersonWithAddress person = 
      new PersonWithAddress(1, "Tom", Arrays.asList(new Address("England")));

    PersonWithAddress personWithNewAddress = 
      new PersonWithAddress(1, "Tom", 
        Arrays.asList(new Address("England"), new Address("USA")));


    // when
    Diff diff = javers.compare(person, personWithNewAddress);
    List objectsByChangeType = diff.getObjectsByChangeType(NewObject.class);

    // then
    assertThat(objectsByChangeType).hasSize(1);
    assertThat(objectsByChangeType.get(0).equals(new Address("USA")));
}

同様に、アドレスの削除が検出されます。

@Test
public void givenListOfPerson_whenPersonRemovedAddress_thenDetectThatChange() {
    // given
    Javers javers = JaversBuilder.javers().build();

    PersonWithAddress person = 
      new PersonWithAddress(1, "Tom", Arrays.asList(new Address("England")));

    PersonWithAddress personWithNewAddress = 
      new PersonWithAddress(1, "Tom", Collections.emptyList());


    // when
    Diff diff = javers.compare(person, personWithNewAddress);
    List objectsByChangeType = diff.getObjectsByChangeType(ObjectRemoved.class);

    // then
    assertThat(objectsByChangeType).hasSize(1);
    assertThat(objectsByChangeType.get(0).equals(new Address("England")));
}

6. 結論

このクイック記事では、オブジェクトの状態変化を検出するためのAPIを提供する便利なライブラリであるJaVersライブラリを使用しました。 単純なPOJOオブジェクトの変更を検出できるだけでなく、オブジェクトのコレクションやオブジェクトグラフのより複雑なシフトも検出できます。

いつものように、コードはGitHubから入手できます。