Class DeepComparator

java.lang.Object
com.graphql_java_generator.plugin.test.helper.DeepComparator
All Implemented Interfaces:
Cloneable

public class DeepComparator extends Object implements Cloneable
This class deep compares two objects, say a and b. It:
  • Checks that a and b are of the same class
  • Compares each field of a to each field of b (the fields defined in their superclasses are also scanned):
  • If the field is an id field, and a.id.equals(b.id), then a and b are considered as being the same. The comparison will check that there other attributes are equals, and if not these differences are registered as differences of the same object (with the key being the value of the id field, like the key in a Map). See addIdField(Class, String) for more information on this
  • If the field is an ignored field, this field is skipped
  • If the field is of a basic type: use the equals method. All enums should be registered in the basic type list.
  • If the field is a List: do a deep non-ordered comparison. Each list must be of the same size, and each object in a's field must be deep equal to one object of the b's list. To do this, for each item in a's list, a recursive deepEquals call is done on each item of the b's list until this deepEquals call returns true. If no such call returns true, then this item of the a's list is not present in the b's list: they are different
  • If the field is a known object type (see parameters): a recursive call to the deep comparison is done, to compare the a's field to the b's field.
  • Otherwise an error is thrown (non managed type for comparison). This insure that the proper comparison mode is used
All differences are logged if the level is debug or lower. They are also returned by the #differences(Object, Object) method, to allow further processing. This makes it possible to correct these differences.
Author:
etienne-sf
  • Constructor Details

    • DeepComparator

      public DeepComparator()
    • DeepComparator

      public DeepComparator(org.slf4j.Logger logger)
  • Method Details

    • equals

      public boolean equals(Object o1, Object o2)
      Executes a deep comparison between the two given objects.
      Parameters:
      o1 -
      o2 -
      Returns:
      true if no differences have been found, during the deep comparison. False if at least one difference has been found.
    • differences

      public List<DeepComparator.Difference> differences(Object o1, Object o2, int nbMaxDifferences)
      Executes a deep comparison between the two given objects. All differences are reported.
      If you just want to know if these two objects are different, you can use the #differences(Object, Object) method, which will stop the comparison as soon as a difference is found. It may be much faster.
      Parameters:
      o1 -
      o2 -
      nbMaxDifferences - The maximum number of differences to return. This allows to limit the size of the returned list, and to accelerate the comparison.
      Setting 1 here will stop as soon as a difference is found.
      Setting it to a negative value prevents any comparison to occur.
      Set it to Integer.MAX_VALUE to have (almost) no limit on the number of returned differences
      Returns:
      The list of differences. Always non null. If this list is empty, then the two objects are identical
    • compare

      public boolean compare(Object o1, Object o2)
      Executes a deep comparison between the two given objects. This method is internal: it used when recursing into objects of a collection. The path parameter allows to log where the comparison is located, when in debug log level.
      This method stops after the first difference found.
      Parameters:
      o1 -
      o2 -
      Returns:
      true if no differences have been found, during the deep comparison. False if at least one difference has been found.
    • addBasicClass

      public void addBasicClass(Class<?> clazz)
      Add a Class as an basic class, that is a class that is compared by using the Object.equals(Object) method
      Parameters:
      clazz -
    • addIgnoredClass

      public void addIgnoredClass(Class<?> clazz)
      Add a Class as an ignored class, that is that if a field to compare is of this class, the comparison is skipped
      Parameters:
      clazz -
    • addIdField

      public void addIdField(Class<?> clazz, String fieldName)
      Add an idField for a class. An idField is a field that identify an instance of a given class.Two objects with the same value in their id field are same (for instance two persons of the same name), but may not be equals (other attributes differ). This allows to trace differences in two objects that are the same.
      For classes that has such a field, the rules are :
      • If the id field of the two instances are differents, generates a difference with the current difference's path
      • If the id field of the two instances are equals, add /Xxx(idField:id) to the difference's path (where Xxx is the classname, idField is name if the field/attribute that has been compared and id is the value for this id field as a String), and loop for the other attributes
      When such a field is defined for a class, when compariring tw will be ignored, for each class. The key is the class. The value is the list of ignored field names for this class. The ignored fields should contain all ignored fields for this class, including those which are actually defined in its superclasses. This allow to choose if a field is ignored or not per subclass (if there are two subclasses for one superclasse).
      Parameters:
      clazz -
      fieldName -
    • addIgnoredFields

      public void addIgnoredFields(Class<?> clazz, String fieldName)
      Add a field of a class as ignored. That is: when comparing this class as an object, this field will be skipped.
      Parameters:
      clazz -
      fieldName -
    • addSpecificComparisonRules

      public void addSpecificComparisonRules(Class<?> clazz, String fieldName, DeepComparator.ComparisonRule comparator)
      Add a comparison rule, for the given field of the given classe. This DeepComparator.ComparisonRule will be called for each such field of such class that is encountered during the deep comparison.
      This allows to break cycles (and avoid Stack Overflow exception): if the A.b field is of class B, and the B.a field is of class A, then you can define specific comparison rule in the #comparisonPredicates map, so that when comparing the B.a field, you don't cycle back into the A class. This comparison can be a non operation method, or a any comparison of you own.
      Parameters:
      clazz -
      fieldName -
      comparator -
    • clone

      protected DeepComparator clone()
      Returns a fresh comparator, that is ready to execute a new Comparison. The executedComparisons map is free. The various configuration lists are set in the clone with the exact same list as the original one. That means that added (for instance) a basic class, will add it for both the clone and the original object.
      But the executedComparisons remains specific to each instance.
      Overrides:
      clone in class Object