Skip to content

Commit ad3fa5c

Browse files
fduttonFaron Dutton
andauthored
Ignores siblings of $ref when dialect is Draft 4, 6 or 7 (#809)
Resolves #723 Co-authored-by: Faron Dutton <[email protected]>
1 parent b88ccc7 commit ad3fa5c

File tree

8 files changed

+265
-134
lines changed

8 files changed

+265
-134
lines changed

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import com.fasterxml.jackson.databind.JsonNode;
2020
import com.fasterxml.jackson.databind.node.ObjectNode;
2121
import com.networknt.schema.CollectorContext.Scope;
22+
import com.networknt.schema.SpecVersion.VersionFlag;
2223
import com.networknt.schema.ValidationContext.DiscriminatorContext;
2324
import com.networknt.schema.utils.StringUtils;
2425
import com.networknt.schema.walk.DefaultKeywordWalkListenerRunner;
@@ -38,6 +39,8 @@
3839
* constructed, it can be used to validate multiple json data concurrently.
3940
*/
4041
public class JsonSchema extends BaseJsonValidator {
42+
private static final long V201909_VALUE = VersionFlag.V201909.getVersionFlagValue();
43+
4144
private Map<String, JsonValidator> validators;
4245
private final JsonMetaSchema metaSchema;
4346
private boolean validatorsLoaded = false;
@@ -252,6 +255,8 @@ private Map<String, JsonValidator> read(JsonNode schemaNode) {
252255
validators.put(getSchemaPath() + "/false", validator);
253256
}
254257
} else {
258+
JsonValidator refValidator = null;
259+
255260
Iterator<String> pnames = schemaNode.fieldNames();
256261
while (pnames.hasNext()) {
257262
String pname = pnames.next();
@@ -262,6 +267,10 @@ private Map<String, JsonValidator> read(JsonNode schemaNode) {
262267
if (validator != null) {
263268
validators.put(getSchemaPath() + "/" + pname, validator);
264269

270+
if ("$ref".equals(pname)) {
271+
refValidator = validator;
272+
}
273+
265274
if ("required".equals(pname)) {
266275
this.requiredValidator = validator;
267276
}
@@ -272,10 +281,24 @@ private Map<String, JsonValidator> read(JsonNode schemaNode) {
272281
}
273282

274283
}
284+
285+
// Ignore siblings for older drafts
286+
if (null != refValidator && activeDialect() < V201909_VALUE) {
287+
validators.clear();
288+
validators.put(getSchemaPath() + "/$ref", refValidator);
289+
}
275290
}
291+
276292
return validators;
277293
}
278294

295+
private long activeDialect() {
296+
return this.validationContext
297+
.activeDialect()
298+
.map(VersionFlag::getVersionFlagValue)
299+
.orElse(Long.MAX_VALUE);
300+
}
301+
279302
/**
280303
* A comparator that sorts validators, such that 'properties' comes before 'required',
281304
* so that we can apply default values before validating required.

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

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@
1818

1919
import java.util.HashMap;
2020
import java.util.Map;
21+
import java.util.Optional;
2122
import java.util.Stack;
2223

2324
import com.fasterxml.jackson.databind.JsonNode;
2425
import com.fasterxml.jackson.databind.node.ObjectNode;
26+
import com.networknt.schema.SpecVersion.VersionFlag;
2527
import com.networknt.schema.uri.URIFactory;
2628
import com.networknt.schema.urn.URNFactory;
2729

@@ -31,8 +33,8 @@ public class ValidationContext {
3133
private final JsonMetaSchema metaSchema;
3234
private final JsonSchemaFactory jsonSchemaFactory;
3335
private SchemaValidatorsConfig config;
34-
private final Map<String, JsonSchemaRef> refParsingInProgress = new HashMap<String, JsonSchemaRef>();
35-
private final Stack<DiscriminatorContext> discriminatorContexts = new Stack<DiscriminatorContext>();
36+
private final Map<String, JsonSchemaRef> refParsingInProgress = new HashMap<>();
37+
private final Stack<DiscriminatorContext> discriminatorContexts = new Stack<>();
3638

3739
public ValidationContext(URIFactory uriFactory, URNFactory urnFactory, JsonMetaSchema metaSchema,
3840
JsonSchemaFactory jsonSchemaFactory, SchemaValidatorsConfig config) {
@@ -58,11 +60,11 @@ public JsonSchema newSchema(String schemaPath, JsonNode schemaNode, JsonSchema p
5860

5961
public JsonValidator newValidator(String schemaPath, String keyword /* keyword */, JsonNode schemaNode,
6062
JsonSchema parentSchema, String customMessage) {
61-
return metaSchema.newValidator(this, schemaPath, keyword, schemaNode, parentSchema, customMessage);
63+
return this.metaSchema.newValidator(this, schemaPath, keyword, schemaNode, parentSchema, customMessage);
6264
}
6365

6466
public String resolveSchemaId(JsonNode schemaNode) {
65-
return metaSchema.readId(schemaNode);
67+
return this.metaSchema.readId(schemaNode);
6668
}
6769

6870
public URIFactory getURIFactory() {
@@ -74,66 +76,71 @@ public URNFactory getURNFactory() {
7476
}
7577

7678
public JsonSchemaFactory getJsonSchemaFactory() {
77-
return jsonSchemaFactory;
79+
return this.jsonSchemaFactory;
7880
}
7981

8082
public SchemaValidatorsConfig getConfig() {
81-
if (config == null) {
82-
config = new SchemaValidatorsConfig();
83+
if (this.config == null) {
84+
this.config = new SchemaValidatorsConfig();
8385
}
84-
return config;
86+
return this.config;
8587
}
8688

8789
public void setConfig(SchemaValidatorsConfig config) {
8890
this.config = config;
8991
}
9092

9193
public void setReferenceParsingInProgress(String refValue, JsonSchemaRef ref) {
92-
refParsingInProgress.put(refValue, ref);
94+
this.refParsingInProgress.put(refValue, ref);
9395
}
9496

9597
public JsonSchemaRef getReferenceParsingInProgress(String refValue) {
96-
return refParsingInProgress.get(refValue);
98+
return this.refParsingInProgress.get(refValue);
9799
}
98100

99101
public DiscriminatorContext getCurrentDiscriminatorContext() {
100-
if (!discriminatorContexts.empty()) {
101-
return discriminatorContexts.peek();
102+
if (!this.discriminatorContexts.empty()) {
103+
return this.discriminatorContexts.peek();
102104
}
103105
return null; // this is the case when we get on a schema that has a discriminator, but it's not used in anyOf
104106
}
105107

106-
public void enterDiscriminatorContext(final DiscriminatorContext ctx, String at) {
107-
discriminatorContexts.push(ctx);
108+
public void enterDiscriminatorContext(final DiscriminatorContext ctx, @SuppressWarnings("unused") String at) {
109+
this.discriminatorContexts.push(ctx);
108110
}
109111

110-
public void leaveDiscriminatorContextImmediately(String at) {
111-
discriminatorContexts.pop();
112+
public void leaveDiscriminatorContextImmediately(@SuppressWarnings("unused") String at) {
113+
this.discriminatorContexts.pop();
112114
}
113115

114116
public JsonMetaSchema getMetaSchema() {
115-
return metaSchema;
117+
return this.metaSchema;
118+
}
119+
120+
public Optional<VersionFlag> activeDialect() {
121+
String metaSchema = getMetaSchema().getUri();
122+
return SpecVersionDetector.detectOptionalVersion(metaSchema);
116123
}
117124

118125
public static class DiscriminatorContext {
119-
private final Map<String, ObjectNode> discriminators = new HashMap<String, ObjectNode>();
126+
private final Map<String, ObjectNode> discriminators = new HashMap<>();
120127

121128
private boolean discriminatorMatchFound = false;
122129

123130
public void registerDiscriminator(final String schemaPath, final ObjectNode discriminator) {
124-
discriminators.put(schemaPath, discriminator);
131+
this.discriminators.put(schemaPath, discriminator);
125132
}
126133

127134
public ObjectNode getDiscriminatorForPath(final String schemaPath) {
128-
return discriminators.get(schemaPath);
135+
return this.discriminators.get(schemaPath);
129136
}
130137

131138
public void markMatch() {
132-
discriminatorMatchFound = true;
139+
this.discriminatorMatchFound = true;
133140
}
134141

135142
public boolean isDiscriminatorMatchFound() {
136-
return discriminatorMatchFound;
143+
return this.discriminatorMatchFound;
137144
}
138145

139146
/**
@@ -142,7 +149,7 @@ public boolean isDiscriminatorMatchFound() {
142149
* @return true in case there are discriminator candidates
143150
*/
144151
public boolean isActive() {
145-
return !discriminators.isEmpty();
152+
return !this.discriminators.isEmpty();
146153
}
147154
}
148155
}

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

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ private void disableV202012Tests() {
7474
this.disabled.put(Paths.get("src/test/suite/tests/draft2020-12/dynamicRef.json"), "Unsupported behavior");
7575
this.disabled.put(Paths.get("src/test/suite/tests/draft2020-12/id.json"), "Unsupported behavior");
7676
this.disabled.put(Paths.get("src/test/suite/tests/draft2020-12/optional/format-assertion.json"), "Unsupported behavior");
77-
this.disabled.put(Paths.get("src/test/suite/tests/draft2020-12/ref.json"), "Unsupported behavior");
7877
this.disabled.put(Paths.get("src/test/suite/tests/draft2020-12/vocabulary.json"), "Unsupported behavior");
7978
}
8079

@@ -83,23 +82,21 @@ private void disableV201909Tests() {
8382
this.disabled.put(Paths.get("src/test/suite/tests/draft2019-09/defs.json"), "Unsupported behavior");
8483
this.disabled.put(Paths.get("src/test/suite/tests/draft2019-09/id.json"), "Unsupported behavior");
8584
this.disabled.put(Paths.get("src/test/suite/tests/draft2019-09/recursiveRef.json"), "Unsupported behavior");
86-
this.disabled.put(Paths.get("src/test/suite/tests/draft2019-09/ref.json"), "Unsupported behavior");
8785
this.disabled.put(Paths.get("src/test/suite/tests/draft2019-09/vocabulary.json"), "Unsupported behavior");
8886
}
8987

9088
private void disableV7Tests() {
9189
this.disabled.put(Paths.get("src/test/suite/tests/draft7/anchor.json"), "Unsupported behavior");
9290
this.disabled.put(Paths.get("src/test/suite/tests/draft7/defs.json"), "Unsupported behavior");
9391
this.disabled.put(Paths.get("src/test/suite/tests/draft7/optional/content.json"), "Unsupported behavior");
94-
this.disabled.put(Paths.get("src/test/suite/tests/draft7/ref.json"), "Unsupported behavior");
9592
}
9693

9794
private void disableV6Tests() {
98-
this.disabled.put(Paths.get("src/test/suite/tests/draft6/ref.json"), "Unsupported behavior");
99-
}
95+
// nothing here
96+
}
10097

10198
private void disableV4Tests() {
102-
this.disabled.put(Paths.get("src/test/suite/tests/draft4/ref.json"), "Unsupported behavior");
99+
// nothing here
103100
}
104101

105102
}

0 commit comments

Comments
 (0)