Skip to content

Commit 123c301

Browse files
committed
fix(validate): Use BigDecimal for multipleOf to avoid float equality
SonarQube flagged the previous (n / multipleOf) % 1 != 0 check for floating-point equality. Switches to BigDecimal.remainder so e.g. 0.3 divided by 0.1 reports cleanly instead of falling foul of double rounding.
1 parent 499d6d6 commit 123c301

1 file changed

Lines changed: 13 additions & 1 deletion

File tree

src/main/java/com/retailsvc/http/validate/DefaultValidator.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import com.retailsvc.http.spec.schema.Schema;
1919
import com.retailsvc.http.spec.schema.StringSchema;
2020
import com.retailsvc.http.spec.schema.TypeName;
21+
import java.math.BigDecimal;
2122
import java.time.LocalDate;
2223
import java.time.OffsetDateTime;
2324
import java.util.ArrayList;
@@ -175,11 +176,22 @@ private void validateNumber(Object value, NumberSchema s, String pointer) {
175176
if (s.exclusiveMaximum() != null && n >= s.exclusiveMaximum().doubleValue()) {
176177
fail(pointer, "exclusiveMaximum", "number not less than " + s.exclusiveMaximum(), n);
177178
}
178-
if (s.multipleOf() != null && (n / s.multipleOf().doubleValue()) % 1 != 0) {
179+
if (s.multipleOf() != null && !isMultipleOf(n, s.multipleOf().doubleValue())) {
179180
fail(pointer, "multipleOf", "not a multiple of " + s.multipleOf(), n);
180181
}
181182
}
182183

184+
/**
185+
* Returns whether {@code value} is an exact multiple of {@code divisor}, using {@link BigDecimal}
186+
* to avoid floating-point rounding artifacts that {@code (value / divisor) % 1 == 0} would
187+
* produce (e.g., {@code 0.3 / 0.1} is not exactly {@code 3.0} as a double).
188+
*/
189+
private static boolean isMultipleOf(double value, double divisor) {
190+
BigDecimal v = BigDecimal.valueOf(value);
191+
BigDecimal d = BigDecimal.valueOf(divisor);
192+
return v.remainder(d).compareTo(BigDecimal.ZERO) == 0;
193+
}
194+
183195
@SuppressWarnings("unchecked")
184196
private void validateObject(Object value, ObjectSchema s, String pointer) {
185197
require(value instanceof Map, pointer, "type", "expected object");

0 commit comments

Comments
 (0)