From 441a5e5142634c4c4beb3d86a637187b01b6fcfd Mon Sep 17 00:00:00 2001 From: Min Jin Date: Thu, 22 Oct 2026 10:27:27 -0700 Subject: [PATCH] [kubernetes] Fix Quantity.hashCode to honor equals/hashCode contract Quantity.equals compares the underlying BigDecimal by value (ObjectUtils.compare -> BigDecimal.compareTo, scale-insensitive), but hashCode used Objects.hash(number) which is scale-sensitive. Value-equal quantities such as "1" and "1000m" (1.000) are therefore equal yet produce different hash codes, breaking HashMap/HashSet lookups. Normalize the scale with BigDecimal.stripTrailingZeros() before hashing so the hash is consistent with the value-based equals. Adds a focused unit test (fails before, passes after). --- .../java/io/kubernetes/client/custom/Quantity.java | 5 ++++- .../io/kubernetes/client/custom/QuantityTest.java | 13 +++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/kubernetes/src/main/java/io/kubernetes/client/custom/Quantity.java b/kubernetes/src/main/java/io/kubernetes/client/custom/Quantity.java index 8ab19aa875..c2940354b5 100644 --- a/kubernetes/src/main/java/io/kubernetes/client/custom/Quantity.java +++ b/kubernetes/src/main/java/io/kubernetes/client/custom/Quantity.java @@ -90,7 +90,10 @@ public boolean equals(Object o) { @Override public int hashCode() { - return Objects.hash(number); + // equals() compares numbers by value (scale-insensitive via BigDecimal.compareTo), so the + // hash must also be scale-insensitive to honor the equals/hashCode contract. Normalize the + // scale before hashing; otherwise e.g. "1" and "1000m" are equal but hash differently. + return Objects.hash(number == null ? null : number.stripTrailingZeros()); } public static class QuantityAdapter extends TypeAdapter { diff --git a/kubernetes/src/test/java/io/kubernetes/client/custom/QuantityTest.java b/kubernetes/src/test/java/io/kubernetes/client/custom/QuantityTest.java index f86ada4b2c..8ef4c39ebb 100644 --- a/kubernetes/src/test/java/io/kubernetes/client/custom/QuantityTest.java +++ b/kubernetes/src/test/java/io/kubernetes/client/custom/QuantityTest.java @@ -30,4 +30,17 @@ void containsInSet() { assertEquals(set1, set2, "Sets of equal elements are not equal"); } + + @Test + void equalQuantitiesWithDifferentScaleHaveEqualHashCode() { + // "1" parses to scale 0; "1000m" parses to 1000 * 10^-3 = 1.000 (scale 3). They are equal by + // value, so the equals/hashCode contract requires equal hash codes (and HashSet membership). + final Quantity a = Quantity.fromString("1"); + final Quantity b = Quantity.fromString("1000m"); + + assertEquals(a, b, "quantities with the same value should be equal"); + assertEquals( + a.hashCode(), b.hashCode(), "equal quantities must have equal hash codes (equals/hashCode contract)"); + assertEquals(Set.of(a), Set.of(b), "equal quantities must be interchangeable as hash-set members"); + } }