Skip to content

Commit a818b6e

Browse files
committed
Fix #53: Backporting from the 2020-12 branch the fix for multipleOf
Signed-off-by: Paulo Lopes <[email protected]>
1 parent 616cde6 commit a818b6e

File tree

1 file changed

+41
-6
lines changed

1 file changed

+41
-6
lines changed

src/main/java/io/vertx/json/schema/common/MultipleOfValidatorFactory.java

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,15 @@
1515
import io.vertx.json.schema.SchemaException;
1616
import io.vertx.json.schema.ValidationException;
1717

18+
import java.math.BigDecimal;
19+
1820
public class MultipleOfValidatorFactory implements ValidatorFactory {
1921

2022
@Override
2123
public Validator createValidator(JsonObject schema, JsonPointer scope, SchemaParserInternal parser, MutableStateValidator parent) {
2224
try {
2325
Number multipleOf = (Number) schema.getValue("multipleOf");
24-
return new MultipleOfValidator(multipleOf.doubleValue());
26+
return new MultipleOfValidator(multipleOf);
2527
} catch (ClassCastException e) {
2628
throw new SchemaException(schema, "Wrong type for multipleOf keyword", e);
2729
} catch (NullPointerException e) {
@@ -35,17 +37,50 @@ public boolean canConsumeSchema(JsonObject schema) {
3537
}
3638

3739
static class MultipleOfValidator extends BaseSyncValidator {
38-
private final double multipleOf;
40+
private final Long multipleOfL;
41+
private final BigDecimal multipleOfD;
42+
43+
public MultipleOfValidator(Number multipleOf) {
44+
// can be null to signal integer arithmetic
45+
multipleOfD = toBigDecimal(multipleOf, false);
46+
if (multipleOfD == null) {
47+
multipleOfL = multipleOf.longValue();
48+
} else {
49+
multipleOfL = null;
50+
}
51+
}
3952

40-
public MultipleOfValidator(double multipleOf) {
41-
this.multipleOf = multipleOf;
53+
private BigDecimal toBigDecimal(Number in, boolean force) {
54+
if (in instanceof BigDecimal) {
55+
return (BigDecimal) in;
56+
}
57+
if (in instanceof Float) {
58+
return BigDecimal.valueOf(in.floatValue());
59+
}
60+
if (in instanceof Double) {
61+
return BigDecimal.valueOf(in.doubleValue());
62+
}
63+
if (force) {
64+
return BigDecimal.valueOf(in.longValue());
65+
}
66+
return null;
4267
}
4368

4469
@Override
4570
public void validateSync(ValidatorContext context, Object in) throws ValidationException {
4671
if (in instanceof Number) {
47-
if (((Number) in).doubleValue() % multipleOf != 0) {
48-
throw ValidationException.create("provided number should be multiple of " + multipleOf, "multipleOf", in);
72+
// floating point arithmetic,
73+
// if the multipleOf is decimal, we always need to handle this operation as decimal
74+
final BigDecimal inBD = toBigDecimal((Number) in, multipleOfD != null);
75+
if (inBD != null) {
76+
if (inBD.remainder(multipleOfD).compareTo(BigDecimal.ZERO) != 0) {
77+
throw ValidationException.create("provided number should be multiple of " + multipleOfD, "multipleOf", in);
78+
}
79+
} else {
80+
// integer arithmetic, fallback for simpler arithmetic
81+
if (((Number) in).longValue() % multipleOfL != 0L) {
82+
throw ValidationException.create("provided number should be multiple of " + multipleOfL, "multipleOf", in);
83+
}
4984
}
5085
}
5186
}

0 commit comments

Comments
 (0)