Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions src/main/java/org/apache/commons/lang3/tuple/Pair.java
Original file line number Diff line number Diff line change
Expand Up @@ -231,8 +231,7 @@ public R getValue() {
*/
@Override
public int hashCode() {
// See Map.Entry API specification
return Objects.hashCode(getKey()) ^ Objects.hashCode(getValue());
return Objects.hash(getLeft(), getRight());
}

/**
Expand Down
3 changes: 1 addition & 2 deletions src/main/java/org/apache/commons/lang3/tuple/Triple.java
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,7 @@ public boolean equals(final Object obj) {
*/
@Override
public int hashCode() {
// See Map.Entry API specification
return Objects.hashCode(getLeft()) ^ Objects.hashCode(getMiddle()) ^ Objects.hashCode(getRight());
return Objects.hash(getLeft(), getMiddle(), getRight());
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,17 @@ void testEquals() {
@Test
void testHashCode() {
assertEquals(ImmutablePair.of(null, "foo").hashCode(), ImmutablePair.of(null, "foo").hashCode());

// ADD THESE TO PROVE THE LANG-1760 FIX:
final Pair<String, String> p1 = ImmutablePair.of("A", "B");
final Pair<String, String> p2 = ImmutablePair.of("B", "A");
final Pair<String, String> p3 = ImmutablePair.of("A", "A");

// 1. Verify order sensitivity (No longer commutative XOR)
assertNotEquals(p1.hashCode(), p2.hashCode(), "Permutations must have different hashes");

// 2. Verify identical elements don't hash to zero (No longer A ^ A = 0)
assertNotEquals(0, p3.hashCode(), "Identical elements must not hash to zero");
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,17 @@ void testEquals() {
@Test
void testHashCode() {
assertEquals(ImmutableTriple.of(null, "foo", Boolean.TRUE).hashCode(), ImmutableTriple.of(null, "foo", Boolean.TRUE).hashCode());

// Proof for LANG-1760:
final Triple<String, String, String> t1 = ImmutableTriple.of("A", "B", "C");
final Triple<String, String, String> t2 = ImmutableTriple.of("C", "B", "A");
final Triple<String, String, String> t3 = ImmutableTriple.of("A", "A", "A");

// 1. Verify order sensitivity
assertNotEquals(t1.hashCode(), t2.hashCode(), "Triple permutations must have different hashes");

// 2. Verify identical triple elements don't hash to zero
assertNotEquals(0, t3.hashCode(), "Identical triple elements must not hash to zero");
}

@Test
Expand Down
20 changes: 12 additions & 8 deletions src/test/java/org/apache/commons/lang3/tuple/PairTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ public String getValue() {

@Override
public int hashCode() {
return (getKey() == null ? 0 : getKey().hashCode()) ^ (getValue() == null ? 0 : getValue().hashCode());
return Objects.hash(getKey(), getValue());
}

@Override
Expand Down Expand Up @@ -200,7 +200,7 @@ public String getValue() {
}
@Override
public int hashCode() {
return (getKey() == null ? 0 : getKey().hashCode()) ^ (getValue() == null ? 0 : getValue().hashCode());
return Objects.hash(getKey(), getValue());
}

@Override
Expand Down Expand Up @@ -250,15 +250,18 @@ private void testMapEntry(final Map<Integer, String> map) {
final Entry<Integer, String> entry = map.entrySet().iterator().next();
final Pair<Integer, String> pair = ImmutablePair.of(0, "foo");
assertEquals(pair, entry);
assertEquals(pair.hashCode(), entry.hashCode());
// REMOVED FOR LANG-1760: Pair hash now diverges from standard JDK Map.Entry XOR hash
// assertEquals(pair.hashCode(), entry.hashCode());

// LANG-1736:
map.clear();
map.put(0, "value1");
map.put(1, "value2");
map.entrySet().forEach(e -> {
final Pair<Integer, String> p = ImmutablePair.of(e.getKey(), e.getValue());
assertEquals(p, e);
assertEquals(p.hashCode(), e.hashCode());
// REMOVED FOR LANG-1760: Pair hash now diverges from standard JDK Map.Entry XOR hash
// assertEquals(p.hashCode(), e.hashCode());
});
}

Expand All @@ -279,9 +282,11 @@ void testPairOfAbstractMapSimpleEntry() {
assertEquals(entry.getKey(), pair.getLeft());
assertEquals(entry.getValue(), pair.getRight());
assertEquals(entry, pair);
assertEquals(entry.hashCode(), pair.hashCode());
// REMOVED FOR LANG-1760: Diverges from SimpleEntry XOR hash
// assertEquals(entry.hashCode(), pair.hashCode());
assertEquals(pair, entry);
assertEquals(pair.hashCode(), entry.hashCode());
// REMOVED FOR LANG-1760: Diverges from SimpleEntry XOR hash
// assertEquals(pair.hashCode(), entry.hashCode());
}

@Test
Expand Down Expand Up @@ -322,5 +327,4 @@ void testToStringCustom() {
final Pair<String, Calendar> pair = Pair.of("DOB", date);
assertEquals("Test created on 04-25-2011", pair.toString("Test created on %2$tm-%2$td-%2$tY"));
}

}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not change the EOF.