Skip to content

Commit d7df2d7

Browse files
authored
Restore support for null-valued maps when ignoring fields (#3723)
1 parent 9cf73ca commit d7df2d7

2 files changed

Lines changed: 46 additions & 13 deletions

File tree

assertj-core/src/main/java/org/assertj/core/api/recursive/comparison/RecursiveComparisonDifferenceCalculator.java

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
import static java.util.stream.Collectors.groupingBy;
1818
import static java.util.stream.Collectors.joining;
1919
import static java.util.stream.Collectors.toList;
20-
import static java.util.stream.Collectors.toMap;
2120
import static java.util.stream.StreamSupport.stream;
2221
import static org.assertj.core.api.recursive.comparison.ComparisonDifference.rootComparisonDifference;
2322
import static org.assertj.core.api.recursive.comparison.DualValue.DEFAULT_ORDERED_COLLECTION_TYPES;
@@ -35,6 +34,7 @@
3534
import java.util.LinkedHashSet;
3635
import java.util.List;
3736
import java.util.Map;
37+
import java.util.Map.Entry;
3838
import java.util.Objects;
3939
import java.util.Optional;
4040
import java.util.Set;
@@ -46,9 +46,11 @@
4646
import java.util.concurrent.atomic.AtomicLongArray;
4747
import java.util.concurrent.atomic.AtomicReference;
4848
import java.util.concurrent.atomic.AtomicReferenceArray;
49+
import java.util.function.Function;
4950
import java.util.regex.Pattern;
51+
import java.util.stream.Collector;
52+
import java.util.stream.Collectors;
5053
import java.util.stream.Stream;
51-
5254
import org.assertj.core.internal.DeepDifference;
5355

5456
/**
@@ -575,7 +577,7 @@ private static void compareUnorderedIterables(DualValue dualValue, ComparisonSta
575577
// It may be that expectedElement matches an actual element in a different hash bucket, to account for this, we check the
576578
// other actual elements for matches. This may result in O(n^2) complexity in the worst case.
577579
if (!expectedElementMatched) {
578-
for (Map.Entry<Integer, ? extends List<?>> actualElementsEntry : actualElementsGroupedByHashCode.entrySet()) {
580+
for (Entry<Integer, ? extends List<?>> actualElementsEntry : actualElementsGroupedByHashCode.entrySet()) {
579581
// avoid checking the same bucket twice
580582
if (actualElementsEntry.getKey().equals(expectedHash)) continue;
581583
Iterator<?> actualElementsIterator = actualElementsEntry.getValue().iterator();
@@ -627,6 +629,8 @@ private static <K, V> void compareSortedMap(DualValue dualValue, ComparisonState
627629

628630
Map<?, ?> actualMap = filterIgnoredFields((Map<?, ?>) dualValue.actual, dualValue.fieldLocation,
629631
comparisonState.recursiveComparisonConfiguration);
632+
633+
@SuppressWarnings("unchecked")
630634
Map<K, V> expectedMap = (Map<K, V>) filterIgnoredFields((Map<?, ?>) dualValue.expected,
631635
dualValue.fieldLocation,
632636
comparisonState.recursiveComparisonConfiguration);
@@ -636,9 +640,9 @@ private static <K, V> void compareSortedMap(DualValue dualValue, ComparisonState
636640
// no need to inspect entries, maps are not equal as they don't have the same size
637641
return;
638642
}
639-
Iterator<Map.Entry<K, V>> expectedMapEntries = expectedMap.entrySet().iterator();
640-
for (Map.Entry<?, ?> actualEntry : actualMap.entrySet()) {
641-
Map.Entry<?, ?> expectedEntry = expectedMapEntries.next();
643+
Iterator<Entry<K, V>> expectedMapEntries = expectedMap.entrySet().iterator();
644+
for (Entry<?, ?> actualEntry : actualMap.entrySet()) {
645+
Entry<?, ?> expectedEntry = expectedMapEntries.next();
642646
// check keys are matched before comparing values as keys represents a field
643647
if (!java.util.Objects.equals(actualEntry.getKey(), expectedEntry.getKey())) {
644648
// report a missing key/field.
@@ -683,17 +687,29 @@ private static void compareUnorderedMap(DualValue dualValue, ComparisonState com
683687
}
684688

685689
private static Map<?, ?> filterIgnoredFields(Map<?, ?> map, FieldLocation fieldLocation,
686-
RecursiveComparisonConfiguration recursiveComparisonConfiguration) {
687-
Set<String> ignoredFields = recursiveComparisonConfiguration.getIgnoredFields();
688-
List<Pattern> ignoredFieldsRegexes = recursiveComparisonConfiguration.getIgnoredFieldsRegexes();
690+
RecursiveComparisonConfiguration configuration) {
691+
Set<String> ignoredFields = configuration.getIgnoredFields();
692+
List<Pattern> ignoredFieldsRegexes = configuration.getIgnoredFieldsRegexes();
689693
if (ignoredFields.isEmpty() && ignoredFieldsRegexes.isEmpty()) {
690694
return map;
691695
}
692696
return map.entrySet().stream()
693-
.filter(e -> !recursiveComparisonConfiguration.matchesAnIgnoredField(fieldLocation.field(e.getKey().toString())))
694-
.filter(e -> !recursiveComparisonConfiguration.matchesAnIgnoredFieldRegex(fieldLocation.field(e.getKey()
695-
.toString())))
696-
.collect(toMap(Map.Entry::getKey, Map.Entry::getValue));
697+
.filter(e -> !configuration.matchesAnIgnoredField(fieldLocation.field(e.getKey().toString())))
698+
.filter(e -> !configuration.matchesAnIgnoredFieldRegex(fieldLocation.field(e.getKey().toString())))
699+
.collect(toMap(Entry::getKey, Entry::getValue));
700+
}
701+
702+
// workaround for https://bugs.openjdk.org/browse/JDK-8148463
703+
private static <T, K, U> Collector<T, ?, Map<K, U>> toMap(Function<? super T, ? extends K> keyMapper,
704+
Function<? super T, ? extends U> valueMapper) {
705+
@SuppressWarnings("unchecked")
706+
U none = (U) new Object();
707+
Collector<T, ?, Map<K, U>> downstream = Collectors.toMap(keyMapper, valueMapper.andThen(v -> v == null ? none : v));
708+
Function<Map<K, U>, Map<K, U>> finisher = map -> {
709+
map.replaceAll((k, v) -> v == none ? null : v);
710+
return map;
711+
};
712+
return Collectors.collectingAndThen(downstream, finisher);
697713
}
698714

699715
private static FieldLocation keyFieldLocation(FieldLocation parentFieldLocation, Object key) {

assertj-tests/assertj-integration-tests/assertj-core-tests/src/test/java/org/assertj/tests/core/api/recursive/comparison/RecursiveComparisonAssert_isEqualTo_ignoringFields_Test.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -804,6 +804,22 @@ public void should_honor_ignored_fields_in_nested_map() {
804804
.isEqualTo(mapB);
805805
}
806806

807+
@Test
808+
void should_honor_ignored_fields_in_map_with_null_value() {
809+
// GIVEN
810+
Map<String, String> actual = new HashMap<>();
811+
actual.put("foo", "value1");
812+
actual.put("bar", null);
813+
814+
Map<String, String> expected = new HashMap<>();
815+
expected.put("foo", "value2");
816+
expected.put("bar", null);
817+
// WHEN/THEN
818+
then(actual).usingRecursiveComparison()
819+
.ignoringFields("foo")
820+
.isEqualTo(expected);
821+
}
822+
807823
static class Data {
808824
private final InnerData innerData;
809825
private final List<InnerData> innerDataList;
@@ -839,4 +855,5 @@ public String getField1() {
839855
}
840856
}
841857
}
858+
842859
}

0 commit comments

Comments
 (0)