diff --git a/generator/Generator.sc b/generator/Generator.sc index 5f42a1ad4..fc0441cfb 100644 --- a/generator/Generator.sc +++ b/generator/Generator.sc @@ -2236,7 +2236,7 @@ def generateMainClasses(): Unit = { @Override public int hashCode() { - return ${if (i == 0) "1" else if (i == 1) "Objects.hashCode(_1)" else s"""Objects.hash(${(1 to i).gen(j => s"_$j")(", ")})"""}; + return ${if (i == 0) "1" else if (i == 1) "Objects.hashCode(_1)" else if (i == 2) "Objects.hashCode(_1) ^ Objects.hashCode(_2)" else s"""Objects.hash(${(1 to i).gen(j => s"_$j")(", ")})"""}; } @Override @@ -3715,7 +3715,7 @@ def generateTestClasses(): Unit = { @$test public void shouldComputeCorrectHashCode() { final int actual = createTuple().hashCode(); - final int expected = ${im.getType("java.util.Objects")}.${if (i == 1) "hashCode" else "hash"}($nullArgs); + final int expected = ${if (i == 2) s"new ${im.getType("java.util.AbstractMap.SimpleEntry")}<>($nullArgs)" else im.getType("java.util.Objects")}.${if (i == 2) "hashCode()" else if (i == 1) s"hashCode($nullArgs)" else s"hash($nullArgs)"}; $assertThat(actual).isEqualTo(expected); } diff --git a/src-gen/main/java/io/vavr/Tuple2.java b/src-gen/main/java/io/vavr/Tuple2.java index 8258f6a52..314673b78 100644 --- a/src-gen/main/java/io/vavr/Tuple2.java +++ b/src-gen/main/java/io/vavr/Tuple2.java @@ -394,7 +394,7 @@ public boolean equals(Object o) { @Override public int hashCode() { - return Objects.hash(_1, _2); + return Objects.hashCode(_1) ^ Objects.hashCode(_2); } @Override diff --git a/src-gen/test/java/io/vavr/Tuple2Test.java b/src-gen/test/java/io/vavr/Tuple2Test.java index 17200e6a7..160ca58cd 100644 --- a/src-gen/test/java/io/vavr/Tuple2Test.java +++ b/src-gen/test/java/io/vavr/Tuple2Test.java @@ -36,9 +36,9 @@ import io.vavr.collection.Seq; import io.vavr.collection.Stream; import java.util.AbstractMap; +import java.util.AbstractMap.SimpleEntry; import java.util.Comparator; import java.util.Map; -import java.util.Objects; import org.junit.Test; public class Tuple2Test { @@ -237,7 +237,7 @@ public void shouldRecognizeNonEqualityPerComponent() { @Test public void shouldComputeCorrectHashCode() { final int actual = createTuple().hashCode(); - final int expected = Objects.hash(null, null); + final int expected = new SimpleEntry<>(null, null).hashCode(); assertThat(actual).isEqualTo(expected); } diff --git a/src/test/java/io/vavr/TupleTest.java b/src/test/java/io/vavr/TupleTest.java index 82fde37bb..9ae3589fa 100644 --- a/src/test/java/io/vavr/TupleTest.java +++ b/src/test/java/io/vavr/TupleTest.java @@ -164,7 +164,7 @@ public void shouldCreateTuple2FromEntry() { @Test public void shouldHashTuple2() { final Tuple2 t = tuple2(); - assertThat(t.hashCode()).isEqualTo(Objects.hash(t._1, t._2)); + assertThat(t.hashCode()).isEqualTo(new AbstractMap.SimpleEntry<>(t._1, t._2).hashCode()); } @Test diff --git a/src/test/java/io/vavr/collection/AbstractMapTest.java b/src/test/java/io/vavr/collection/AbstractMapTest.java index ccd2245fb..51272a351 100644 --- a/src/test/java/io/vavr/collection/AbstractMapTest.java +++ b/src/test/java/io/vavr/collection/AbstractMapTest.java @@ -1441,4 +1441,11 @@ public void shouldNonNilGroupByIdentity() { assertThat(actual).isEqualTo(expected); } + // -- hashCode + + @Override + @Test + public void shouldCalculateDifferentHashCodesForDifferentTraversables() { + assertThat(mapOf('a', 2, 'b', 1).hashCode()).isNotEqualTo(mapOf('a', 1, 'b', 2).hashCode()); + } } diff --git a/src/test/java/io/vavr/collection/AbstractMultimapTest.java b/src/test/java/io/vavr/collection/AbstractMultimapTest.java index fd4a5788b..b2abb2c7d 100644 --- a/src/test/java/io/vavr/collection/AbstractMultimapTest.java +++ b/src/test/java/io/vavr/collection/AbstractMultimapTest.java @@ -183,6 +183,8 @@ protected , T2> Multimap emptyMap() { abstract protected , V> Multimap mapOfPairs(K k1, V v1, K k, V v2, K k3, V v3); + abstract protected , V> Multimap mapOf(K k1, V v1, K k2, V v2); + abstract protected , V> Multimap mapOf(K key, V value); abstract protected , V> Multimap mapOf(java.util.Map map); @@ -1198,4 +1200,11 @@ public void shouldCollectUsingMultimap() { // java.lang.ClassCastException: io.vavr.collection.List$Cons cannot be cast to java.lang.Comparable } + // -- hashCode + + @Override + @Test + public void shouldCalculateDifferentHashCodesForDifferentTraversables() { + assertThat(mapOf("a", 2, "b", 1).hashCode()).isNotEqualTo(mapOf("a", 1, "b", 2).hashCode()); + } } diff --git a/src/test/java/io/vavr/collection/HashMultimapTest.java b/src/test/java/io/vavr/collection/HashMultimapTest.java index 31cf94035..1a5e44a6d 100644 --- a/src/test/java/io/vavr/collection/HashMultimapTest.java +++ b/src/test/java/io/vavr/collection/HashMultimapTest.java @@ -98,6 +98,20 @@ protected , V> HashMultimap mapOfPairs(K k1, V v1, } } + @Override + protected , V> Multimap mapOf(K k1, V v1, K k2, V v2) { + switch (containerType) { + case SEQ: + return HashMultimap.withSeq().of(k1, v1, k2, v2); + case SET: + return HashMultimap.withSet().of(k1, v1, k2, v2); + case SORTED_SET: + return HashMultimap.withSortedSet(Comparators.naturalComparator()).of(k1, v1, k2, v2); + default: + throw new RuntimeException(); + } + } + @Override protected , V> HashMultimap mapOf(K key, V value) { switch (containerType) { diff --git a/src/test/java/io/vavr/collection/LinkedHashMultimapTest.java b/src/test/java/io/vavr/collection/LinkedHashMultimapTest.java index d3aca6993..5212e5b72 100644 --- a/src/test/java/io/vavr/collection/LinkedHashMultimapTest.java +++ b/src/test/java/io/vavr/collection/LinkedHashMultimapTest.java @@ -98,6 +98,20 @@ protected , V> LinkedHashMultimap mapOfPairs(K k1, } } + @Override + protected , V> Multimap mapOf(K k1, V v1, K k2, V v2) { + switch (containerType) { + case SEQ: + return LinkedHashMultimap.withSeq().of(k1, v1, k2, v2); + case SET: + return LinkedHashMultimap.withSet().of(k1, v1, k2, v2); + case SORTED_SET: + return LinkedHashMultimap.withSortedSet(Comparators.naturalComparator()).of(k1, v1, k2, v2); + default: + throw new RuntimeException(); + } + } + @Override protected , V> LinkedHashMultimap mapOf(K key, V value) { switch (containerType) { diff --git a/src/test/java/io/vavr/collection/TreeMultimapTest.java b/src/test/java/io/vavr/collection/TreeMultimapTest.java index e5b53c9d6..3a3051666 100644 --- a/src/test/java/io/vavr/collection/TreeMultimapTest.java +++ b/src/test/java/io/vavr/collection/TreeMultimapTest.java @@ -98,6 +98,20 @@ protected , V> TreeMultimap mapOfPairs(K k1, V v1, } } + @Override + protected , V> Multimap mapOf(K k1, V v1, K k2, V v2) { + switch (containerType) { + case SEQ: + return TreeMultimap.withSeq().of(k1, v1, k2, v2); + case SET: + return TreeMultimap.withSet().of(k1, v1, k2, v2); + case SORTED_SET: + return TreeMultimap.withSortedSet(Comparators.naturalComparator()).of(k1, v1, k2, v2); + default: + throw new RuntimeException(); + } + } + @Override protected , V> TreeMultimap mapOf(K key, V value) { switch (containerType) {