Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -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<Quantity> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
}
Loading