Skip to content

Commit 321ef08

Browse files
authored
Merge pull request #188 from everit-org/patternproperties-regexp-fix
Fixing regex handling in `"patternProperties"`
2 parents e605506 + 648d54c commit 321ef08

File tree

10 files changed

+87
-33
lines changed

10 files changed

+87
-33
lines changed

core/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
<modelVersion>4.0.0</modelVersion>
2222
<groupId>org.everit.json</groupId>
2323
<artifactId>org.everit.json.schema</artifactId>
24-
<version>1.9.0</version>
24+
<version>1.9.1</version>
2525
<packaging>bundle</packaging>
2626
<properties>
2727
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

core/src/main/java/org/everit/json/schema/ObjectSchema.java

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package org.everit.json.schema;
22

33
import static java.util.Objects.requireNonNull;
4+
import static java.util.stream.Collectors.toMap;
45

6+
import java.util.AbstractMap;
57
import java.util.ArrayList;
68
import java.util.Collections;
79
import java.util.HashMap;
@@ -10,10 +12,12 @@
1012
import java.util.Map;
1113
import java.util.Objects;
1214
import java.util.Set;
15+
import java.util.regex.Pattern;
1316

1417
import org.everit.json.schema.internal.JSONPrinter;
15-
16-
import com.google.re2j.Pattern;
18+
import org.everit.json.schema.regexp.JavaUtilRegexpFactory;
19+
import org.everit.json.schema.regexp.Regexp;
20+
import org.everit.json.schema.regexp.RegexpFactory;
1721

