Class RecursiveComparisonAssert<SELF extends RecursiveComparisonAssert<SELF>>

    • Method Detail

      • isEqualTo

        public SELF isEqualTo​(Object expected)
        Asserts that the object under test (actual) is equal to the given object when compared field by field recursively (including inherited fields are included in the comparison). If the comparison fails it will report all the differences found and which effective RecursiveComparisonConfiguration was used to help users understand the failure.

        This is typically useful when actual's equals was not overridden.

        The comparison is not symmetrical since it is limited to actual's fields, the algorithm gather all actual's fields and then compare them to the corresponding expected's fields. It is then possible for the expected object to have more fields than actual which is handy when comparing a base type to a subtype.

        Strict/lenient recursive comparison

        By default the objects to compare can be of different types but must have the same properties/fields. For example if object under test has a work field of type Address, the expected object to compare the object under test to must also have one but it can of a different type like AddressDto.

        It is possible to enforce strict type checking by calling withStrictTypeChecking() and make the comparison fail whenever the compared objects or their fields are not compatible.
        Compatible means that the expected object/field types are the same or a subtype of actual/field types, for example if actual is an Animal and expected a Dog, they will be compared field by field in strict type checking mode.

        Ignoring null fields in the recursive comparison

        When an object is partially populated, it can still be interesting to see if its populated values are correct against a fully populated object.

        This possible by calling ignoringActualNullFields() before isEqualTo but bear in mind that only actual null fields are ignored, said otherwise the expected object null fields are used in the comparison.

        Recursive comparison use of overridden equals methods

        By default the recursive comparison is not applied on fields whose classes have overridden the equals method, concretely it means equals is used to compare these fields instead of keeping on applying the recursive comparison. The rationale is that if a class has redefined equals then it should be used to compare instances unless having a good reason.

        It is possible though to change this behavior and force recursive comparison by calling any of these methods (but before calling isEqualTo otherwise this has no effect!):

        1. ignoringOverriddenEqualsForTypes(Class...) Any fields of these classes are compared recursively
        2. ignoringOverriddenEqualsForFields(String...) Any given fields are compared recursively
        3. ignoringOverriddenEqualsForFieldsMatchingRegexes(String...) Any fields matching one of these regexes are compared recursively
        4. ignoringAllOverriddenEquals() except for java types, all fields are compared field by field recursively.
        Recursive comparison and cycles

        The recursive comparison handles cycles.

        Comparator used in the recursive comparison

        By default floats are compared with a precision of 1.0E-6 and doubles with 1.0E-15.

        You can specify a custom comparator per (nested) fields or type with the methods below (but before calling isEqualTo otherwise this has no effect!):

        1. withComparatorForFields(Comparator, String...) for one or multiple fields
        2. withComparatorForType(Comparator, Class) for a given type

        Note that field comparators always take precedence over type comparators.

        Example

        Here is a basic example with a default RecursiveComparisonConfiguration, you can find other examples for each of the method changing the recursive comparison behavior like ignoringFields(String...).

         public class Person {
           String name;
           double height;
           Home home = new Home();
         }
        
         public class Home {
           Address address = new Address();
           Date ownedSince;
         }
        
         public static class Address {
           int number;
           String street;
         }
        
         Person sherlock = new Person("Sherlock", 1.80);
         sherlock.home.ownedSince = new Date(123);
         sherlock.home.address.street = "Baker Street";
         sherlock.home.address.number = 221;
        
         Person sherlock2 = new Person("Sherlock", 1.80);
         sherlock2.home.ownedSince = new Date(123);
         sherlock2.home.address.street = "Baker Street";
         sherlock2.home.address.number = 221;
        
         // assertion succeeds as the data of both objects are the same.
         assertThat(sherlock).usingRecursiveComparison()
                             .isEqualTo(sherlock2);
        Specified by:
        isEqualTo in interface Assert<SELF extends RecursiveComparisonAssert<SELF>,​Object>
        Overrides:
        isEqualTo in class AbstractAssert<SELF extends RecursiveComparisonAssert<SELF>,​Object>
        Parameters:
        expected - the object to compare actual to.
        Returns:
        this assertion object.
        Throws:
        AssertionError - if the actual object is null.
        AssertionError - if the actual and the given objects are not deeply equal property/field by property/field.
        IntrospectionError - if one property/field to compare can not be found.
      • ignoringActualNullFields

        public SELF ignoringActualNullFields()
        Makes the recursive comparison to ignore all actual null fields (but note that the expected object null fields are used in the comparison).

        Example:

         public class Person {
           String name;
           double height;
           Home home = new Home();
         }
        
         public class Home {
           Address address = new Address();
         }
        
         public static class Address {
           int number;
           String street;
         }
        
         Person noName = new Person(null, 1.80);
         noName.home.address.street = null;
         noName.home.address.number = 221;
        
         Person sherlock = new Person("Sherlock", 1.80);
         sherlock.home.address.street = "Baker Street";
         sherlock.home.address.number = 221;
        
         // assertion succeeds as name and home.address.street fields are ignored in the comparison
         assertThat(noName).usingRecursiveComparison()
                           .ignoringActualNullFields()
                           .isEqualTo(sherlock);
        
         // assertion fails as name and home.address.street fields are populated for sherlock but not for noName.
         assertThat(sherlock).usingRecursiveComparison()
                             .ignoringActualNullFields()
                             .isEqualTo(noName);
        Returns:
        this RecursiveComparisonAssert to chain other methods.
      • ignoringActualEmptyOptionalFields

        public SELF ignoringActualEmptyOptionalFields()
        Makes the recursive comparison to ignore all actual empty optional fields (including Optional, OptionalInt, OptionalLong and OptionalDouble), note that the expected object empty optional fields are not ignored, this only applies to actual's fields.

        Example:

         public class Person {
           String name;
           OptionalInt age;
           OptionalLong id;
           OptionalDouble height;
           Home home = new Home();
         }
        
         public class Home {
           String address;
           Optional<String> phone;
         }
        
         Person homerWithoutDetails = new Person("Homer Simpson");
         homerWithoutDetails.home.address.street = "Evergreen Terrace";
         homerWithoutDetails.home.address.number = 742;
         homerWithoutDetails.home.phone = Optional.empty();
         homerWithoutDetails.age = OptionalInt.empty();
         homerWithoutDetails.id = OptionalLong.empty();
         homerWithoutDetails.height = OptionalDouble.empty();
        
         Person homerWithDetails = new Person("Homer Simpson");
         homerWithDetails.home.address.street = "Evergreen Terrace";
         homerWithDetails.home.address.number = 742;
         homerWithDetails.home.phone = Optional.of("(939) 555-0113");
         homerWithDetails.age = OptionalInt.of(39);
         homerWithDetails.id = OptionalLong.of(123456);
         homerWithDetails.height = OptionalDouble.of(1.83);
        
         // assertion succeeds as phone is ignored in the comparison
         assertThat(homerWithoutDetails).usingRecursiveComparison()
                                        .ignoringActualEmptyOptionalFields()
                                        .isEqualTo(homerWithDetails);
        
         // assertion fails as phone, age, id and height are not ignored and are populated for homerWithDetails but not for homerWithoutDetails.
         assertThat(homerWithDetails).usingRecursiveComparison()
                                     .ignoringActualEmptyOptionalFields()
                                     .isEqualTo(homerWithoutDetails);
        Returns:
        this RecursiveComparisonAssert to chain other methods.
      • ignoringExpectedNullFields

        public SELF ignoringExpectedNullFields()
        Makes the recursive comparison to ignore all expected null fields.

        Example:

         public class Person {
           String name;
           double height;
           Home home = new Home();
         }
        
         public class Home {
           Address address = new Address();
         }
        
         public static class Address {
           int number;
           String street;
         }
        
         Person sherlock = new Person("Sherlock", 1.80);
         sherlock.home.address.street = "Baker Street";
         sherlock.home.address.number = 221;
        
         Person noName = new Person(null, 1.80);
         noName.home.address.street = null;
         noName.home.address.number = 221;
        
         // assertion succeeds as name and home.address.street fields are ignored in the comparison
         assertThat(sherlock).usingRecursiveComparison()
                             .ignoringExpectedNullFields()
                             .isEqualTo(noName);
        
         // assertion fails as name and home.address.street fields are populated for sherlock but not for noName.
         assertThat(noName).usingRecursiveComparison()
                           .ignoringExpectedNullFields()
                           .isEqualTo(sherlock);
        Returns:
        this RecursiveComparisonAssert to chain other methods.
      • ignoringFields

        public SELF ignoringFields​(String... fieldsToIgnore)
        Makes the recursive comparison to ignore the given object under test fields. Nested fields can be specified like this: home.address.street.

        Example:

         public class Person {
           String name;
           double height;
           Home home = new Home();
         }
        
         public class Home {
           Address address = new Address();
         }
        
         public static class Address {
           int number;
           String street;
         }
        
         Person sherlock = new Person("Sherlock", 1.80);
         sherlock.home.address.street = "Baker Street";
         sherlock.home.address.number = 221;
        
         Person noName = new Person(null, 1.80);
         noName.home.address.street = null;
         noName.home.address.number = 221;
        
         // assertion succeeds as name and home.address.street fields are ignored in the comparison
         assertThat(sherlock).usingRecursiveComparison()
                             .ignoringFields("name", "home.address.street")
                             .isEqualTo(noName);
        
         // assertion fails as home.address.street fields differ and is not ignored.
         assertThat(sherlock).usingRecursiveComparison()
                             .ignoringFields("name")
                             .isEqualTo(noName);
        Parameters:
        fieldsToIgnore - the fields of the object under test to ignore in the comparison.
        Returns:
        this RecursiveComparisonAssert to chain other methods.
      • ignoringFieldsMatchingRegexes

        public SELF ignoringFieldsMatchingRegexes​(String... regexes)
        Makes the recursive comparison to ignore the object under test fields matching the given regexes.

        Nested fields can be specified by using dots like this: home\.address\.street (\ is used to escape dots since they have a special meaning in regexes).

        Example:

         public class Person {
           String name;
           double height;
           Home home = new Home();
         }
        
         public class Home {
           Address address = new Address();
         }
        
         public static class Address {
           int number;
           String street;
         }
        
         Person sherlock = new Person("Sherlock", 1.80);
         sherlock.home.address.street = "Baker Street";
         sherlock.home.address.number = 221;
        
         Person noName = new Person(null, 1.80);
         noName.home.address.street = "Butcher Street";
         noName.home.address.number = 222;
        
         // assertion succeeds as name and all home fields are ignored in the comparison
         assertThat(sherlock).usingRecursiveComparison()
                             .ignoringFieldsMatchingRegexes("n.me", "home.*")
                             .isEqualTo(noName);
        
         // although home fields are ignored, assertion fails as name fields differ.
         assertThat(sherlock).usingRecursiveComparison()
                             .ignoringFieldsMatchingRegexes("home.*")
                             .isEqualTo(noName);
        Parameters:
        regexes - regexes used to ignore fields in the comparison.
        Returns:
        this RecursiveComparisonAssert to chain other methods.
      • ignoringFieldsOfTypes

        public RecursiveComparisonAssert<?> ignoringFieldsOfTypes​(Class<?>... typesToIgnore)
        Makes the recursive comparison to ignore the object under test fields of the given types. The fields are ignored if their types exactly match one of the ignored types, for example if a field is a subtype of an ignored type it is not ignored.

        If some object under test fields are null it is not possible to evaluate their types unless in strictTypeChecking mode, in that case the corresponding expected field's type is evaluated instead but if strictTypeChecking mode is disabled then null fields are not ignored.

        Example:

         public class Person {
           String name;
           double height;
           Home home = new Home();
         }
        
         public class Home {
           Address address = new Address();
         }
        
         public static class Address {
           int number;
           String street;
         }
        
         Person sherlock = new Person("Sherlock", 1.80);
         sherlock.home.address.street = "Baker Street";
         sherlock.home.address.number = 221;
        
         Person sherlock2 = new Person("Sherlock", 1.90);
         sherlock2.home.address.street = "Butcher Street";
         sherlock2.home.address.number = 221;
        
         // assertion succeeds as we ignore Address and height
         assertThat(sherlock).usingRecursiveComparison()
                             .ignoringFieldsOfTypes(double.class, Address.class)
                             .isEqualTo(sherlock2);
        
         // now this assertion fails as expected since the home.address.street fields and height differ
         assertThat(sherlock).usingRecursiveComparison()
                             .isEqualTo(sherlock2);
        Parameters:
        typesToIgnore - the types we want to ignore in the object under test fields.
        Returns:
        this RecursiveComparisonAssert to chain other methods.
      • ignoringAllOverriddenEquals

        public SELF ignoringAllOverriddenEquals()
        By default the recursive comparison uses overridden equals methods to compare fields, this method allows to compare recursively all fields except fields with java types (at some point we need to compare something!).

        For the recursive comparison to use the overridden equals of a given type anyway (like Date) you can register a type comparator using withComparatorForType(Comparator, Class).

        Example:

         public class Person {
           String name;
           double height;
           Home home = new Home();
         }
        
         public class Home {
           Address address = new Address();
         }
        
         public static class Address {
           int number;
           String street;
        
           // only compares number, ouch!
           @Override
           public boolean equals(final Object other) {
             if (!(other instanceof Address)) return false;
             Address castOther = (Address) other;
             return Objects.equals(number, castOther.number);
           }
         }
        
         Person sherlock = new Person("Sherlock", 1.80);
         sherlock.home.address.street = "Baker Street";
         sherlock.home.address.number = 221;
        
         Person sherlock2 = new Person("Sherlock", 1.80);
         sherlock2.home.address.street = "Butcher Street";
         sherlock2.home.address.number = 221;
        
         // assertion succeeds but that's not what we expected since the home.address.street fields differ
         // but the equals implementation in Address does not compare them.
         assertThat(sherlock).usingRecursiveComparison()
                             .isEqualTo(sherlock2);
        
         // to avoid the previous issue, we force a recursive comparison on the home.address field
         // now this assertion fails as we expect since the home.address.street fields differ
         assertThat(sherlock).usingRecursiveComparison()
                             .ignoringAllOverriddenEquals()
                             .isEqualTo(sherlock2);
        Returns:
        this RecursiveComparisonAssert to chain other methods.
      • ignoringOverriddenEqualsForFields

        public SELF ignoringOverriddenEqualsForFields​(String... fields)
        By default the recursive comparison uses overridden equals methods to compare fields, this method allows to force a recursive comparison for the given fields (it adds them to the already registered ones).

        Nested fields can be specified by using dots like this: home.address.street

        Example:

         public class Person {
           String name;
           double height;
           Home home = new Home();
         }
        
         public class Home {
           Address address = new Address();
         }
        
         public static class Address {
           int number;
           String street;
        
           // only compares number, ouch!
           @Override
           public boolean equals(final Object other) {
             if (!(other instanceof Address)) return false;
             Address castOther = (Address) other;
             return Objects.equals(number, castOther.number);
           }
         }
        
         Person sherlock = new Person("Sherlock", 1.80);
         sherlock.home.address.street = "Baker Street";
         sherlock.home.address.number = 221;
        
         Person sherlock2 = new Person("Sherlock", 1.80);
         sherlock2.home.address.street = "Butcher Street";
         sherlock2.home.address.number = 221;
        
         // assertion succeeds but that's not what we expected since the home.address.street fields differ
         // but the equals implementation in Address does not compare them.
         assertThat(sherlock).usingRecursiveComparison()
                             .isEqualTo(sherlock2);
        
         // to avoid the previous issue, we force a recursive comparison on the home.address field
         // now this assertion fails as we expect since the home.address.street fields differ
         assertThat(sherlock).usingRecursiveComparison()
                             .ignoringOverriddenEqualsForFields("home.address")
                             .isEqualTo(sherlock2);
        Parameters:
        fields - the fields we want to force a recursive comparison on.
        Returns:
        this RecursiveComparisonAssert to chain other methods.
      • ignoringOverriddenEqualsForTypes

        public SELF ignoringOverriddenEqualsForTypes​(Class<?>... types)
        By default the recursive comparison uses overridden equals methods to compare fields, this method allows to force a recursive comparison for all fields of the given types (it adds them to the already registered ones).

        Example:

         public class Person {
           String name;
           double height;
           Home home = new Home();
         }
        
         public class Home {
           Address address = new Address();
         }
        
         public static class Address {
           int number;
           String street;
        
           // only compares number, ouch!
           @Override
           public boolean equals(final Object other) {
             if (!(other instanceof Address)) return false;
             Address castOther = (Address) other;
             return Objects.equals(number, castOther.number);
           }
         }
        
         Person sherlock = new Person("Sherlock", 1.80);
         sherlock.home.address.street = "Baker Street";
         sherlock.home.address.number = 221;
        
         Person sherlock2 = new Person("Sherlock", 1.80);
         sherlock2.home.address.street = "Butcher Street";
         sherlock2.home.address.number = 221;
        
         // assertion succeeds but that's not what we expected since the home.address.street fields differ
         // but the equals implementation in Address does not compare them.
         assertThat(sherlock).usingRecursiveComparison()
                             .isEqualTo(sherlock2);
        
         // to avoid the previous issue, we force a recursive comparison on the Address type
         // now this assertion fails as we expect since the home.address.street fields differ
         assertThat(sherlock).usingRecursiveComparison()
                             .ignoringOverriddenEqualsForTypes(Address.class)
                             .isEqualTo(sherlock2);
        Parameters:
        types - the types we want to force a recursive comparison on.
        Returns:
        this RecursiveComparisonAssert to chain other methods.
      • ignoringOverriddenEqualsForFieldsMatchingRegexes

        public SELF ignoringOverriddenEqualsForFieldsMatchingRegexes​(String... regexes)
        By default the recursive comparison uses overridden equals methods to compare fields, this method allows to force a recursive comparison for the fields matching the given regexes (it adds them to the already registered ones).

        Nested fields can be specified by using dots like: home\.address\.street (\ is used to escape dots since they have a special meaning in regexes).

        Example:

         public class Person {
           String name;
           double height;
           Home home = new Home();
         }
        
         public class Home {
           Address address = new Address();
         }
        
         public static class Address {
           int number;
           String street;
        
           // only compares number, ouch!
           @Override
           public boolean equals(final Object other) {
             if (!(other instanceof Address)) return false;
             Address castOther = (Address) other;
             return Objects.equals(number, castOther.number);
           }
         }
        
         Person sherlock = new Person("Sherlock", 1.80);
         sherlock.home.address.street = "Baker Street";
         sherlock.home.address.number = 221;
        
         Person sherlock2 = new Person("Sherlock", 1.80);
         sherlock2.home.address.street = "Butcher Street";
         sherlock2.home.address.number = 221;
        
         // assertion succeeds but that's not what we expected since the home.address.street fields differ
         // but the equals implementation in Address does not compare them.
         assertThat(sherlock).usingRecursiveComparison()
                             .isEqualTo(sherlock2);
        
         // to avoid the previous issue, we force a recursive comparison on home and its fields
         // now this assertion fails as we expect since the home.address.street fields differ
         assertThat(sherlock).usingRecursiveComparison()
                             .ignoringOverriddenEqualsForFieldsMatchingRegexes("home.*")
                             .isEqualTo(sherlock2);
        Parameters:
        regexes - regexes used to specify the fields we want to force a recursive comparison on.
        Returns:
        this RecursiveComparisonAssert to chain other methods.
      • ignoringCollectionOrder

        public SELF ignoringCollectionOrder()
        Makes the recursive comparison to ignore collection order in all fields in the object under test.

        Example:

         public class Person {
           String name;
           List<Person> friends = new ArrayList<>();
         }
        
         Person sherlock1 = new Person("Sherlock Holmes");
         sherlock1.friends.add(new Person("Dr. John Watson"));
         sherlock1.friends.add(new Person("Molly Hooper"));
        
         Person sherlock2 = new Person("Sherlock Holmes");
         sherlock2.friends.add(new Person("Molly Hooper"));
         sherlock2.friends.add(new Person("Dr. John Watson"));
        
         // assertion succeeds as all fields collection order is ignored in the comparison
         assertThat(sherlock1).usingRecursiveComparison()
                              .ignoringCollectionOrder()
                              .isEqualTo(sherlock2);
        
         // assertion fails as fields collection order is not ignored in the comparison
         assertThat(sherlock1).usingRecursiveComparison()
                              .isEqualTo(sherlock2);
        Returns:
        this RecursiveComparisonAssert to chain other methods.
      • ignoringCollectionOrderInFields

        public SELF ignoringCollectionOrderInFields​(String... fieldsToIgnoreCollectionOrder)
        Makes the recursive comparison to ignore collection order in the object under test specified fields. Nested fields can be specified like this: home.address.street.

        Example:

         public class Person {
           String name;
           List<Person> friends = new ArrayList<>();
           List<Person> enemies = new ArrayList<>();
         }
        
         Person sherlock1 = new Person("Sherlock Holmes");
         sherlock1.friends.add(new Person("Dr. John Watson"));
         sherlock1.friends.add(new Person("Molly Hooper"));
         sherlock1.enemies.add(new Person("Jim Moriarty"));
         sherlock1.enemies.add(new Person("Irene Adler"));
        
         Person sherlock2 = new Person("Sherlock Holmes");
         sherlock2.friends.add(new Person("Molly Hooper"));
         sherlock2.friends.add(new Person("Dr. John Watson"));
         sherlock2.enemies.add(new Person("Irene Adler"));
         sherlock2.enemies.add(new Person("Jim Moriarty"));
        
         // assertion succeeds as friends and enemies fields collection order is ignored in the comparison
         assertThat(sherlock1).usingRecursiveComparison()
                              .ignoringCollectionOrderInFields("friends", "enemies")
                              .isEqualTo(sherlock2);
        
         // assertion fails as enemies field collection order differ and it is not ignored
         assertThat(sherlock1).usingRecursiveComparison()
                              .ignoringCollectionOrderInFields("friends")
                              .isEqualTo(sherlock2);
        Parameters:
        fieldsToIgnoreCollectionOrder - the fields of the object under test to ignore collection order in the comparison.
        Returns:
        this RecursiveComparisonAssert to chain other methods.
      • ignoringCollectionOrderInFieldsMatchingRegexes

        public SELF ignoringCollectionOrderInFieldsMatchingRegexes​(String... regexes)
        Makes the recursive comparison to ignore collection order in the object under test fields matching the specified regexes.

        Nested fields can be specified by using dots like this: home\.address\.street (\ is used to escape dots since they have a special meaning in regexes).

        Example:

         public class Person {
           String name;
           List<Person> friends = new ArrayList<>();
           List<Person> enemies = new ArrayList<>();
         }
        
         Person sherlock1 = new Person("Sherlock Holmes");
         sherlock1.friends.add(new Person("Dr. John Watson"));
         sherlock1.friends.add(new Person("Molly Hooper"));
         sherlock1.enemies.add(new Person("Jim Moriarty"));
         sherlock1.enemies.add(new Person("Irene Adler"));
        
         Person sherlock2 = new Person("Sherlock Holmes");
         sherlock2.friends.add(new Person("Molly Hooper"));
         sherlock2.friends.add(new Person("Dr. John Watson"));
         sherlock2.enemies.add(new Person("Irene Adler"));
         sherlock2.enemies.add(new Person("Jim Moriarty"));
        
         // assertion succeeds as friends and enemies fields collection order is ignored in the comparison
         assertThat(sherlock1).usingRecursiveComparison()
                              .ignoringCollectionOrderInFieldsMatchingRegexes("friend.", "enemie.")
                              .isEqualTo(sherlock2);
        
         // assertion fails as enemies field collection order differ and it is not ignored
         assertThat(sherlock1).usingRecursiveComparison()
                              .ignoringCollectionOrderInFields("friend.")
                              .isEqualTo(sherlock2);
        Parameters:
        regexes - regexes used to find the object under test fields to ignore collection order in the comparison.
        Returns:
        this RecursiveComparisonAssert to chain other methods.
      • withStrictTypeChecking

        public SELF withStrictTypeChecking()
        Makes the recursive comparison to check that actual's type is compatible with expected's type (and do the same for each field).
        Compatible means that the expected's type is the same or a subclass of actual's type.

        Examples:

         public class Person {
           String name;
           double height;
           Person bestFriend;
         }
        
         Person sherlock = new Person("Sherlock", 1.80);
         sherlock.bestFriend = new Person("Watson", 1.70);
        
         Person sherlockClone = new Person("Sherlock", 1.80);
         sherlockClone.bestFriend = new Person("Watson", 1.70);
        
         // assertion succeeds as sherlock and sherlockClone have the same data and types
         assertThat(sherlock).usingRecursiveComparison()
                             .withStrictTypeChecking()
                             .isEqualTo(sherlockClone);
        
         // Let's now define a data structure similar to Person
        
         public class PersonDTO {
           String name;
           double height;
           PersonDTO bestFriend;
         }
        
         PersonDTO sherlockDto = new PersonDTO("Sherlock", 1.80);
         sherlockDto.bestFriend = new PersonDTO("Watson", 1.70);
        
         // assertion fails as Person and PersonDTO are not compatible even though they have the same data
         assertThat(sherlock).usingRecursiveComparison()
                             .withStrictTypeChecking()
                             .isEqualTo(noName);
        
         // Let's define a subclass of Person
        
         public class Detective extends Person {
           boolean busy;
         }
        
         Detective detectiveSherlock = new Detective("Sherlock", 1.80);
         detectiveSherlock.bestFriend = new Person("Watson", 1.70);
         detectiveSherlock.busy = true;
        
         // assertion succeeds as Detective inherits from Person and
         // only Person's fields are included into the comparison.
         assertThat(sherlock).usingRecursiveComparison()
                             .withStrictTypeChecking()
                             .isEqualTo(detectiveSherlock);
        Returns:
        this RecursiveComparisonAssert to chain other methods.
      • withComparatorForFields

        public SELF withComparatorForFields​(Comparator<?> comparator,
                                            String... fieldLocations)
        Allows to register a specific comparator to compare fields with the given locations. A typical usage is for comparing double/float fields with a given precision.

        Comparators specified by this method have precedence over comparators added with withComparatorForType(Comparator, Class).

        The field locations must be specified from the root object, for example if Foo has a Bar field which has an id, one can register to a comparator for Bar's id by calling:

         withComparatorForField("bar.id", idComparator)

        Complete example:

         public class TolkienCharacter {
           String name;
           double height;
         }
        
         TolkienCharacter frodo = new TolkienCharacter("Frodo", 1.2);
         TolkienCharacter tallerFrodo = new TolkienCharacter("Frodo", 1.3);
         TolkienCharacter reallyTallFrodo = new TolkienCharacter("Frodo", 1.9);
        
         Comparator<Double> closeEnough = (d1, d2) -> Math.abs(d1 - d2) <= 0.5 ? 0 : 1;
        
         // assertions succeed
         assertThat(frodo).usingRecursiveComparison()
                          .withComparatorForFields(closeEnough, "height")
                          .isEqualTo(tallerFrodo);
        
         // assertion fails
         assertThat(frodo).usingRecursiveComparison()
                          .withComparatorForFields(closeEnough, "height")
                          .isEqualTo(reallyTallFrodo);
        Parameters:
        comparator - the Comparator to use to compare the given fields
        fieldLocations - the location from the root object of the fields the comparator should be used for
        Returns:
        this RecursiveComparisonAssert to chain other methods.
      • withComparatorForType

        public <T> SELF withComparatorForType​(Comparator<? super T> comparator,
                                              Class<T> type)
        Allows to register a specific comparator to compare the fields with the given type. A typical usage is for comparing double/float fields with a given precision.

        Comparators specified by this method have less precedence than comparators added with withComparatorForFields(Comparator, String...).

        Example:

         public class TolkienCharacter {
           String name;
           double height;
         }
        
         TolkienCharacter frodo = new TolkienCharacter("Frodo", 1.2);
         TolkienCharacter tallerFrodo = new TolkienCharacter("Frodo", 1.3);
         TolkienCharacter reallyTallFrodo = new TolkienCharacter("Frodo", 1.9);
        
         Comparator<Double> closeEnough = (d1, d2) -> Math.abs(d1 - d2) <= 0.5 ? 0 : 1;
        
         // assertions succeed
         assertThat(frodo).usingRecursiveComparison()
                          .withComparatorForType(closeEnough, Double.class)
                          .isEqualTo(tallerFrodo);
        
         // assertion fails
         assertThat(frodo).usingRecursiveComparison()
                          .withComparatorForType(closeEnough, Double.class)
                          .isEqualTo(reallyTallFrodo);
        Type Parameters:
        T - the class type to register a comparator for
        Parameters:
        comparator - the Comparator to use to compare the given fields
        type - the type to be compared with the given comparator.
        Returns:
        this RecursiveComparisonAssert to chain other methods.