20
20
import org .slf4j .Logger ;
21
21
import org .slf4j .LoggerFactory ;
22
22
23
+ import java .math .BigInteger ;
23
24
import java .util .Collections ;
24
25
import java .util .Set ;
25
26
26
27
public class MinimumValidator extends BaseJsonValidator implements JsonValidator {
27
28
private static final Logger logger = LoggerFactory .getLogger (MinimumValidator .class );
28
29
private static final String PROPERTY_EXCLUSIVE_MINIMUM = "exclusiveMinimum" ;
29
30
30
- private double minimum ;
31
31
private boolean excluded = false ;
32
32
33
+ /**
34
+ * In order to limit number of `if` statements in `validate` method, all the
35
+ * logic of picking the right comparison is abstracted into a mixin.
36
+ */
37
+ private final ThresholdMixin typedMinimum ;
38
+
33
39
public MinimumValidator (String schemaPath , JsonNode schemaNode , JsonSchema parentSchema , ValidationContext validationContext ) {
34
40
super (schemaPath , schemaNode , parentSchema , ValidatorTypeCode .MINIMUM , validationContext );
35
- if (schemaNode .isNumber ()) {
36
- minimum = schemaNode .doubleValue ();
37
- } else {
41
+
42
+ if (!schemaNode .isNumber ()) {
38
43
throw new JsonSchemaException ("minimum value is not a number" );
39
44
}
40
45
@@ -44,6 +49,56 @@ public MinimumValidator(String schemaPath, JsonNode schemaNode, JsonSchema paren
44
49
}
45
50
46
51
parseErrorCode (getValidatorType ().getErrorCodeKey ());
52
+
53
+ if (!JsonType .INTEGER .toString ().equals (getNodeFieldType ())) {
54
+ // "number" or no type
55
+ // by default treat value as double: compatible with previous behavior
56
+ final double dmin = schemaNode .doubleValue ();
57
+ typedMinimum = new ThresholdMixin () {
58
+ @ Override
59
+ public boolean crossesThreshold (JsonNode node ) {
60
+ double value = node .asDouble ();
61
+ return lessThan (value , dmin ) || (excluded && MinimumValidator .this .equals (value , dmin ));
62
+ }
63
+
64
+ @ Override
65
+ public String thresholdValue () {
66
+ return String .valueOf (dmin );
67
+ }
68
+ };
69
+
70
+ } else if ( schemaNode .isLong () || schemaNode .isInt () ) {
71
+ // "integer", and within long range
72
+ final long lmin = schemaNode .asLong ();
73
+ typedMinimum = new ThresholdMixin () {
74
+ @ Override
75
+ public boolean crossesThreshold (JsonNode node ) {
76
+ long val = node .asLong ();
77
+ return node .isBigInteger () || lmin > val || (excluded && lmin >= val );
78
+ }
79
+
80
+ @ Override
81
+ public String thresholdValue () {
82
+ return String .valueOf (lmin );
83
+ }
84
+ };
85
+
86
+ } else {
87
+ // "integer" outside long range
88
+ final BigInteger bimin = new BigInteger (schemaNode .asText ());
89
+ typedMinimum = new ThresholdMixin () {
90
+ @ Override
91
+ public boolean crossesThreshold (JsonNode node ) {
92
+ int cmp = bimin .compareTo (node .bigIntegerValue ());
93
+ return cmp > 0 || (excluded && cmp >= 0 );
94
+ }
95
+
96
+ @ Override
97
+ public String thresholdValue () {
98
+ return String .valueOf (bimin );
99
+ }
100
+ };
101
+ }
47
102
}
48
103
49
104
public Set <ValidationMessage > validate (JsonNode node , JsonNode rootNode , String at ) {
@@ -53,14 +108,9 @@ public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String
53
108
// minimum only applies to numbers
54
109
return Collections .emptySet ();
55
110
}
56
- String fieldType = this .getNodeFieldType ();
57
-
58
- double value = node .asDouble ();
59
- if (lessThan (value , minimum ) || (excluded && equals (value , minimum ))) {
60
- if (JsonType .INTEGER .toString ().equals (fieldType )) {
61
- return Collections .singleton (buildValidationMessage (at , "" + (int ) minimum ));
62
- }
63
- return Collections .singleton (buildValidationMessage (at , "" + minimum ));
111
+
112
+ if (typedMinimum .crossesThreshold (node )) {
113
+ return Collections .singleton (buildValidationMessage (at , typedMinimum .thresholdValue ()));
64
114
}
65
115
return Collections .emptySet ();
66
116
}
0 commit comments