1822
/**
1923
* Object schema validator.
@@ -25,7 +29,13 @@ public class ObjectSchema extends Schema {
2529
*/
2630
public static class Builder extends Schema.Builder<ObjectSchema> {
2731

28-
private final Map<Pattern, Schema> patternProperties = new HashMap<>();
32+
private static final RegexpFactory DEFAULT_REGEXP_FACTORY = new JavaUtilRegexpFactory();
33+
34+
private static final Regexp toRegexp(String pattern) {
35+
return DEFAULT_REGEXP_FACTORY.createHandler(pattern);
36+
}
37+
38+
private final Map<Regexp, Schema> patternProperties = new HashMap<>();
2939

3040
private boolean requiresObject = true;
3141

@@ -89,13 +99,21 @@ public Builder minProperties(Integer minProperties) {
8999
return this;
90100
}
91101

102+
@Deprecated
92103
public Builder patternProperty(java.util.regex.Pattern pattern, Schema schema) {
93-
this.patternProperties.put(Pattern.compile(pattern.toString()), schema);
94-
return this;
104+
Regexp handler = toRegexp(pattern.toString());
105+
return patternProperty(handler, schema);
95106
}
96107

108+
@Deprecated
97109
public Builder patternProperty(String pattern, Schema schema) {
98-
return patternProperty(java.util.regex.Pattern.compile(pattern), schema);
110+
Regexp handler = toRegexp(pattern);
111+
return patternProperty(handler, schema);
112+
}
113+
114+
public Builder patternProperty(Regexp pattern, Schema schema) {
115+
this.patternProperties.put(pattern, schema);
116+
return this;
99117
}
100118

101119
/**
@@ -112,7 +130,7 @@ public Builder patternProperty(String pattern, Schema schema) {
112130
public Builder propertyDependency(String ifPresent, String mustBePresent) {
113131
Set<String> dependencies = propertyDependencies.get(ifPresent);
114132
if (dependencies == null) {
115-
dependencies = new HashSet<String>(1);
133+
dependencies = new HashSet<>(1);
116134
propertyDependencies.put(ifPresent, dependencies);
117135
}
118136
dependencies.add(mustBePresent);
@@ -169,7 +187,7 @@ private static <K, V> Map<K, V> copyMap(Map<K, V> original) {
169187

170188
private final boolean requiresObject;
171189

172-
private final Map<Pattern, Schema> patternProperties;
190+
private final Map<Regexp, Schema> patternProperties;
173191

174192
/**
175193
* Constructor.
@@ -206,10 +224,20 @@ public Integer getMinProperties() {
206224
return minProperties;
207225
}
208226

209-
public Map<Pattern, Schema> getPatternProperties() {
227+
Map<Regexp, Schema> getRegexpPatternProperties() {
210228
return patternProperties;
211229
}
212230

231+
@Deprecated
232+
public Map<Pattern, Schema> getPatternProperties() {
233+
return patternProperties.entrySet().stream()
234+
.map(entry -> new AbstractMap.SimpleEntry<>(java.util.regex.Pattern.compile(entry.getKey().toString()), entry.getValue()))
235+
.collect(toMap(
236+
(Map.Entry<java.util.regex.Pattern, Schema> entry) -> entry.getKey(),
237+
(Map.Entry<java.util.regex.Pattern, Schema> entry) -> entry.getValue()
238+
));
239+
}
240+
213241
public Map<String, Set<String>> getPropertyDependencies() {
214242
return propertyDependencies;
215243
}
@@ -277,9 +305,10 @@ private boolean definesSchemaProperty(String current, String remaining) {
277305
}
278306

279307
private boolean definesPatternProperty(String current, String remaining) {
280-
for (Pattern pattern : patternProperties.keySet()) {
281-
if (pattern.matcher(current).matches()) {
282-
if (remaining == null || patternProperties.get(pattern).definesProperty(remaining)) {
308+
for (Map.Entry<Regexp, Schema> entry : patternProperties.entrySet()) {
309+
Regexp pattern = entry.getKey();
310+
if (!pattern.patternMatchingFailure(current).isPresent()) {
311+
if (remaining == null || entry.getValue().definesProperty(remaining)) {
283312
return true;
284313
}
285314
}
@@ -373,10 +402,10 @@ void describePropertiesTo(JSONPrinter writer) {
373402
private void describePropertyDependenciesTo(JSONPrinter writer) {
374403
writer.key("dependencies");
375404
writer.object();
376-
propertyDependencies.entrySet().forEach(entry -> {
377-
writer.key(entry.getKey());
405+
propertyDependencies.forEach((key, value) -> {
406+
writer.key(key);
378407
writer.array();
379-
entry.getValue().forEach(writer::value);
408+
value.forEach(writer::value);
380409
writer.endArray();
381410
});
382411
writer.endObject();

core/src/main/java/org/everit/json/schema/ObjectSchemaValidatingVisitor.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33
import static java.lang.String.format;
44
import static java.util.Objects.requireNonNull;
55

6-
import com.google.re2j.Pattern;
76
import java.util.ArrayList;
87
import java.util.List;
98
import java.util.Set;
9+
10+
import org.everit.json.schema.regexp.Regexp;
1011
import org.json.JSONObject;
1112

1213
class ObjectSchemaValidatingVisitor extends Visitor {
@@ -119,21 +120,21 @@ private List<String> getAdditionalProperties() {
119120
}
120121

121122
private boolean matchesAnyPattern(String key) {
122-
for (Pattern pattern : schema.getPatternProperties().keySet()) {
123-
if (pattern.matcher(key).find()) {
123+
for (Regexp pattern : schema.getRegexpPatternProperties().keySet()) {
124+
if (!pattern.patternMatchingFailure(key).isPresent()) {
124125
return true;
125126
}
126127
}
127128
return false;
128129
}
129130

130-
@Override void visitPatternPropertySchema(Pattern propertyNamePattern, Schema schema) {
131+
@Override void visitPatternPropertySchema(Regexp propertyNamePattern, Schema schema) {
131132
String[] propNames = JSONObject.getNames(objSubject);
132133
if (propNames == null || propNames.length == 0) {
133134
return;
134135
}
135136
for (String propName : propNames) {
136-
if (propertyNamePattern.matcher(propName).find()) {
137+
if (!propertyNamePattern.patternMatchingFailure(propName).isPresent()) {
137138
ValidationException failure = owner.getFailureOfSchema(schema, objSubject.get(propName));
138139
if (failure != null) {
139140
owner.failure(failure.prepend(propName));

core/src/main/java/org/everit/json/schema/Visitor.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66

77
import org.everit.json.schema.regexp.Regexp;
88

9-
import com.google.re2j.Pattern;
10-
119
abstract class Visitor {
1210

1311
void visitNumberSchema(NumberSchema numberSchema) {
@@ -121,7 +119,7 @@ void visitObjectSchema(ObjectSchema objectSchema) {
121119
}
122120
visitAdditionalProperties(objectSchema.permitsAdditionalProperties());
123121
visitSchemaOfAdditionalProperties(objectSchema.getSchemaOfAdditionalProperties());
124-
for (Map.Entry<Pattern, Schema> entry : objectSchema.getPatternProperties().entrySet()) {
122+
for (Map.Entry<Regexp, Schema> entry : objectSchema.getRegexpPatternProperties().entrySet()) {
125123
visitPatternPropertySchema(entry.getKey(), entry.getValue());
126124
}
127125
for (Map.Entry<String, Schema> schemaDep : objectSchema.getSchemaDependencies().entrySet()) {
@@ -141,7 +139,7 @@ void visitPropertySchema(String properyName, Schema schema) {
141139
void visitSchemaDependency(String propKey, Schema schema) {
142140
}
143141

144-
void visitPatternPropertySchema(Pattern propertyNamePattern, Schema schema) {
142+
void visitPatternPropertySchema(Regexp propertyNamePattern, Schema schema) {
145143
}
146144

147145
void visitSchemaOfAdditionalProperties(Schema schemaOfAdditionalProperties) {

core/src/main/java/org/everit/json/schema/loader/ObjectSchemaLoader.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import org.everit.json.schema.ObjectSchema;
77
import org.everit.json.schema.Schema;
8+
import org.everit.json.schema.regexp.Regexp;
89

910
/**
1011
* @author erosb
@@ -40,7 +41,8 @@ ObjectSchema.Builder load() {
4041
.ifPresent(patternProps -> {
4142
patternProps.keySet().forEach(pattern -> {
4243
Schema patternSchema = defaultLoader.loadChild(patternProps.require(pattern)).build();
43-
builder.patternProperty(pattern, patternSchema);
44+
Regexp regexp = ls.config.regexpFactory.createHandler(pattern);
45+
builder.patternProperty(regexp, patternSchema);
4446
});
4547
});
4648
ls.schemaJson().maybe("dependencies").map(JsonValue::requireObject)

core/src/test/java/org/everit/json/schema/ObjectSchemaTest.java

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,26 +16,40 @@
1616
package org.everit.json.schema;
1717

1818
import static java.util.Arrays.asList;
19+
import static java.util.stream.Collectors.toMap;
1920
import static org.everit.json.schema.TestSupport.buildWithLocation;
2021
import static org.everit.json.schema.TestSupport.loadAsV6;
2122
import static org.junit.Assert.assertEquals;
2223
import static org.junit.Assert.assertTrue;
2324
import static org.junit.Assert.fail;
2425

25-
import com.google.re2j.Pattern;
26+
import java.util.AbstractMap;
27+
import java.util.HashMap;
2628
import java.util.List;
29+
import java.util.Map;
2730
import java.util.concurrent.Callable;
2831

2932
import org.everit.json.schema.loader.SchemaLoader;
3033
import org.json.JSONObject;
3134
import org.json.JSONPointer;
3235
import org.junit.Test;
3336

37+
import com.google.re2j.Pattern;
38+
3439
import nl.jqno.equalsverifier.EqualsVerifier;
3540
import nl.jqno.equalsverifier.Warning;
3641

3742
public class ObjectSchemaTest {
3843

44+
private static final Map<String, Schema> toStringToSchemaMap(Map<java.util.regex.Pattern, Schema> original) {
45+
return original.entrySet().stream()
46+
.map(entry -> new AbstractMap.SimpleEntry<>(entry.getKey().toString(), entry.getValue()))
47+
.collect(toMap(
48+
entry -> entry.getKey(),
49+
entry -> entry.getValue()
50+
));
51+
}
52+
3953
private static final JSONObject OBJECTS = ResourceLoader.DEFAULT.readObj("objecttestcases.json");
4054

4155
private ResourceLoader loader = ResourceLoader.DEFAULT;
@@ -241,6 +255,16 @@ public void patternPropertyOnEmptyObjct() {
241255
.build().validate(new JSONObject());
242256
}
243257

258+
@Test
259+
public void patternPropertyTranslation() {
260+
ObjectSchema subject = ObjectSchema.builder()
261+
.patternProperty(java.util.regex.Pattern.compile("b_.*"), BooleanSchema.INSTANCE)
262+
.build();
263+
Map<java.util.regex.Pattern, Schema> expected = new HashMap<>();
264+
expected.put(java.util.regex.Pattern.compile("b_.*"), BooleanSchema.INSTANCE);
265+
assertEquals(toStringToSchemaMap(expected), toStringToSchemaMap(subject.getPatternProperties()));
266+
}
267+
244268
@Test
245269
public void patternPropertyOverridesAdditionalPropSchema() {
246270
ObjectSchema.builder()

core/src/test/java/org/everit/json/schema/loader/DefinesPropertyTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package org.everit.json.schema.loader;
22

3+
import static org.junit.Assert.assertFalse;
4+
35
import org.everit.json.schema.BooleanSchema;
46
import org.everit.json.schema.CombinedSchema;
57
import org.everit.json.schema.ObjectSchema;
@@ -10,8 +12,6 @@
1012
import org.junit.Assert;
1113
import org.junit.Test;
1214

13-
import static org.junit.Assert.assertFalse;
14-
1515
public class DefinesPropertyTest {
1616

1717
private static JSONObject ALL_SCHEMAS = ResourceLoader.DEFAULT.readObj("testschemas.json");
@@ -53,7 +53,7 @@ public void patternPropertiesHasField() {
5353
Assert.assertTrue(actual.definesProperty("#/aaa"));
5454
Assert.assertTrue(actual.definesProperty("#/aaaa"));
5555
Assert.assertTrue(actual.definesProperty("#/aaaaa"));
56-
56+
5757
assertFalse(actual.definesProperty("b"));
5858
}
5959

core/src/test/resources/org/everit/jsonvalidator/testschemas.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"patternProperties": {
33
"patternProperties": {
4-
"a*": {
4+
"aa*": {
55
"type": "integer"
66
},
77
"aaa*": {

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>org.everit.json</groupId>
88
<artifactId>org.everit.json.schema.parent</artifactId>
9-
<version>1.9.0</version>
9+
<version>1.9.1</version>
1010

1111
<packaging>pom</packaging>
1212

tests/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
<parent>
2525
<groupId>org.everit.json</groupId>
2626
<artifactId>org.everit.json.schema.parent</artifactId>
27-
<version>1.9.0</version>
27+
<version>1.9.1</version>
2828
</parent>
2929

3030
<artifactId>org.everit.json.schema.tests</artifactId>

0 commit comments

Comments
 (0)