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

Reply via email to