1. 概述

本文将介绍 JaVers 库的核心功能。这个库专门用于检测和追踪 Java 对象的状态变更。当我们在代码中使用可变对象时,对象可能在应用的多个位置被修改——JaVers 能帮我们精准捕获并审计这些变更,简直是调试和审计的利器。

2. Maven 依赖配置

先在 pom.xml 中添加核心依赖:

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

最新版本请查阅 Maven 中央仓库

3. 检测 POJO 状态变更

以简单的 Person 类为例:

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

    // 标准 getter/constructor
}

假设在应用某处创建了 Person 对象,而另一处修改了相同 id 对象的 name 字段。我们需要对比这两个对象,找出具体变更点。

使用 JaVers 的 compare() 方法轻松搞定:

@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. 检测对象列表状态变更

处理对象集合时,同样需要逐个检测元素状态变更。常见场景包括:

  • 从列表中移除对象
  • 向列表中新增对象
  • 修改列表中对象的属性

看个实际例子:当从列表中移除某个对象时,这种变更可能引发问题,我们需要审计整个列表的变化。用 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. 对比对象图结构

实际项目中常遇到对象图(对象嵌套对象)。假设有 PersonWithAddress 类包含 Address 列表,当给人员新增地址时:

@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. 总结

JaVers 是个实用的变更检测库,核心优势包括: ✅ 简单 POJO 变更检测:基础属性修改一目了然
集合变更追踪:列表增删改全面覆盖
对象图深度对比:复杂嵌套结构也能轻松搞定

对于需要审计对象状态变更的场景(如配置管理、数据同步),这个库简直是“简单粗暴”的解决方案。完整代码示例请访问 GitHub


原始标题:Intro to JaVer | Baeldung