fix(user): replace Math.abs(hashCode()) with Math.floorMod in computeColor
Math.abs(Integer.MIN_VALUE) overflows back to Integer.MIN_VALUE (negative), making the old pattern unsafe for any palette size that doesn't evenly divide MIN_VALUE. Math.floorMod always returns a non-negative residue in [0, n-1], eliminating the overflow edge case entirely. Fixes SpotBugs RV_ABSOLUTE_VALUE_OF_HASHCODE (priority 1, CORRECTNESS). Closes #471 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit was merged in pull request #490.
This commit is contained in:
@@ -88,7 +88,8 @@ public class AppUser {
|
|||||||
};
|
};
|
||||||
|
|
||||||
public static String computeColor(UUID id) {
|
public static String computeColor(UUID id) {
|
||||||
return PALETTE[Math.abs(id.hashCode()) % PALETTE.length];
|
// Math.floorMod avoids the Integer.MIN_VALUE overflow trap in Math.abs(hashCode())
|
||||||
|
return PALETTE[Math.floorMod(id.hashCode(), PALETTE.length)];
|
||||||
}
|
}
|
||||||
|
|
||||||
@PrePersist
|
@PrePersist
|
||||||
|
|||||||
@@ -35,4 +35,15 @@ class AppUserTest {
|
|||||||
.count();
|
.count();
|
||||||
assertThat(distinct).isGreaterThan(1);
|
assertThat(distinct).isGreaterThan(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void computeColor_returnsValidPaletteColorForIntegerMinValueHash() {
|
||||||
|
// UUID "80000000-0000-0000-0000-000000000000" has hashCode() == Integer.MIN_VALUE.
|
||||||
|
// Math.abs(Integer.MIN_VALUE) overflows back to Integer.MIN_VALUE (negative), making
|
||||||
|
// Math.abs(hashCode()) % n unsafe for palette sizes that don't evenly divide MIN_VALUE.
|
||||||
|
// Math.floorMod eliminates this edge case entirely.
|
||||||
|
UUID minHashId = UUID.fromString("80000000-0000-0000-0000-000000000000");
|
||||||
|
assertThat(minHashId.hashCode()).isEqualTo(Integer.MIN_VALUE);
|
||||||
|
assertThat(EXPECTED_PALETTE).contains(AppUser.computeColor(minHashId));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user