This is an automated email from the ASF dual-hosted git repository.
ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-lang.git
The following commit(s) were added to refs/heads/master by this push:
new 94f612b31 [LANG-1764] Several hash collisions in Fraction class
94f612b31 is described below
commit 94f612b31fd934c17850b9a1c8f1eded2cbdc842
Author: Gary Gregory <[email protected]>
AuthorDate: Tue Mar 18 23:18:14 2025 -0400
[LANG-1764] Several hash collisions in Fraction class
---
src/changes/changes.xml | 3 +-
.../org/apache/commons/lang3/math/Fraction.java | 2 +-
.../apache/commons/lang3/math/FractionTest.java | 36 +++++++++++++++-------
3 files changed, 28 insertions(+), 13 deletions(-)
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index db2fe3c46..ac8c9e478 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -81,7 +81,8 @@ The <action> type attribute can be add,update,fix,remove.
<action type="fix" dev="ggregory" due-to="Gary
Gregory">Don't call TypeUtils.toString(Type) on every array item in
TypeUtils.parameterize[WithOwner](Type, Class, Map, Type>) unless
required.</action>
<action type="fix" dev="ggregory" due-to="Gary
Gregory">Remove -nouses directive from maven-bundle-plugin. OSGi package
imports now state 'uses' definitions for package imports, this doesn't affect
JPMS (from org.apache.commons:commons-parent:80).</action>
<action type="fix" dev="ggregory" due-to="Gary
Gregory">Instead of throwing a NullPointerException,
ArrayUtils.toStringArray(Object[]) should return "null" for null elements like
ArrayUtils.toStringArray(Object[], String) returns its
valueForNullElements.</action>
- <action type="fix" dev="ggregory" due-to="Gary
Gregory">Deprecate NumericEntityUnescaper.OPTION in favor of Apache Commons
Text.</action>
+ <action issue="LANG-1764" type="fix" dev="ggregory" due-to="Gary
Gregory">Deprecate NumericEntityUnescaper.OPTION in favor of Apache Commons
Text.</action>
+ <action type="fix" dev="ggregory" due-to="Gary
Gregory">Several hash collisions in Fraction class.</action>
<!-- ADD -->
<action type="add" dev="ggregory" due-to="Gary
Gregory">Add Strings and refactor StringUtils.</action>
<action issue="LANG-1747" type="add" dev="ggregory" due-to="Oliver B.
Fischer, Gary Gregory">Add StopWatch.run([Failable]Runnable) and
get([Failable]Supplier).</action>
diff --git a/src/main/java/org/apache/commons/lang3/math/Fraction.java
b/src/main/java/org/apache/commons/lang3/math/Fraction.java
index 0f608b59e..9329a3e1e 100644
--- a/src/main/java/org/apache/commons/lang3/math/Fraction.java
+++ b/src/main/java/org/apache/commons/lang3/math/Fraction.java
@@ -703,7 +703,7 @@ public int getProperWhole() {
public int hashCode() {
if (hashCode == 0) {
// hash code update should be atomic.
- hashCode = 37 * (37 * 17 + getNumerator()) + getDenominator();
+ hashCode = Objects.hash(denominator, numerator);
}
return hashCode;
}
diff --git a/src/test/java/org/apache/commons/lang3/math/FractionTest.java
b/src/test/java/org/apache/commons/lang3/math/FractionTest.java
index 2620e9b0a..c7e7349a3 100644
--- a/src/test/java/org/apache/commons/lang3/math/FractionTest.java
+++ b/src/test/java/org/apache/commons/lang3/math/FractionTest.java
@@ -26,6 +26,8 @@
import org.apache.commons.lang3.AbstractLangTest;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
/**
* Test cases for the {@link Fraction} class
@@ -616,17 +618,29 @@ public void testHashCode() {
assertTrue(f1.hashCode() != f2.hashCode());
f2 = Fraction.getFraction(6, 10);
assertTrue(f1.hashCode() != f2.hashCode());
- // Use cases from https://issues.apache.org/jira/browse/LANG-1764
- assertNotEquals(Fraction.getFraction(0, 37),
Fraction.getFraction(-464320789, 46));
- assertNotEquals(Fraction.getFraction(0, 37),
Fraction.getFraction(-464320788, 9));
- assertNotEquals(Fraction.getFraction(0, 37),
Fraction.getFraction(1857283155, 38));
- assertNotEquals(Fraction.getFraction(0, 25185704),
Fraction.getFraction(1161454280, 1050304));
- assertNotEquals(Fraction.getFraction(0, 38817068),
Fraction.getFraction(1509581512, 18875972));
- assertNotEquals(Fraction.getFraction(0, 38817068),
Fraction.getFraction(-2146369536, 2145078572));
- assertNotEquals(Fraction.getFraction(1400217380, 128),
Fraction.getFraction(2092630052, 150535040));
- assertNotEquals(Fraction.getFraction(1400217380, 128),
Fraction.getFraction(-580400986, 268435638));
- assertNotEquals(Fraction.getFraction(1400217380, 2147483592),
Fraction.getFraction(-2147483648, 268435452));
- assertNotEquals(Fraction.getFraction(1756395909, 4194598),
Fraction.getFraction(1174949894, 42860673));
+ }
+
+ /**
+ * Tests https://issues.apache.org/jira/browse/LANG-1764
+ */
+ @ParameterizedTest
+ // @formatter:off
+ @CsvSource({
+ "0, 37, -464320789, 46",
+ "0, 37, -464320788, 9",
+ "0, 37, 1857283155, 38",
+ "0, 25185704, 1161454280, 1050304",
+ "0, 38817068, 1509581512, 18875972",
+ "0, 38817068, -2146369536, 2145078572",
+ "1400217380, 128, 2092630052, 150535040",
+ "1400217380, 128, -580400986, 268435638",
+ "1400217380, 2147483592, -2147483648, 268435452",
+ "1756395909, 4194598, 1174949894, 42860673"
+ })
+ // @formatter:on
+ public void testHashCodeNotEquals(int f1n, int f1d, int f2n, int f2d) {
+ assertNotEquals(Fraction.getFraction(f1n, f1d),
Fraction.getFraction(f2n, f2d));
+ assertNotEquals(Fraction.getFraction(f1n, f1d).hashCode(),
Fraction.getFraction(f2n, f2d).hashCode());
}
@Test