Best Assertj code snippet using org.assertj.core.api.recursive.comparison.RecursiveComparisonConfiguration.toComparator
Source:RecursiveComparisonConfiguration.java  
...350   * @since 3.17.0351   */352  @SuppressWarnings("unchecked")353  public <T> void registerEqualsForType(BiPredicate<? super T, ? super T> equals, Class<T> type) {354    registerComparatorForType(toComparator(equals), type);355  }356  /**357   * Registers the given {@link Comparator} to compare the fields at the given locations.358   * <p>359   * The fields must be specified from the root object, for example if {@code Foo} has a {@code Bar} field and both have an {@code id} field,360   * one can register a comparator for Foo and Bar's {@code id} by calling:361   * <pre><code class='java'> registerComparatorForFields(idComparator, "foo.id", "foo.bar.id")</code></pre>362   * <p>363   * Comparators registered with this method have precedence over comparators registered with {@link #registerComparatorForType(Comparator, Class)}.364   * <p>365   * Note that registering a {@link Comparator} for a given field will override the previously registered BiPredicate/Comparator (if any).366   * <p>367   * See {@link RecursiveComparisonAssert#withComparatorForFields(Comparator, String...) RecursiveComparisonAssert#withComparatorForFields(Comparator, String...)} for examples.368   *369   * @param comparator the {@link java.util.Comparator Comparator} to use to compare the given field370   * @param fieldLocations the locations from the root object of the fields the comparator should be used for371   * @throws NullPointerException if the given comparator is null.372   */373  public void registerComparatorForFields(Comparator<?> comparator, String... fieldLocations) {374    requireNonNull(comparator, "Expecting a non null Comparator");375    Stream.of(fieldLocations).forEach(fieldLocation -> fieldComparators.registerComparator(fieldLocation, comparator));376  }377  /**378   * Registers the given {@link BiPredicate} to compare the fields at the given locations.379   * <p>380   * The fields must be specified from the root object, for example if {@code Foo} has a {@code Bar} field and both have an {@code id} field,381   * one can register a BiPredicate for Foo and Bar's {@code id} by calling:382   * <pre><code class='java'> registerEqualsForFields(idBiPredicate, "foo.id", "foo.bar.id")</code></pre>383   * <p>384   * BiPredicates registered with this method have precedence over the ones registered with {@link #registerEqualsForType(BiPredicate, Class)}385   * or the comparators registered with {@link #registerComparatorForType(Comparator, Class)}.386   * <p>387   * Note that registering a {@link BiPredicate} for a given field will override the previously registered BiPredicate/Comparator (if any).388   * <p>389   * See {@link RecursiveComparisonAssert#withEqualsForFields(BiPredicate, String...) RecursiveComparisonAssert#withEqualsForFields(BiPredicate, String...)} for examples.390   *391   * @param equals the equals implementation to compare the given fields.392   * @param fieldLocations the locations from the root object of the fields the comparator should be used for393   * @throws NullPointerException if the given BiPredicate is null.394   * @since 3.17.0395   */396  public void registerEqualsForFields(BiPredicate<?, ?> equals, String... fieldLocations) {397    registerComparatorForFields(toComparator(equals), fieldLocations);398  }399  /**400   * Sets whether the recursive comparison will check that actual's type is compatible with expected's type (the same applies for each field).401   * Compatible means that the expected's type is the same or a subclass of actual's type.402   * <p>403   * See {@link RecursiveComparisonAssert#withStrictTypeChecking()} for code examples.404   *405   * @param strictTypeChecking whether the recursive comparison will check that actual's type is compatible with expected's type.406   */407  public void strictTypeChecking(boolean strictTypeChecking) {408    this.strictTypeChecking = strictTypeChecking;409  }410  public boolean isInStrictTypeCheckingMode() {411    return strictTypeChecking;412  }413  public List<Pattern> getIgnoredFieldsRegexes() {414    return ignoredFieldsRegexes;415  }416  public List<Class<?>> getIgnoredOverriddenEqualsForTypes() {417    return ignoredOverriddenEqualsForTypes;418  }419  public List<String> getIgnoredOverriddenEqualsForFields() {420    return ignoredOverriddenEqualsForFields;421  }422  public List<Pattern> getIgnoredOverriddenEqualsForFieldsMatchingRegexes() {423    return ignoredOverriddenEqualsForFieldsMatchingRegexes;424  }425  public Stream<Entry<String, Comparator<?>>> comparatorByFields() {426    return fieldComparators.comparatorByFields();427  }428  @Override429  public String toString() {430    return multiLineDescription(CONFIGURATION_PROVIDER.representation());431  }432  @Override433  public int hashCode() {434    return java.util.Objects.hash(fieldComparators, ignoreAllActualEmptyOptionalFields, ignoreAllActualNullFields,435                                  ignoreAllExpectedNullFields, ignoreAllOverriddenEquals, ignoreCollectionOrder,436                                  ignoredCollectionOrderInFields, ignoredCollectionOrderInFieldsMatchingRegexes, ignoredFields,437                                  ignoredFieldsRegexes, ignoredOverriddenEqualsForFields, ignoredOverriddenEqualsForTypes,438                                  ignoredOverriddenEqualsForFieldsMatchingRegexes, ignoredTypes, strictTypeChecking,439                                  typeComparators);440  }441  @Override442  public boolean equals(Object obj) {443    if (this == obj) return true;444    if (obj == null) return false;445    if (getClass() != obj.getClass()) return false;446    RecursiveComparisonConfiguration other = (RecursiveComparisonConfiguration) obj;447    return java.util.Objects.equals(fieldComparators, other.fieldComparators)448           && ignoreAllActualEmptyOptionalFields == other.ignoreAllActualEmptyOptionalFields449           && ignoreAllActualNullFields == other.ignoreAllActualNullFields450           && ignoreAllExpectedNullFields == other.ignoreAllExpectedNullFields451           && ignoreAllOverriddenEquals == other.ignoreAllOverriddenEquals452           && ignoreCollectionOrder == other.ignoreCollectionOrder453           && java.util.Objects.equals(ignoredCollectionOrderInFields, other.ignoredCollectionOrderInFields)454           && java.util.Objects.equals(ignoredFields, other.ignoredFields)455           && java.util.Objects.equals(ignoredFieldsRegexes, other.ignoredFieldsRegexes)456           && java.util.Objects.equals(ignoredOverriddenEqualsForFields, other.ignoredOverriddenEqualsForFields)457           && java.util.Objects.equals(ignoredOverriddenEqualsForTypes, other.ignoredOverriddenEqualsForTypes)458           && java.util.Objects.equals(ignoredOverriddenEqualsForFieldsMatchingRegexes,459                                       other.ignoredOverriddenEqualsForFieldsMatchingRegexes)460           && java.util.Objects.equals(ignoredTypes, other.ignoredTypes) && strictTypeChecking == other.strictTypeChecking461           && java.util.Objects.equals(typeComparators, other.typeComparators)462           && java.util.Objects.equals(ignoredCollectionOrderInFieldsMatchingRegexes,463                                       other.ignoredCollectionOrderInFieldsMatchingRegexes);464  }465  public String multiLineDescription(Representation representation) {466    StringBuilder description = new StringBuilder();467    describeIgnoreAllActualNullFields(description);468    describeIgnoreAllActualEmptyOptionalFields(description);469    describeIgnoreAllExpectedNullFields(description);470    describeIgnoredFields(description);471    describeIgnoredFieldsRegexes(description);472    describeIgnoredFieldsForTypes(description);473    describeOverriddenEqualsMethodsUsage(description, representation);474    describeIgnoreCollectionOrder(description);475    describeIgnoredCollectionOrderInFields(description);476    describeIgnoredCollectionOrderInFieldsMatchingRegexes(description);477    describeRegisteredComparatorByTypes(description);478    describeRegisteredComparatorForFields(description);479    describeTypeCheckingStrictness(description);480    return description.toString();481  }482  boolean shouldIgnore(DualValue dualValue) {483    FieldLocation fieldLocation = dualValue.fieldLocation;484    return matchesAnIgnoredField(fieldLocation)485           || matchesAnIgnoredFieldRegex(fieldLocation)486           || shouldIgnoreFieldBasedOnFieldValue(dualValue);487  }488  Set<String> getNonIgnoredActualFieldNames(DualValue dualValue) {489    Set<String> actualFieldsNames = Objects.getFieldsNames(dualValue.actual.getClass());490    // we are doing the same as shouldIgnore(DualValue dualValue) but in two steps for performance reasons:491    // - we filter first ignored field by names that don't need building DualValues492    // - then we filter field DualValues with the remaining criteria that need to get the field value493    // DualValues are built introspecting fields which is expensive.494    return actualFieldsNames.stream()495                            // evaluate field name ignoring criteria on dualValue field location + field name496                            .filter(fieldName -> !shouldIgnoreFieldBasedOnFieldLocation(dualValue.fieldLocation.field(fieldName)))497                            .map(fieldName -> dualValueForField(dualValue, fieldName))498                            // evaluate field value ignoring criteria499                            .filter(fieldDualValue -> !shouldIgnoreFieldBasedOnFieldValue(fieldDualValue))500                            // back to field name501                            .map(DualValue::getFieldName)502                            .filter(fieldName -> !fieldName.isEmpty())503                            .collect(toSet());504  }505  // non accessible stuff506  private boolean shouldIgnoreFieldBasedOnFieldValue(DualValue dualValue) {507    return matchesAnIgnoredNullField(dualValue)508           || matchesAnIgnoredFieldType(dualValue)509           || matchesAnIgnoredEmptyOptionalField(dualValue);510  }511  private boolean shouldIgnoreFieldBasedOnFieldLocation(FieldLocation fieldLocation) {512    return matchesAnIgnoredField(fieldLocation) || matchesAnIgnoredFieldRegex(fieldLocation);513  }514  private static DualValue dualValueForField(DualValue parentDualValue, String fieldName) {515    Object actualFieldValue = COMPARISON.getSimpleValue(fieldName, parentDualValue.actual);516    // no guarantees we have a field in expected named as fieldName517    Object expectedFieldValue;518    try {519      expectedFieldValue = COMPARISON.getSimpleValue(fieldName, parentDualValue.expected);520    } catch (@SuppressWarnings("unused") Exception e) {521      // set the field to null to express it is absent, this not 100% accurate as the value could be null522      // but it works to evaluate if dualValue should be ignored with matchesAnIgnoredFieldType523      expectedFieldValue = null;524    }525    FieldLocation fieldLocation = parentDualValue.fieldLocation.field(fieldName);526    return new DualValue(fieldLocation, actualFieldValue, expectedFieldValue);527  }528  boolean hasCustomComparator(DualValue dualValue) {529    String fieldName = dualValue.getConcatenatedPath();530    if (hasComparatorForField(fieldName)) return true;531    if (dualValue.actual == null && dualValue.expected == null) return false;532    // best effort assuming actual and expected have the same type (not 100% true as we can compare object of differennt types)533    Class<?> valueType = dualValue.actual != null ? dualValue.actual.getClass() : dualValue.expected.getClass();534    return hasComparatorForType(valueType);535  }536  boolean shouldIgnoreOverriddenEqualsOf(DualValue dualValue) {537    // we must compare java basic types otherwise the recursive comparison loops infinitely!538    if (dualValue.isActualJavaType()) return false;539    // enums don't have fields, comparing them field by field has no sense, we need to use equals which is overridden and final540    if (dualValue.isActualAnEnum()) return false;541    return ignoreAllOverriddenEquals542           || matchesAnIgnoredOverriddenEqualsField(dualValue.fieldLocation)543           || (dualValue.actual != null && shouldIgnoreOverriddenEqualsOf(dualValue.actual.getClass()));544  }545  @VisibleForTesting546  boolean shouldIgnoreOverriddenEqualsOf(Class<? extends Object> clazz) {547    return matchesAnIgnoredOverriddenEqualsRegex(clazz) || matchesAnIgnoredOverriddenEqualsType(clazz);548  }549  boolean shouldIgnoreCollectionOrder(FieldLocation fieldLocation) {550    return ignoreCollectionOrder551           || matchesAnIgnoredCollectionOrderInField(fieldLocation)552           || matchesAnIgnoredCollectionOrderInFieldRegex(fieldLocation);553  }554  private void describeIgnoredFieldsRegexes(StringBuilder description) {555    if (!ignoredFieldsRegexes.isEmpty())556      description.append(format("- the fields matching the following regexes were ignored in the comparison: %s%n",557                                describeRegexes(ignoredFieldsRegexes)));558  }559  private void describeIgnoredFields(StringBuilder description) {560    if (!ignoredFields.isEmpty())561      description.append(format("- the following fields were ignored in the comparison: %s%n", describeIgnoredFields()));562  }563  private void describeIgnoredFieldsForTypes(StringBuilder description) {564    if (!ignoredTypes.isEmpty())565      description.append(format("- the following types were ignored in the comparison: %s%n", describeIgnoredTypes()));566  }567  private void describeIgnoreAllActualNullFields(StringBuilder description) {568    if (ignoreAllActualNullFields) description.append(format("- all actual null fields were ignored in the comparison%n"));569  }570  private void describeIgnoreAllActualEmptyOptionalFields(StringBuilder description) {571    if (getIgnoreAllActualEmptyOptionalFields())572      description.append(format("- all actual empty optional fields were ignored in the comparison (including Optional, OptionalInt, OptionalLong and OptionalDouble)%n"));573  }574  private void describeIgnoreAllExpectedNullFields(StringBuilder description) {575    if (ignoreAllExpectedNullFields) description.append(format("- all expected null fields were ignored in the comparison%n"));576  }577  private void describeOverriddenEqualsMethodsUsage(StringBuilder description, Representation representation) {578    String header = ignoreAllOverriddenEquals579        ? "- no overridden equals methods were used in the comparison (except for java types)"580        : "- overridden equals methods were used in the comparison";581    description.append(header);582    if (isConfiguredToIgnoreSomeButNotAllOverriddenEqualsMethods()) {583      description.append(format(" except for:%n"));584      describeIgnoredOverriddenEqualsMethods(description, representation);585    } else {586      description.append(format("%n"));587    }588  }589  private void describeIgnoredOverriddenEqualsMethods(StringBuilder description, Representation representation) {590    if (!ignoredOverriddenEqualsForFields.isEmpty())591      description.append(format("%s the following fields: %s%n", INDENT_LEVEL_2,592                                describeIgnoredOverriddenEqualsForFields()));593    if (!ignoredOverriddenEqualsForTypes.isEmpty())594      description.append(format("%s the following types: %s%n", INDENT_LEVEL_2,595                                describeIgnoredOverriddenEqualsForTypes(representation)));596    if (!ignoredOverriddenEqualsForFieldsMatchingRegexes.isEmpty())597      description.append(format("%s the types matching the following regexes: %s%n", INDENT_LEVEL_2,598                                describeRegexes(ignoredOverriddenEqualsForFieldsMatchingRegexes)));599  }600  private String describeIgnoredOverriddenEqualsForTypes(Representation representation) {601    List<String> fieldsDescription = ignoredOverriddenEqualsForTypes.stream()602                                                                    .map(representation::toStringOf)603                                                                    .collect(toList());604    return join(fieldsDescription).with(", ");605  }606  private String describeIgnoredOverriddenEqualsForFields() {607    return join(ignoredOverriddenEqualsForFields).with(", ");608  }609  private void describeIgnoreCollectionOrder(StringBuilder description) {610    if (ignoreCollectionOrder) description.append(format("- collection order was ignored in all fields in the comparison%n"));611  }612  private void describeIgnoredCollectionOrderInFields(StringBuilder description) {613    if (!ignoredCollectionOrderInFields.isEmpty())614      description.append(format("- collection order was ignored in the following fields in the comparison: %s%n",615                                describeIgnoredCollectionOrderInFields()));616  }617  private void describeIgnoredCollectionOrderInFieldsMatchingRegexes(StringBuilder description) {618    if (!ignoredCollectionOrderInFieldsMatchingRegexes.isEmpty())619      description.append(format("- collection order was ignored in the fields matching the following regexes in the comparison: %s%n",620                                describeRegexes(ignoredCollectionOrderInFieldsMatchingRegexes)));621  }622  private boolean matchesAnIgnoredOverriddenEqualsRegex(Class<?> clazz) {623    if (ignoredOverriddenEqualsForFieldsMatchingRegexes.isEmpty()) return false; // shortcut624    String canonicalName = clazz.getCanonicalName();625    return ignoredOverriddenEqualsForFieldsMatchingRegexes.stream()626                                                          .anyMatch(regex -> regex.matcher(canonicalName).matches());627  }628  private boolean matchesAnIgnoredOverriddenEqualsType(Class<?> clazz) {629    return ignoredOverriddenEqualsForTypes.contains(clazz);630  }631  private boolean matchesAnIgnoredOverriddenEqualsField(FieldLocation fieldLocation) {632    return ignoredOverriddenEqualsForFields.stream().anyMatch(fieldLocation::matches);633  }634  private boolean matchesAnIgnoredNullField(DualValue dualValue) {635    return (ignoreAllActualNullFields && dualValue.actual == null)636           || (ignoreAllExpectedNullFields && dualValue.expected == null);637  }638  private boolean matchesAnIgnoredEmptyOptionalField(DualValue dualValue) {639    return ignoreAllActualEmptyOptionalFields640           && dualValue.isActualFieldAnEmptyOptionalOfAnyType();641  }642  private boolean matchesAnIgnoredFieldRegex(FieldLocation fieldLocation) {643    return ignoredFieldsRegexes.stream()644                               .anyMatch(regex -> regex.matcher(fieldLocation.getPathToUseInRules()).matches());645  }646  private boolean matchesAnIgnoredFieldType(DualValue dualValue) {647    Object actual = dualValue.actual;648    if (actual != null) return ignoredTypes.contains(actual.getClass());649    Object expected = dualValue.expected;650    // actual is null => we can't evaluate its type, we can only reliably check dualValue.expected's type if651    // strictTypeChecking is enabled which guarantees expected is of the same type.652    if (strictTypeChecking && expected != null) return ignoredTypes.contains(expected.getClass());653    // if strictTypeChecking is disabled, we can't safely ignore the field (if we did, we would ignore all null fields!).654    return false;655  }656  private boolean matchesAnIgnoredField(FieldLocation fieldLocation) {657    return ignoredFields.stream().anyMatch(fieldLocation::matches);658  }659  private boolean matchesAnIgnoredCollectionOrderInField(FieldLocation fieldLocation) {660    return ignoredCollectionOrderInFields.stream().anyMatch(fieldLocation::matches);661  }662  private boolean matchesAnIgnoredCollectionOrderInFieldRegex(FieldLocation fieldLocation) {663    String pathToUseInRules = fieldLocation.getPathToUseInRules();664    return ignoredCollectionOrderInFieldsMatchingRegexes.stream().anyMatch(regex -> regex.matcher(pathToUseInRules).matches());665  }666  private String describeIgnoredFields() {667    return join(ignoredFields).with(", ");668  }669  private String describeIgnoredTypes() {670    List<String> typesDescription = ignoredTypes.stream()671                                                .map(Class::getName)672                                                .collect(toList());673    return join(typesDescription).with(", ");674  }675  private String describeIgnoredCollectionOrderInFields() {676    return join(ignoredCollectionOrderInFields).with(", ");677  }678  private String describeRegexes(List<Pattern> regexes) {679    List<String> fieldsDescription = regexes.stream()680                                            .map(Pattern::pattern)681                                            .collect(toList());682    return join(fieldsDescription).with(", ");683  }684  private boolean isConfiguredToIgnoreSomeButNotAllOverriddenEqualsMethods() {685    boolean ignoreSomeOverriddenEqualsMethods = !ignoredOverriddenEqualsForFieldsMatchingRegexes.isEmpty()686                                                || !ignoredOverriddenEqualsForTypes.isEmpty()687                                                || !ignoredOverriddenEqualsForFields.isEmpty();688    return !ignoreAllOverriddenEquals && ignoreSomeOverriddenEqualsMethods;689  }690  private void describeRegisteredComparatorByTypes(StringBuilder description) {691    if (!typeComparators.isEmpty()) {692      description.append(format("- these types were compared with the following comparators:%n"));693      describeComparatorForTypes(description);694    }695  }696  private void describeComparatorForTypes(StringBuilder description) {697    typeComparators.comparatorByTypes()698                   .map(this::formatRegisteredComparatorByType)699                   .forEach(description::append);700  }701  private String formatRegisteredComparatorByType(Entry<Class<?>, Comparator<?>> next) {702    return format("%s %s -> %s%n", INDENT_LEVEL_2, next.getKey().getName(), next.getValue());703  }704  private void describeRegisteredComparatorForFields(StringBuilder description) {705    if (!fieldComparators.isEmpty()) {706      description.append(format("- these fields were compared with the following comparators:%n"));707      describeComparatorForFields(description);708      if (!typeComparators.isEmpty()) {709        description.append(format("- field comparators take precedence over type comparators.%n"));710      }711    }712  }713  private void describeComparatorForFields(StringBuilder description) {714    fieldComparators.comparatorByFields()715                    .map(this::formatRegisteredComparatorForField)716                    .forEach(description::append);717  }718  private String formatRegisteredComparatorForField(Entry<String, Comparator<?>> comparatorForField) {719    return format("%s %s -> %s%n", INDENT_LEVEL_2, comparatorForField.getKey(), comparatorForField.getValue());720  }721  private void describeTypeCheckingStrictness(StringBuilder description) {722    String str = strictTypeChecking723        ? "- actual and expected objects and their fields were considered different when of incompatible types (i.e. expected type does not extend actual's type) even if all their fields match, for example a Person instance will never match a PersonDto (call strictTypeChecking(false) to change that behavior).%n"724        : "- actual and expected objects and their fields were compared field by field recursively even if they were not of the same type, this allows for example to compare a Person to a PersonDto (call strictTypeChecking(true) to change that behavior).%n";725    description.append(format(str));726  }727  /**728   * Creates builder to build {@link RecursiveComparisonConfiguration}.729   * @return created builder730   */731  public static Builder builder() {732    return new Builder();733  }734  /**735   * Builder to build {@link RecursiveComparisonConfiguration}.736   */737  public static final class Builder {738    private boolean strictTypeChecking;739    private boolean ignoreAllActualNullFields;740    private boolean ignoreAllActualEmptyOptionalFields;741    private boolean ignoreAllExpectedNullFields;742    private String[] ignoredFields = {};743    private String[] ignoredFieldsMatchingRegexes = {};744    private Class<?>[] ignoredTypes = {};745    private Class<?>[] ignoredOverriddenEqualsForTypes = {};746    private String[] ignoredOverriddenEqualsForFields = {};747    private String[] ignoredOverriddenEqualsForFieldsMatchingRegexes = {};748    private boolean ignoreAllOverriddenEquals;749    private boolean ignoreCollectionOrder;750    private String[] ignoredCollectionOrderInFields = {};751    private String[] ignoredCollectionOrderInFieldsMatchingRegexes = {};752    private TypeComparators typeComparators = new TypeComparators();753    private FieldComparators fieldComparators = new FieldComparators();754    private Builder() {}755    /**756     * Sets whether the recursive comparison will check that actual's type is compatible with expected's type (the same applies for each field).757     * Compatible means that the expected's type is the same or a subclass of actual's type.758     * <p>759     * See {@link RecursiveComparisonAssert#withStrictTypeChecking()} for code examples.760     *761     * @param strictTypeChecking whether the recursive comparison will check that actual's type is compatible with expected's type.762     * @return this builder.763     */764    public Builder withStrictTypeChecking(boolean strictTypeChecking) {765      this.strictTypeChecking = strictTypeChecking;766      return this;767    }768    /**769     * Sets whether actual null fields are ignored in the recursive comparison.770     * <p>771     * See {@link RecursiveComparisonAssert#ignoringActualNullFields()} for code examples.772     *773     * @param ignoreAllActualNullFields whether to ignore actual null fields in the recursive comparison774     * @return this builder.775     */776    public Builder withIgnoreAllActualNullFields(boolean ignoreAllActualNullFields) {777      this.ignoreAllActualNullFields = ignoreAllActualNullFields;778      return this;779    }780    /**781     * Sets whether actual empty optional fields are ignored in the recursive comparison.782     * <p>783     * See {@link RecursiveComparisonAssert#ignoringActualEmptyOptionalFields()} for code examples.784     *785     * @param ignoreAllActualEmptyOptionalFields whether to ignore actual empty optional fields in the recursive comparison786     * @return this builder.787     */788    public Builder withIgnoreAllActualEmptyOptionalFields(boolean ignoreAllActualEmptyOptionalFields) {789      this.ignoreAllActualEmptyOptionalFields = ignoreAllActualEmptyOptionalFields;790      return this;791    }792    /**793     * Sets whether expected null fields are ignored in the recursive comparison.794     * <p>795     * See {@link RecursiveComparisonAssert#ignoringExpectedNullFields()} for code examples.796     *797     * @param ignoreAllExpectedNullFields whether to ignore expected null fields in the recursive comparison798     * @return this builder.799     */800    public Builder withIgnoreAllExpectedNullFields(boolean ignoreAllExpectedNullFields) {801      this.ignoreAllExpectedNullFields = ignoreAllExpectedNullFields;802      return this;803    }804    /**805     * Adds the given fields to the list of the object under test fields to ignore in the recursive comparison. Nested fields can be specified like this: home.address.street.806     * <p>807     * See {@link RecursiveComparisonAssert#ignoringFields(String...) RecursiveComparisonAssert#ignoringFields(String...)} for examples.808     *809     * @param fieldsToIgnore the fields of the object under test to ignore in the comparison.810     * @return this builder.811     */812    public Builder withIgnoredFields(String... fieldsToIgnore) {813      this.ignoredFields = fieldsToIgnore;814      return this;815    }816    /**817     * Allows to ignore in the recursive comparison the object under test fields matching the given regexes. The given regexes are added to the already registered ones.818     * <p>819     * See {@link RecursiveComparisonAssert#ignoringFieldsMatchingRegexes(String...) RecursiveComparisonAssert#ignoringFieldsMatchingRegexes(String...)} for examples.820     *821     * @param regexes regexes used to ignore fields in the comparison.822     * @return this builder.823     */824    public Builder withIgnoredFieldsMatchingRegexes(String... regexes) {825      this.ignoredFieldsMatchingRegexes = regexes;826      return this;827    }828    /**829     * Adds the given types to the list of the object under test fields types to ignore in the recursive comparison.830     * The fields are ignored if their types exactly match one of the ignored types, if a field is a subtype of an ignored type it won't be ignored.831     * <p>832     * Note that if some object under test fields are null, they are not ignored by this method as their type can't be evaluated.833     * <p>834     * See {@link RecursiveComparisonAssert#ignoringFields(String...) RecursiveComparisonAssert#ignoringFieldsOfTypes(Class...)} for examples.835     *836     * @param types the types of the object under test to ignore in the comparison.837     * @return this builder.838     */839    public Builder withIgnoredFieldsOfTypes(Class<?>... types) {840      this.ignoredTypes = types;841      return this;842    }843    /**844     * Adds the given types to the list of types to force a recursive comparison on.845     * <p>846     * See {@link RecursiveComparisonAssert#ignoringOverriddenEqualsForTypes(Class...) RecursiveComparisonAssert#ignoringOverriddenEqualsForTypes(Class...)} for examples.847     *848     * @param types the types to the list of types to force a recursive comparison on.849     * @return this builder.850     */851    public Builder withIgnoredOverriddenEqualsForTypes(Class<?>... types) {852      this.ignoredOverriddenEqualsForTypes = types;853      return this;854    }855    /**856     * Adds the given fields to the list of fields to force a recursive comparison on.857     * <p>858     * See {@link RecursiveComparisonAssert#ignoringOverriddenEqualsForFields(String...) RecursiveComparisonAssert#ignoringOverriddenEqualsForFields(String...)} for examples.859     *860     * @param fields the fields to force a recursive comparison on.861     * @return this builder.862     */863    public Builder withIgnoredOverriddenEqualsForFields(String... fields) {864      this.ignoredOverriddenEqualsForFields = fields;865      return this;866    }867    /**868     * Adds the given regexes to the list of regexes used find the fields to force a recursive comparison on.869     * <p>870     * See {@link RecursiveComparisonAssert#ignoringOverriddenEqualsForFieldsMatchingRegexes(String...) RecursiveComparisonAssert#ignoringOverriddenEqualsForFieldsMatchingRegexes(String...)} for examples.871     *872     * @param regexes regexes used to specify the fields we want to force a recursive comparison on.873     * @return this builder.874     */875    public Builder withIgnoredOverriddenEqualsForFieldsMatchingRegexes(String... regexes) {876      this.ignoredOverriddenEqualsForFieldsMatchingRegexes = regexes;877      return this;878    }879    /**880     * Force a recursive comparison on all fields (except java types) if true.881     * <p>882     * See {@link RecursiveComparisonAssert#ignoringAllOverriddenEquals()} for examples.883     *884     * @param ignoreAllOverriddenEquals whether to force a recursive comparison on all fields (except java types) or not.885     * @return this builder.886     */887    public Builder withIgnoreAllOverriddenEquals(boolean ignoreAllOverriddenEquals) {888      this.ignoreAllOverriddenEquals = ignoreAllOverriddenEquals;889      return this;890    }891    /**892     * Sets whether to ignore collection order in the comparison.893     * <p>894     * See {@link RecursiveComparisonAssert#ignoringCollectionOrder()} for code examples.895     *896     * @param ignoreCollectionOrder whether to ignore collection order in the comparison.897     * @return this builder.898     */899    public Builder withIgnoreCollectionOrder(boolean ignoreCollectionOrder) {900      this.ignoreCollectionOrder = ignoreCollectionOrder;901      return this;902    }903    /**904     * Adds the given fields to the list of the object under test fields to ignore collection order in the recursive comparison.905     * <p>906     * See {@link RecursiveComparisonAssert#ignoringCollectionOrderInFields(String...) RecursiveComparisonAssert#ignoringCollectionOrderInFields(String...)} for examples.907     *908     * @param fieldsToIgnoreCollectionOrder the fields of the object under test to ignore collection order in the comparison.909     * @return this builder.910     */911    public Builder withIgnoredCollectionOrderInFields(String... fieldsToIgnoreCollectionOrder) {912      this.ignoredCollectionOrderInFields = fieldsToIgnoreCollectionOrder;913      return this;914    }915    /**916     * Adds the given regexes to the list of regexes used to find the object under test fields to ignore collection order in the recursive comparison.917     * <p>918     * See {@link RecursiveComparisonAssert#ignoringCollectionOrderInFieldsMatchingRegexes(String...) RecursiveComparisonAssert#ignoringCollectionOrderInFieldsMatchingRegexes(String...)} for examples.919     *920     * @param regexes regexes used to find the object under test fields to ignore collection order in in the comparison.921     * @return this builder.922     */923    public Builder withIgnoredCollectionOrderInFieldsMatchingRegexes(String... regexes) {924      this.ignoredCollectionOrderInFieldsMatchingRegexes = regexes;925      return this;926    }927    /**928     * Registers the given {@link Comparator} to compare the fields with the given type.929     * <p>930     * Comparators registered with this method have less precedence than comparators registered with {@link #withComparatorForFields(Comparator, String...)}931     * or BiPredicate registered with  {@link #withEqualsForFields(BiPredicate, String...)}.932     * <p>933     * Note that registering a {@link Comparator} for a given type will override the previously registered BiPredicate/Comparator (if any).934     * <p>935     * See {@link RecursiveComparisonAssert#withComparatorForType(Comparator, Class)} for examples.936     *937     * @param <T> the class type to register a comparator for938     * @param comparator the {@link java.util.Comparator Comparator} to use to compare the given field939     * @param type the type to be compared with the given comparator.940     * @return this builder.941     * @throws NullPointerException if the given Comparator is null.942     */943    public <T> Builder withComparatorForType(Comparator<? super T> comparator, Class<T> type) {944      requireNonNull(comparator, "Expecting a non null Comparator");945      this.typeComparators.put(type, comparator);946      return this;947    }948    /**949     * Registers the given {@link BiPredicate} to compare the fields with the given type.950     * <p>951     * BiPredicates registered with this method have less precedence than the ones registered with {@link #withEqualsForFields(BiPredicate, String...)}952     * or the comparators registered with {@link #withComparatorForFields(Comparator, String...)}.953     * <p>954     * Note that registering a {@link BiPredicate} for a given type will override the previously registered BiPredicate/Comparator (if any).955     * <p>956     * See {@link RecursiveComparisonAssert#withEqualsForType(BiPredicate, Class)} for examples.957     *958     * @param <T> the class type to register a BiPredicate for959     * @param equals the {@link BiPredicate} to use to compare the given field960     * @param type the type to be compared with the given comparator.961     * @return this builder.962     * @since 3.17.0963     * @throws NullPointerException if the given BiPredicate is null.964     */965    @SuppressWarnings("unchecked")966    public <T> Builder withEqualsForType(BiPredicate<? super T, ? super T> equals, Class<T> type) {967      return withComparatorForType(toComparator(equals), type);968    }969    /**970     * Registers the given {@link Comparator} to compare the fields at the given locations.971     * <p>972     * The fields must be specified from the root object, for example if {@code Foo} has a {@code Bar} field and both have an {@code id} field,973     * one can register a comparator for Foo and Bar's {@code id} by calling:974     * <pre><code class='java'> registerComparatorForFields(idComparator, "foo.id", "foo.bar.id")</code></pre>975     * <p>976     * Comparators registered with this method have precedence over comparators registered with {@link #withComparatorForType(Comparator, Class)}977     * or BiPredicate registered with {@link #withEqualsForType(BiPredicate, Class)}.978     * <p>979     * Note that registering a {@link Comparator} for a given field will override the previously registered BiPredicate/Comparator (if any).980     * <p>981     * See {@link RecursiveComparisonAssert#withComparatorForFields(Comparator, String...) RecursiveComparisonAssert#withComparatorForFields(Comparator comparator, String...fields)} for examples.982     *983     * @param comparator the {@link java.util.Comparator Comparator} to use to compare the given field984     * @param fields the fields the comparator should be used for985     * @return this builder.986     * @throws NullPointerException if the given Comparator is null.987     */988    public Builder withComparatorForFields(Comparator<?> comparator, String... fields) {989      requireNonNull(comparator, "Expecting a non null Comparator");990      Stream.of(fields).forEach(fieldLocation -> fieldComparators.registerComparator(fieldLocation, comparator));991      return this;992    }993    /**994     * Registers the given {@link BiPredicate} to compare the fields at the given locations.995     * <p>996     * The fields must be specified from the root object, for example if {@code Foo} has a {@code Bar} field and both have an {@code id} field,997     * one can register a BiPredicate for Foo and Bar's {@code id} by calling:998     * <pre><code class='java'> withEqualsForFields(idBiPredicate, "foo.id", "foo.bar.id")</code></pre>999     * <p>1000     * BiPredicates registered with this method have precedence over the ones registered with {@link #withEqualsForType(BiPredicate, Class)}1001     * or the comparators registered with {@link #withComparatorForType(Comparator, Class)}.1002     * <p>1003     * Note that registering a {@link BiPredicate} for a given field will override the previously registered BiPredicate/Comparator (if any).1004     * <p>1005     * See {@link RecursiveComparisonAssert#withEqualsForFields(BiPredicate, String...) RecursiveComparisonAssert#withEqualsForFields(BiPredicate equals, String...fields)} for examples.1006     *1007     * @param equals the {@link BiPredicate} to use to compare the given fields1008     * @param fields the fields the BiPredicate should be used for1009     * @return this builder.1010     * @since 3.17.01011     * @throws NullPointerException if the given BiPredicate is null.1012     */1013    public Builder withEqualsForFields(BiPredicate<?, ?> equals, String... fields) {1014      return withComparatorForFields(toComparator(equals), fields);1015    }1016    public RecursiveComparisonConfiguration build() {1017      return new RecursiveComparisonConfiguration(this);1018    }1019  }1020  @SuppressWarnings({ "rawtypes", "unchecked" })1021  private static Comparator toComparator(BiPredicate equals) {1022    requireNonNull(equals, "Expecting a non null BiPredicate");1023    return (o1, o2) -> equals.test(o1, o2) ? 0 : 1;1024  }1025}...toComparator
Using AI Code Generation
1import org.assertj.core.api.recursive.comparison.RecursiveComparisonConfiguration2def config = new RecursiveComparisonConfiguration()3config.ignoreAllActualNullFields()4config.ignoreAllExpectedNullFields()5config.ignoreAllActualEmptyOptionalFields()6config.ignoreAllExpectedEmptyOptionalFields()7config.toComparator()8import org.assertj.core.api.recursive.comparison.RecursiveComparisonConfiguration9def config = new RecursiveComparisonConfiguration()10config.ignoreAllActualNullFields()11config.ignoreAllExpectedNullFields()12config.ignoreAllActualEmptyOptionalFields()13config.ignoreAllExpectedEmptyOptionalFields()14config.toComparator()15import org.assertj.core.api.recursive.comparison.RecursiveComparisonConfiguration16def config = new RecursiveComparisonConfiguration()17config.ignoreAllActualNullFields()18config.ignoreAllExpectedNullFields()19config.ignoreAllActualEmptyOptionalFields()20config.ignoreAllExpectedEmptyOptionalFields()21config.toComparator()22import org.assertj.core.api.recursive.comparison.RecursiveComparisonConfiguration23def config = new RecursiveComparisonConfiguration()24config.ignoreAllActualNullFields()25config.ignoreAllExpectedNullFields()26config.ignoreAllActualEmptyOptionalFields()27config.ignoreAllExpectedEmptyOptionalFields()28config.toComparator()29import org.assertj.core.api.recursive.comparison.RecursiveComparisonConfiguration30def config = new RecursiveComparisonConfiguration()31config.ignoreAllActualNullFields()32config.ignoreAllExpectedNullFields()33config.ignoreAllActualEmptyOptionalFields()34config.ignoreAllExpectedEmptyOptionalFields()35config.toComparator()36import org.assertj.core.api.recursive.comparison.RecursiveComparisonConfiguration37def config = new RecursiveComparisonConfiguration()38config.ignoreAllActualNullFields()39config.ignoreAllExpectedNullFields()40config.ignoreAllActualEmptyOptionalFields()41config.ignoreAllExpectedEmptyOptionalFields()42config.toComparator()43import org.assertj.core.api.recursive.comparison.RecursiveComparisonConfiguration44def config = new RecursiveComparisonConfiguration()45config.ignoreAllActualNullFields()46config.ignoreAllExpectedNullFields()47config.ignoreAllActualEmptyOptionalFields()48config.ignoreAllExpectedEmptyOptionalFields()49config.toComparator()50import org.assertj.core.api.recursive.comparison.RecursiveComparisonConfiguration51def config = new RecursiveComparisonConfiguration()52config.ignoreAllActualNullFields()53config.ignoreAllExpectedNullFields()54config.ignoreAllActualEmptyOptionalFields()55config.ignoreAllExpectedEmptyOptionalFields()56config.toComparator()57import org.assertj.core.api.recursive.comparison.RecursiveComparisonConfiguration58def config = new RecursiveComparisonConfiguration()toComparator
Using AI Code Generation
1import org.assertj.core.api.recursive.comparison.RecursiveComparisonConfiguration;2import java.util.List;3import static org.assertj.core.api.Assertions.assertThat;4import static org.assertj.core.api.recursive.comparison.RecursiveComparisonConfiguration.builder;5public class RecursiveComparisonConfigurationTest {6    public static void main(String[] args) {7        List<String> list1 = List.of("a", "b", "c");8        List<String> list2 = List.of("c", "b", "a");9        assertThat(list1).usingRecursiveComparison().isEqualTo(list2);10        RecursiveComparisonConfiguration recursiveComparisonConfiguration = builder()11                .withIgnoredFields("ignored").build();12        assertThat(list1).usingRecursiveComparison(recursiveComparisonConfiguration).isEqualTo(list2);13    }14}15at RecursiveComparisonConfigurationTest.main(RecursiveComparisonConfigurationTest.java:17)16import org.assertj.core.api.recursive.comparison.RecursiveComparisonConfiguration;17import java.util.List;18import static org.assertj.core.api.Assertions.assertThat;19import static org.assertj.core.api.recursive.comparison.RecursiveComparisonConfiguration.builder;20public class RecursiveComparisonConfigurationTest {21    public static void main(String[] args) {22        List<String> list1 = List.of("a", "b", "c");23        List<String> list2 = List.of("c", "b", "a");24        RecursiveComparisonConfiguration recursiveComparisonConfiguration = builder()25                .withIgnoredFields("ignored").build();26        assertThat(list1).usingComparatorForFields(recursiveComparisonConfiguration.toComparator(), "[]")27                .usingRecursiveComparison().isEqualTo(list2);28    }29}30import org.assertj.core.api.recursive.comparison.RecursiveComparisonConfiguration;31import java.util.List;32import static org.assertj.core.api.Assertions.assertThat;33import static org.assertj.core.api.recursive.comparison.RecursiveComparisonConfiguration.builder;34public class RecursiveComparisonConfigurationTest {35    public static void main(String[] args)toComparator
Using AI Code Generation
1import static java.util.Comparator.comparing;2import static org.assertj.core.api.Assertions.assertThat;3import static org.assertj.core.api.Assertions.within;4import static org.assertj.core.api.recursive.comparison.RecursiveComparisonConfiguration.builder;5import java.util.Date;6import org.junit.Test;7public class DateComparatorTest {8   public void givenTwoDates_whenUsingComparator_thenEqual() {9      Date date1 = new Date();10      Date date2 = new Date();11      assertThat(date1).usingComparator(comparing(Date::getTime)).isEqualTo(date2);12   }13   public void givenTwoDates_whenUsingRecursiveComparisonConfiguration_thenEqual() {14      Date date1 = new Date();15      Date date2 = new Date();16      assertThat(date1).usingRecursiveComparison()17        .ignoringAllOverriddenEquals()18        .isEqualTo(date2);19   }20   public void givenTwoDates_whenUsingRecursiveComparisonConfigurationWithComparator_thenEqual() {21      Date date1 = new Date();22      Date date2 = new Date();23      assertThat(date1).usingRecursiveComparison()24        .ignoringAllOverriddenEquals()25        .withComparatorForType(comparing(Date::getTime), Date.class)26        .isEqualTo(date2);27   }28   public void givenTwoDates_whenUsingRecursiveComparisonConfigurationWithComparatorBuilder_thenEqual() {29      Date date1 = new Date();30      Date date2 = new Date();31      assertThat(date1).usingRecursiveComparison()32        .ignoringAllOverriddenEquals()33        .withComparatorForType(builder().comparatorForType(comparing(Date::getTime), Date.class).build(), Date.class)34        .isEqualTo(date2);35   }36   public void givenTwoDates_whenUsingRecursiveComparisonConfigurationWithComparatorBuilderAndWithin_thenEqual() {37      Date date1 = new Date();38      Date date2 = new Date();39      assertThat(date1).usingRecursiveComparison()40        .ignoringAllOverriddenEquals()41        .withComparatorForType(builder().comparatorForType(comparing(Date::getTime), Date.class).build(), Date.class)42        .isEqualTo(date2, within(1L));43   }44}toComparator
Using AI Code Generation
1    RecursiveComparisonConfiguration recursiveComparisonConfiguration = new RecursiveComparisonConfiguration();2    recursiveComparisonConfiguration.setIgnoreAllActualNullFields(true);3    recursiveComparisonConfiguration.setIgnoreAllExpectedNullFields(true);4    Comparator<Human> humanComparator = recursiveComparisonConfiguration.toComparator();5    RecursiveComparisonConfiguration recursiveComparisonConfigurationWithPropertyPath = new RecursiveComparisonConfiguration();6    recursiveComparisonConfigurationWithPropertyPath.setIgnoreAllActualNullFields(true);7    recursiveComparisonConfigurationWithPropertyPath.setIgnoreAllExpectedNullFields(true);8    recursiveComparisonConfigurationWithPropertyPath.setIgnoreAllActualNullFieldsForPaths("mother", "father");9    Comparator<Human> humanComparatorWithPropertyPath = recursiveComparisonConfigurationWithPropertyPath.toComparator();10    RecursiveComparisonConfiguration recursiveComparisonConfigurationWithPropertyPath2 = new RecursiveComparisonConfiguration();11    recursiveComparisonConfigurationWithPropertyPath2.setIgnoreAllActualNullFields(true);12    recursiveComparisonConfigurationWithPropertyPath2.setIgnoreAllExpectedNullFields(true);13    recursiveComparisonConfigurationWithPropertyPath2.setIgnoreAllActualNullFieldsForPaths("mother", "father");14    recursiveComparisonConfigurationWithPropertyPath2.setIgnoreAllExpectedNullFieldsForPaths("mother", "father");15    Comparator<Human> humanComparatorWithPropertyPath2 = recursiveComparisonConfigurationWithPropertyPath2.toComparator();16    RecursiveComparisonConfiguration recursiveComparisonConfigurationWithPropertyPath3 = new RecursiveComparisonConfiguration();17    recursiveComparisonConfigurationWithPropertyPath3.setIgnoreAllActualNullFields(true);18    recursiveComparisonConfigurationWithPropertyPath3.setIgnoreAllExpectedNullFields(true);19    recursiveComparisonConfigurationWithPropertyPath3.setIgnoreAllActualNullFieldsForPaths("mother", "father");20    recursiveComparisonConfigurationWithPropertyPath3.setIgnoreAllExpectedNullFieldsForPaths("mother", "father");21    recursiveComparisonConfigurationWithPropertyPath3.setIgnoreAllActualNullFieldsForPaths("mother.name", "father.name");toComparator
Using AI Code Generation
1import static org.assertj.core.api.Assertions.*;2import static org.assertj.core.api.recursive.comparison.RecursiveComparisonConfiguration.*;3import org.assertj.core.api.recursive.comparison.*;4import org.junit.jupiter.api.Test;5import java.util.*;6class TestAssertJ {7    void test() {8        List<String> list1 = Arrays.asList("a", "b", "c");9        List<String> list2 = Arrays.asList("c", "b", "a");10        assertThat(list1).usingRecursiveComparison()11                .ignoringFields("id")12                .withComparatorForFields(new Comparator<List<String>>() {13                    public int compare(List<String> o1, List<String> o2) {14                        return o1.size() - o2.size();15                    }16                }, "list")17                .isEqualTo(list2);18    }19}20at org.junit.jupiter.api.AssertionUtils.fail(AssertionUtils.java:39)21at org.junit.jupiter.api.AssertEquals.failNotEqual(AssertEquals.java:208)22at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:163)23at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:148)24at org.junit.jupiter.api.Assertions.assertEquals(Assertions.java:109)25at TestAssertJ.test(TestAssertJ.java:24)26List<String> list1 = Arrays.asList("a", "b", "c");27List<String> list2 = Arrays.asList("c", "b", "a");28assertThat(list1).usingRecursiveComparison()29        .ignoringFields("id")30        .withComparatorForFields(new Comparator<List<String>>() {Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!
