Skip to content

Commit 0f0a24e

Browse files
kostystevehu
authored andcommitted
Almost JSON-spec compliant validation of numeric values (#119)
1 parent 7b3c7f0 commit 0f0a24e

File tree

2 files changed

+94
-11
lines changed

2 files changed

+94
-11
lines changed

src/main/java/com/networknt/schema/TypeValidator.java

Lines changed: 58 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,9 @@ public static boolean isInteger(String str) {
102102
if (str == null || str.equals("")) {
103103
return false;
104104
}
105+
106+
// all code below could be replaced with
107+
//return str.matrch("[-+]?(?:0|[1-9]\\d*)")
105108
int i = 0;
106109
if (str.charAt(0) == '-' || str.charAt(0) == '+') {
107110
if (str.length() == 1) {
@@ -126,31 +129,75 @@ public static boolean isNumeric(String str) {
126129
if (str == null || str.equals("")) {
127130
return false;
128131
}
132+
133+
// all code below could be replaced with
134+
//return str.matrch("[-+]?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?")
129135
int i = 0;
130-
boolean hasDot = false;
131-
if (str.charAt(0) == '-' || str.charAt(0) == '+') {
136+
int len = str.length();
137+
138+
if (str.charAt(i) == MINUS || str.charAt(i) == PLUS) {
132139
if (str.length() == 1) {
133140
return false;
134141
}
135142
i = 1;
136143
}
137-
for (; i < str.length(); i++) {
138-
char c = str.charAt(i);
139-
if ((c < '0' || c > '9') && c != '.') {
144+
145+
char c = str.charAt(i++);
146+
147+
if (c == CHAR_0) {
148+
// TODO: if leading zeros are supported (counter to JSON spec) handle it here
149+
if (i < len){
150+
c = str.charAt(i++);
151+
if (c != DOT && c != CHAR_E && c != CHAR_e) {
152+
return false;
153+
}
154+
}
155+
} else if (CHAR_1 <= c && c <= CHAR_9) {
156+
while ( i < len && CHAR_0 <= c && c <= CHAR_9 ) {
157+
c = str.charAt(i++);
158+
}
159+
} else {
160+
return false;
161+
}
162+
163+
if (c == DOT) {
164+
if (i >= len) {
165+
return false;
166+
}
167+
c = str.charAt(i++);
168+
while ( i < len && CHAR_0 <= c && c <= CHAR_9 ) {
169+
c = str.charAt(i++);
170+
}
171+
}
172+
173+
if (c == CHAR_E || c == CHAR_e) {
174+
if (i >= len ) {
140175
return false;
141176
}
142-
if (c == '.') {
143-
if (hasDot) {
177+
c = str.charAt(i++);
178+
if (c == PLUS || c == MINUS) {
179+
if (i >= len) {
144180
return false;
145181
}
146-
else {
147-
hasDot = true;
148-
}
182+
c = str.charAt(i++);
183+
}
184+
while ( i < len && CHAR_0 <= c && c <= CHAR_9 ) {
185+
c = str.charAt(i++);
149186
}
150187
}
151-
return true;
188+
189+
return i >= len && (CHAR_0 <= c && c <= CHAR_9);
152190
}
153191

192+
private static final char CHAR_0 = '0';
193+
private static final char CHAR_1 = '1';
194+
private static final char CHAR_9 = '9';
195+
private static final char MINUS = '-';
196+
private static final char PLUS = '+';
197+
private static final char DOT = '.';
198+
private static final char CHAR_E = 'E';
199+
private static final char CHAR_e = 'e';
200+
154201
/**
155202
* Check if the type of the JsonNode's value is number based on the
156203
* status of typeLoose flag.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.networknt.schema;
2+
3+
import org.junit.Test;
4+
5+
import static com.networknt.schema.TypeValidator.isNumeric;
6+
import static org.junit.Assert.assertFalse;
7+
import static org.junit.Assert.assertTrue;
8+
9+
public class TypeValidatorTest {
10+
11+
private static final String[] validNumericValues = {
12+
"1", "-1", "1.1", "-1.1", "0E+1", "0E-1", "0E1", "-0E+1", "-0E-1", "-0E1", "0.1E+1", "0.1E-1", "0.1E1",
13+
"-0.1E+1", "-0.1E-1", "-0.1E1", "10.1", "-10.1", "10E+1", "10E-1", "10E1", "-10E+1", "-10E-1", "-10E1",
14+
"10.1E+1", "10.1E-1", "10.1E1", "-10.1E+1", "-10.1E-1", "-10.1E1", "1E+0", "1E-0", "1E0",
15+
"1E00000000000000000000"
16+
};
17+
private static final String[] invalidNumericValues = {
18+
"01.1", "1.", ".1", "0.1.1", "E1", "E+1", "E-1", ".E1", ".E+1", ".E-1", ".1E1", ".1E+1", ".1E-1", "1E-",
19+
"1E+", "1E", "+", "-", "1a", "0.1a", "0E1a", "0E-1a", "1.0a", "1.0aE1"
20+
//, "+0", "+1" // for backward compatibility, in violation of JSON spec
21+
};
22+
23+
@Test
24+
public void testNumeicValues() {
25+
for(String validValue : validNumericValues) {
26+
assertTrue(validValue, isNumeric(validValue));
27+
}
28+
}
29+
30+
@Test
31+
public void testNonNumeicValues() {
32+
for(String invalidValue : invalidNumericValues) {
33+
assertFalse(invalidValue, isNumeric(invalidValue));
34+
}
35+
}
36+
}

0 commit comments

Comments
 (0)