Search code examples
javers

Compare value objects using a custom comparator


I want to compare value objects in a way that null properties are ignored.
More specifically, I only want to include those properties of a value object in the comparison which are not-null on the right side. E.g.

class Person {
  String name;
  String surname;   
}


Person personLeft = new Person();
personLeft.name = "John";
personLeft.surname = "Doe";

Person personRight = new Person();
personRight.name="John"


// this should NOT yield any changes
javers.compare(personLeft, personRight);


// that comparison however, will show that surname has changed
javers.compare(personRight, personLeft);

I though I could tackle this problem by writing a custom comparator and registering it for Person. Unfortunately this comparator is never called. Stumbling upon that post, I fear that this is not possible using a custom comparator for the Person class.
Instead I would have to register custom comparators for all containing value types of the Person class, i.e. String.

Is that the intended use of javers or are there any alternatives to that approach?


Solution

  • What is important here is that CustomValueComparator can be used only for Value types. So you have 2 options:

    1. Map Person as Value and then you implement diff algorithm for Person. It works but is awkward because Person is more like an Entity.
    2. Register a CustomValueComparator for Strings (all Strings), and then you can use Person as Entity. That's the option that I would choose.

    See how it works (groovy):

    class Entity {
        @Id int id
        Person person
    }
    
    class Person {
        String name
    }
    
    def "should use CustomValueComparator for Person when Person is mapped as Value"(){
      given:
        def javers = JaversBuilder.javers().registerValue(Person,
                { l, r -> if (r.name == null) return true
                          else return r.name.equals(l.name)
                }).build()
    
        def personLeft = new Person(name: "john")
        def personRight = new Person()
    
        def eLeft = new Entity(id:1, person: personLeft)
        def eRight = new Entity(id:1, person: personRight)
    
      expect:
        javers.compare(eLeft, eRight).changes.size() == 0
        javers.compare(eRight, eLeft).changes.size() == 1
    
        javers.getTypeMapping(Person) instanceof ValueType
    }
    
    def "should used CustomValueComparator for Strings"(){
      given:
        def javers = JaversBuilder.javers().registerValue(String,
              { l, r -> if (r == null) return true
              else return r.equals(l)
              }).build()
    
        def personLeft = new Person(name: "john")
        def personRight = new Person()
    
      expect:
        javers.compare(personLeft, personRight).changes.size() == 0
        javers.compare(personRight, personLeft).changes.size() == 1
    
        javers.getTypeMapping(Person) instanceof ValueObjectType
    }