Skip to content

Commit 858a838

Browse files
author
Arseny Nasokin
committed
Use ECMA-262 validator when requested
1 parent 2971a32 commit 858a838

File tree

4 files changed

+132
-69
lines changed

4 files changed

+132
-69
lines changed

pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,11 @@
8787
<artifactId>commons-lang3</artifactId>
8888
<version>${version.common-lang3}</version>
8989
</dependency>
90+
<dependency>
91+
<groupId>org.jruby.joni</groupId>
92+
<artifactId>joni</artifactId>
93+
<version>2.1.31</version>
94+
</dependency>
9095
<dependency>
9196
<groupId>ch.qos.logback</groupId>
9297
<artifactId>logback-classic</artifactId>
Lines changed: 102 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,102 @@
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-
import java.util.regex.Matcher;
26-
import java.util.regex.Pattern;
27-
import java.util.regex.PatternSyntaxException;
28-
29-
public class PatternValidator extends BaseJsonValidator implements JsonValidator {
30-
private static final Logger logger = LoggerFactory.getLogger(PatternValidator.class);
31-
32-
private String pattern;
33-
private Pattern p;
34-
35-
public PatternValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) {
36-
37-
super(schemaPath, schemaNode, parentSchema, ValidatorTypeCode.PATTERN, validationContext);
38-
pattern = "";
39-
if (schemaNode != null && schemaNode.isTextual()) {
40-
pattern = schemaNode.textValue();
41-
p = Pattern.compile(pattern);
42-
}
43-
44-
parseErrorCode(getValidatorType().getErrorCodeKey());
45-
}
46-
47-
public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String at) {
48-
debug(logger, node, rootNode, at);
49-
50-
JsonType nodeType = TypeFactory.getValueNodeType(node);
51-
if (nodeType != JsonType.STRING) {
52-
return Collections.emptySet();
53-
}
54-
55-
if (p != null) {
56-
try {
57-
Matcher m = p.matcher(node.asText());
58-
if (!m.find()) {
59-
return Collections.singleton(buildValidationMessage(at, pattern));
60-
}
61-
} catch (PatternSyntaxException pse) {
62-
logger.error("Failed to apply pattern on " + at + ": Invalid syntax [" + pattern + "]", pse);
63-
}
64-
}
65-
66-
return Collections.emptySet();
67-
}
68-
69-
}
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.jcodings.specific.UTF8Encoding;
21+
import org.joni.Option;
22+
import org.joni.Regex;
23+
import org.joni.Syntax;
24+
import org.joni.exception.SyntaxException;
25+
import org.slf4j.Logger;
26+
import org.slf4j.LoggerFactory;
27+
28+
import java.util.Collections;
29+
import java.util.Set;
30+
import java.util.regex.Matcher;
31+
import java.util.regex.Pattern;
32+
import java.util.regex.PatternSyntaxException;
33+
34+
public class PatternValidator extends BaseJsonValidator implements JsonValidator {
35+
private static final Logger logger = LoggerFactory.getLogger(PatternValidator.class);
36+
37+
private String pattern;
38+
private Pattern compiledPattern;
39+
private Regex compiledRegex;
40+
41+
public PatternValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) {
42+
43+
super(schemaPath, schemaNode, parentSchema, ValidatorTypeCode.PATTERN, validationContext);
44+
pattern = "";
45+
if (schemaNode != null && schemaNode.isTextual()) {
46+
pattern = schemaNode.textValue();
47+
try {
48+
compileRegexPattern(pattern, validationContext.getConfig().isEcma262Validator());
49+
} catch (PatternSyntaxException pse) {
50+
logger.error("Failed to compile pattern : Invalid syntax [" + pattern + "]", pse);
51+
throw pse;
52+
} catch (SyntaxException se) {
53+
logger.error("Failed to compile pattern : Invalid syntax [" + pattern + "]", se);
54+
throw se;
55+
}
56+
}
57+
58+
parseErrorCode(getValidatorType().getErrorCodeKey());
59+
}
60+
61+
private void compileRegexPattern(String regex, boolean useEcma262Validator) {
62+
if (useEcma262Validator) {
63+
byte[] regexBytes = regex.getBytes();
64+
this.compiledRegex = new Regex(regexBytes, 0, regexBytes.length, Option.NONE, UTF8Encoding.INSTANCE, Syntax.ECMAScript);
65+
} else {
66+
compiledPattern = Pattern.compile(pattern);
67+
}
68+
}
69+
70+
private boolean matches(String value) {
71+
if (compiledRegex == null && compiledPattern == null) {
72+
return true;
73+
}
74+
75+
if (compiledPattern == null) {
76+
byte[] bytes = value.getBytes();
77+
return compiledRegex.matcher(bytes).search(0, bytes.length, Option.NONE) >= 0;
78+
} else {
79+
return compiledPattern.matcher(value).find();
80+
}
81+
82+
}
83+
84+
public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String at) {
85+
debug(logger, node, rootNode, at);
86+
87+
JsonType nodeType = TypeFactory.getValueNodeType(node);
88+
if (nodeType != JsonType.STRING) {
89+
return Collections.emptySet();
90+
}
91+
92+
try {
93+
if (!matches(node.asText())) {
94+
return Collections.singleton(buildValidationMessage(at, pattern));
95+
}
96+
} catch (PatternSyntaxException pse) {
97+
logger.error("Failed to apply pattern on " + at + ": Invalid syntax [" + pattern + "]", pse);
98+
}
99+
100+
return Collections.emptySet();
101+
}
102+
}

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ public class SchemaValidatorsConfig {
3333
*/
3434
private boolean failFast;
3535

36+
/**
37+
* When set to true, use ECMA-262 compatible validator
38+
*/
39+
private boolean ecma262Validator;
40+
3641
/**
3742
* Map of public, normally internet accessible schema URLs to alternate locations; this allows for offline
3843
* validation of schemas that refer to public URLs. This is merged with any mappings the {@link JsonSchemaFactory}
@@ -90,6 +95,14 @@ public void setHandleNullableField(boolean handleNullableField) {
9095
this.handleNullableField = handleNullableField;
9196
}
9297

98+
public boolean isEcma262Validator() {
99+
return ecma262Validator;
100+
}
101+
102+
public void setEcma262Validator(boolean ecma262Validator) {
103+
this.ecma262Validator = ecma262Validator;
104+
}
105+
93106
public SchemaValidatorsConfig() {
94107
}
95108
}

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,16 @@ public void testInvalidPatternPropertiesValidator() throws Exception {
3636
Set<ValidationMessage> errors = schema.validate(node);
3737
Assert.assertEquals(errors.size(), 0);
3838
}
39+
40+
@Test(expected = JsonSchemaException.class)
41+
public void testInvalidPatternPropertiesValidatorECMA262() throws Exception {
42+
SchemaValidatorsConfig config = new SchemaValidatorsConfig();
43+
config.setEcma262Validator(true);
44+
JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V4);
45+
JsonSchema schema = factory.getSchema("{\"patternProperties\":6}", config);
46+
47+
JsonNode node = getJsonNodeFromStringContent("");
48+
Set<ValidationMessage> errors = schema.validate(node);
49+
Assert.assertEquals(errors.size(), 0);
50+
}
3951
}

0 commit comments

Comments
 (0)