Search code examples
javacollectionsjavers

Using CustomPropertyComparator with java.util.List


I've created a CustomPropertyComparator to use it to compare Objects which were created by JAXB. So, in my case, I am not able to use the @DiffIgnore annotation offered by the framework. Also, the Collections generated by JAXB are based on java.util.List and not java.util.Collection. Unfortunately, I couldn't manage to make javers use my CustomPropertyComparator with the List Interface.

public class Person {    
    private String name;
    private String ignoreThis;
}

public class Company {
    private String id;
    private Person owner;
    private Collection<Person> clients;
    private List<Person> partners;
}

Comparator that only compares the name, but ignores the ignoreThis field:

public class EntityComparator implements CustomPropertyComparator<Person, ValueChange> {
    public ValueChange compare(Person left, Person right, GlobalId affectedId, Property property) {
        if (left.getName().equals(right.getName()))
            return null;
        return new ValueChange(affectedId, "entity/name", left.getName(), right.getName());
    }    
}

My test-cases looks like this:

This tests works, cause it compares the collection

@Test
public void equalEntityClientTest() {
    Person e1 = new Person("james", "ignore this");
    Company le1 = new Company("1", null, Arrays.asList(e1), null);

    Person e2 = new Person("james", "");
    Company le2 = new Company("1", null, Arrays.asList(e2), null);
    Diff diff = javers.compare(le1, le2);

    System.out.println(diff);
    assertEquals(0, diff.getChanges().size());
}

This test fails, cause it doesn't use my comparator to compare the entity and the diff of the ignored field is true.

@Test
public void equalEntityPartnerTest() {
    Person e1 = new Person("james", "ignore this");
    Company le1 = new Company("1", e1, null, Arrays.asList(e1));

    Person e2 = new Person("james", "");
    Company le2 = new Company("1", e2, null, Arrays.asList(e2));
    Diff diff = javers.compare(le1, le2);

    System.out.println(diff);
    assertEquals(0, diff.getChanges().size());
}

In the reference of javers, they explain if you have a custom Collection-Interface you need to implement your own comparator, which is okay if you use a collection not based on java.util.Collection. But actually, I would expect that java.util.List is supported by the javers Library. Also I wasn't able to figure out how I can add/create a Comparator for the List-Interface.

A working example can be found under https://github.com/baumgartner/javerstest


Solution

  • You have touched two issues here. Your first test passes because Javers ignores Collection properties and only this warning is logged:

    10:19:40.332 [main] WARN  o.j.c.d.a.CollectionChangeFakeAppender - Collections: Field Collection<Person> clients; //declared in Company
    are not equals but can't be compared. Raw Collection properties are not supported. Expected Set, List or any of their subclasses. JaVers uses different algorithms for comparing Sets and Lists and needs to know (statically) which one to test.
    

    I think it's not OK, so I have created an issue, see https://github.com/javers/javers/issues/746

    Second issue concerns CustomPropertyComparator. It was designed to compare large structures like Multimap, and it's not called by JaVers when comparing List items, because when you are comparing List items you need boolean equals(a,b) method. That's what CustomValueComparator does.

    Although, CustomPropertyComparator can be extended to have also boolean equals(a,b) method. I have created the second issue for that, see https://github.com/javers/javers/issues/747