Skip to content

Commit 6e99da6

Browse files
authored
Merge pull request #107 from nitin456/master
Fix for perfomance issue
2 parents a2b194c + 326e4a3 commit 6e99da6

File tree

5 files changed

+274
-161
lines changed

5 files changed

+274
-161
lines changed

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

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -43,37 +43,29 @@ public AnyOfValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentS
4343
public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String at) {
4444
debug(logger, node, rootNode, at);
4545

46+
Set<ValidationMessage> allErrors = new LinkedHashSet<ValidationMessage>();
4647
String typeValidatorName = "anyOf/type";
47-
JsonType nodeType = TypeFactory.getValueNodeType(node);
48-
//If schema has type validator and it doesn't match with node type then ignore it
49-
List<JsonSchema> filteredSchemaList = new ArrayList<JsonSchema>();
5048
List<String> expectedTypeList = new ArrayList<String>();
49+
5150
for (JsonSchema schema : schemas) {
5251
if (schema.validators.containsKey(typeValidatorName)) {
53-
JsonType schemaType = ((TypeValidator) schema.validators.get(typeValidatorName)).getSchemaType();
54-
if (schemaType == nodeType) {
55-
filteredSchemaList.add(schema);
52+
TypeValidator typeValidator = ((TypeValidator) schema.validators.get(typeValidatorName));
53+
//If schema has type validator and node type doesn't match with schemaType then ignore it
54+
//For union type, it is must to call TypeValidator
55+
if (typeValidator.getSchemaType() != JsonType.UNION && !typeValidator.equalsToSchemaType(node)) {
56+
expectedTypeList.add(typeValidator.getSchemaType().toString());
57+
continue;
5658
}
57-
expectedTypeList.add(schemaType.toString());
58-
}
59-
else {
60-
filteredSchemaList.add(schema);
6159
}
62-
}
63-
if (!schemas.isEmpty() && filteredSchemaList.isEmpty()) {
64-
return Collections.singleton(buildValidationMessage(at, StringUtils.join(expectedTypeList)));
65-
}
66-
67-
Set<ValidationMessage> allErrors = new LinkedHashSet<ValidationMessage>();
68-
69-
for (JsonSchema schema : filteredSchemaList) {
7060
Set<ValidationMessage> errors = schema.validate(node, rootNode, at);
7161
if (errors.isEmpty()) {
7262
return errors;
7363
}
7464
allErrors.addAll(errors);
7565
}
76-
66+
if (!schemas.isEmpty()) {
67+
return Collections.singleton(buildValidationMessage(at, StringUtils.join(expectedTypeList)));
68+
}
7769
return Collections.unmodifiableSet(allErrors);
7870
}
7971

Lines changed: 150 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -1,142 +1,150 @@
1-
/*
2-
* Copyright (c) 2016 Network New Technologies Inc.
3-
*
4-
* Licensed under the Apache License, Version 2.0 (the "License");
5-
* You may not use this file except in compliance with the License.
6-
* You may obtain a copy of the License at
7-
*
8-
* http://www.apache.org/licenses/LICENSE-2.0
9-
*
10-
* Unless required by applicable law or agreed to in writing, software
11-
* distributed under the License is distributed on an "AS IS" BASIS,
12-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13-
* See the License for the specific language governing permissions and
14-
* limitations under the License.
15-
*/
16-
17-
package com.networknt.schema;
18-
19-
import com.fasterxml.jackson.databind.JsonNode;
20-
import org.slf4j.Logger;
21-
import org.slf4j.LoggerFactory;
22-
23-
import java.util.Collections;
24-
import java.util.Set;
25-
26-
public class TypeValidator extends BaseJsonValidator implements JsonValidator {
27-
private static final Logger logger = LoggerFactory.getLogger(TypeValidator.class);
28-
29-
private JsonType schemaType;
30-
private UnionTypeValidator unionTypeValidator;
31-
32-
public TypeValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) {
33-
super(schemaPath, schemaNode, parentSchema, ValidatorTypeCode.TYPE, validationContext);
34-
schemaType = TypeFactory.getSchemaNodeType(schemaNode);
35-
36-
if (schemaType == JsonType.UNION) {
37-
unionTypeValidator = new UnionTypeValidator(schemaPath, schemaNode, parentSchema, validationContext);
38-
}
39-
40-
parseErrorCode(getValidatorType().getErrorCodeKey());
41-
}
42-
43-
public JsonType getSchemaType() {
44-
return schemaType;
45-
}
46-
47-
public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String at) {
48-
debug(logger, node, rootNode, at);
49-
50-
if (schemaType == JsonType.UNION) {
51-
return unionTypeValidator.validate(node, rootNode, at);
52-
}
53-
54-
JsonType nodeType = TypeFactory.getValueNodeType(node);
55-
// in the case that node type is not the same as schema type, try to convert node to the
56-
// same type of schema. In REST API, query parameters, path parameters and headers are all
57-
// string type and we must convert, otherwise, all schema validations will fail.
58-
if (nodeType != schemaType) {
59-
if (schemaType == JsonType.ANY ) {
60-
return Collections.emptySet();
61-
}
62-
if (schemaType == JsonType.NUMBER && nodeType == JsonType.INTEGER) {
63-
return Collections.emptySet();
64-
}
65-
if (nodeType == JsonType.NULL) {
66-
JsonNode nullable = this.getParentSchema().getSchemaNode().get("nullable");
67-
if (nullable != null && nullable.asBoolean()) {
68-
return Collections.emptySet();
69-
}
70-
}
71-
if(config.isTypeLoose()) {
72-
if (nodeType == JsonType.STRING) {
73-
if(schemaType == JsonType.INTEGER) {
74-
if(isInteger(node.textValue())) {
75-
return Collections.emptySet();
76-
}
77-
} else if(schemaType == JsonType.BOOLEAN) {
78-
if(isBoolean(node.textValue())) {
79-
return Collections.emptySet();
80-
}
81-
} else if(schemaType == JsonType.NUMBER) {
82-
if(isNumeric(node.textValue())) {
83-
return Collections.emptySet();
84-
}
85-
}
86-
}
87-
}
88-
return Collections.singleton(buildValidationMessage(at, nodeType.toString(), schemaType.toString()));
89-
}
90-
return Collections.emptySet();
91-
}
92-
93-
public static boolean isInteger(String str) {
94-
if (str == null) {
95-
return false;
96-
}
97-
if (str.isEmpty()) {
98-
return false;
99-
}
100-
int i = 0;
101-
if (str.charAt(0) == '-') {
102-
if (str.length() == 1) {
103-
return false;
104-
}
105-
i = 1;
106-
}
107-
for (; i < str.length(); i++) {
108-
char c = str.charAt(i);
109-
if (c < '0' || c > '9') {
110-
return false;
111-
}
112-
}
113-
return true;
114-
}
115-
116-
public static boolean isBoolean(String s) {
117-
return "true".equals(s) || "false".equals(s);
118-
}
119-
120-
public static boolean isNumeric(String str) {
121-
if (str == null) {
122-
return false;
123-
}
124-
if (str.isEmpty()) {
125-
return false;
126-
}
127-
int i = 0;
128-
if (str.charAt(0) == '-') {
129-
if (str.length() == 1) {
130-
return false;
131-
}
132-
i = 1;
133-
}
134-
for (; i < str.length(); i++) {
135-
char c = str.charAt(i);
136-
if (c < '0' || c > '9' && c != '.') {
137-
return false;
138-
}
139-
}
140-
return true;
141-
}
142-
}
1+
/*
2+
* Copyright (c) 2016 Network New Technologies Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* You may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.networknt.schema;
18+
19+
import com.fasterxml.jackson.databind.JsonNode;
20+
import org.slf4j.Logger;
21+
import org.slf4j.LoggerFactory;
22+
23+
import java.util.Collections;
24+
import java.util.Set;
25+
26+
public class TypeValidator extends BaseJsonValidator implements JsonValidator {
27+
private static final Logger logger = LoggerFactory.getLogger(TypeValidator.class);
28+
29+
private JsonType schemaType;
30+
private UnionTypeValidator unionTypeValidator;
31+
32+
public TypeValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) {
33+
super(schemaPath, schemaNode, parentSchema, ValidatorTypeCode.TYPE, validationContext);
34+
schemaType = TypeFactory.getSchemaNodeType(schemaNode);
35+
36+
if (schemaType == JsonType.UNION) {
37+
unionTypeValidator = new UnionTypeValidator(schemaPath, schemaNode, parentSchema, validationContext);
38+
}
39+
40+
parseErrorCode(getValidatorType().getErrorCodeKey());
41+
}
42+
43+
public JsonType getSchemaType() {
44+
return schemaType;
45+
}
46+
47+
public boolean equalsToSchemaType(JsonNode node) {
48+
JsonType nodeType = TypeFactory.getValueNodeType(node);
49+
// in the case that node type is not the same as schema type, try to convert node to the
50+
// same type of schema. In REST API, query parameters, path parameters and headers are all
51+
// string type and we must convert, otherwise, all schema validations will fail.
52+
if (nodeType != schemaType) {
53+
if (schemaType == JsonType.ANY) {
54+
return true;
55+
}
56+
if (schemaType == JsonType.NUMBER && nodeType == JsonType.INTEGER) {
57+
return true;
58+
}
59+
if (nodeType == JsonType.NULL) {
60+
JsonNode nullable = this.getParentSchema().getSchemaNode().get("nullable");
61+
if (nullable != null && nullable.asBoolean()) {
62+
return true;
63+
}
64+
}
65+
if(config.isTypeLoose()) {
66+
if (nodeType == JsonType.STRING) {
67+
if(schemaType == JsonType.INTEGER) {
68+
if(isInteger(node.textValue())) {
69+
return Collections.emptySet();
70+
}
71+
} else if(schemaType == JsonType.BOOLEAN) {
72+
if(isBoolean(node.textValue())) {
73+
return Collections.emptySet();
74+
}
75+
} else if(schemaType == JsonType.NUMBER) {
76+
if(isNumeric(node.textValue())) {
77+
return Collections.emptySet();
78+
}
79+
}
80+
}
81+
}
82+
return false;
83+
}
84+
return true;
85+
}
86+
87+
public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String at) {
88+
debug(logger, node, rootNode, at);
89+
90+
if (schemaType == JsonType.UNION) {
91+
return unionTypeValidator.validate(node, rootNode, at);
92+
}
93+
94+
if (!equalsToSchemaType(node)) {
95+
JsonType nodeType = TypeFactory.getValueNodeType(node);
96+
return Collections.singleton(buildValidationMessage(at, nodeType.toString(), schemaType.toString()));
97+
}
98+
return Collections.emptySet();
99+
}
100+
101+
public static boolean isInteger(String str) {
102+
if (str == null) {
103+
return false;
104+
}
105+
if (str.isEmpty()) {
106+
return false;
107+
}
108+
int i = 0;
109+
if (str.charAt(0) == '-') {
110+
if (str.length() == 1) {
111+
return false;
112+
}
113+
i = 1;
114+
}
115+
for (; i < str.length(); i++) {
116+
char c = str.charAt(i);
117+
if (c < '0' || c > '9') {
118+
return false;
119+
}
120+
}
121+
return true;
122+
}
123+
124+
public static boolean isBoolean(String s) {
125+
return "true".equals(s) || "false".equals(s);
126+
}
127+
128+
public static boolean isNumeric(String str) {
129+
if (str == null) {
130+
return false;
131+
}
132+
if (str.isEmpty()) {
133+
return false;
134+
}
135+
int i = 0;
136+
if (str.charAt(0) == '-') {
137+
if (str.length() == 1) {
138+
return false;
139+
}
140+
i = 1;
141+
}
142+
for (; i < str.length(); i++) {
143+
char c = str.charAt(i);
144+
if (c < '0' || c > '9' && c != '.') {
145+
return false;
146+
}
147+
}
148+
return true;
149+
}
150+
}

src/test/java/com/networknt/schema/JsonSchemaTest.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,11 @@ public void testTypeValidator() throws Exception {
269269
runTestFile("tests/type.json");
270270
}
271271

272+
@Test
273+
public void testUnionTypeValidator() throws Exception {
274+
runTestFile("tests/union_type.json");
275+
}
276+
272277
@Test
273278
public void testUniqueItemsValidator() throws Exception {
274279
runTestFile("tests/uniqueItems.json");

src/test/resources/tests/anyOf.json

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,5 +64,35 @@
6464
"valid": false
6565
}
6666
]
67+
},
68+
{
69+
"description": "anyOf",
70+
"schema": {
71+
"anyOf": [
72+
{
73+
"type": "integer"
74+
},
75+
{
76+
"type": "string"
77+
}
78+
]
79+
},
80+
"tests": [
81+
{
82+
"description": "neither anyOf valid",
83+
"data": true,
84+
"valid": false
85+
},
86+
{
87+
"description": "first anyOf valid",
88+
"data": "test",
89+
"valid": true
90+
},
91+
{
92+
"description": "second anyOf valid",
93+
"data": 3,
94+
"valid": true
95+
}
96+
]
6797
}
6898
]

0 commit comments

Comments
 (0)