Skip to content

Commit 8fce164

Browse files
authored
Support fragment references using $anchor (#500)
* refactor: use meta schema to get fragment ref node * resolve $anchor instead of $id for fragment ref when meta schema uses it
1 parent 4b5f7aa commit 8fce164

File tree

2 files changed

+28
-32
lines changed

2 files changed

+28
-32
lines changed

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

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,31 @@ public static Builder builder(String uri, JsonMetaSchema blueprint) {
361361
}
362362

363363
public String readId(JsonNode schemaNode) {
364-
JsonNode idNode = schemaNode.get(idKeyword);
364+
return readText(schemaNode, idKeyword);
365+
}
366+
367+
public JsonNode getNodeByFragmentRef(String ref, JsonNode node) {
368+
boolean supportsAnchor = keywords.containsKey("$anchor");
369+
String refName = supportsAnchor ? ref.substring(1) : ref;
370+
String fieldToRead = supportsAnchor ? "$anchor" : idKeyword;
371+
372+
boolean nodeContainsRef = refName.equals(readText(node, fieldToRead));
373+
if (nodeContainsRef) {
374+
return node;
375+
} else {
376+
Iterator<JsonNode> children = node.elements();
377+
while (children.hasNext()) {
378+
JsonNode refNode = getNodeByFragmentRef(ref, children.next());
379+
if (refNode != null) {
380+
return refNode;
381+
}
382+
}
383+
}
384+
return null;
385+
}
386+
387+
private String readText(JsonNode node, String field) {
388+
JsonNode idNode = node.get(field);
365389
if (idNode == null || !idNode.isTextual()) {
366390
return null;
367391
}
@@ -372,10 +396,6 @@ public String getUri() {
372396
return uri;
373397
}
374398

375-
public String getIdKeyword() {
376-
return idKeyword;
377-
}
378-
379399

380400
public JsonValidator newValidator(ValidationContext validationContext, String schemaPath, String keyword /* keyword */, JsonNode schemaNode,
381401
JsonSchema parentSchema, String customMessage) {

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

Lines changed: 3 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
import java.net.URLDecoder;
2222
import java.util.Collections;
2323
import java.util.Comparator;
24-
import java.util.HashMap;
2524
import java.util.Iterator;
2625
import java.util.LinkedHashSet;
2726
import java.util.Map;
@@ -46,8 +45,8 @@
4645
public class JsonSchema extends BaseJsonValidator {
4746
private static final Pattern intPattern = Pattern.compile("^[0-9]+$");
4847
private Map<String, JsonValidator> validators;
49-
private final String idKeyword;
5048
private final ValidationContext validationContext;
49+
private final JsonMetaSchema metaSchema;
5150
private boolean validatorsLoaded = false;
5251

5352
/**
@@ -82,7 +81,7 @@ private JsonSchema(ValidationContext validationContext, String schemaPath, URI c
8281
validationContext.getConfig() != null && validationContext.getConfig().isFailFast(),
8382
validationContext.getConfig() != null ? validationContext.getConfig().getApplyDefaultsStrategy() : null);
8483
this.validationContext = validationContext;
85-
this.idKeyword = validationContext.getMetaSchema().getIdKeyword();
84+
this.metaSchema = validationContext.getMetaSchema();
8685
this.currentUri = this.combineCurrentUriWithIds(currentUri, schemaNode);
8786
if (validationContext.getConfig() != null) {
8887
if (validationContext.getConfig().isOpenAPI3StyleDiscriminators()) {
@@ -156,7 +155,7 @@ public JsonNode getRefSchemaNode(String ref) {
156155
}
157156
}
158157
} else if (ref.startsWith("#") && ref.length() > 1) {
159-
node = getNodeById(ref, node);
158+
node = metaSchema.getNodeByFragmentRef(ref, node);
160159
if (node == null) {
161160
node = handleNullNode(ref, schema);
162161
}
@@ -180,29 +179,6 @@ private JsonNode handleNullNode(String ref, JsonSchema schema) {
180179
return null;
181180
}
182181

183-
private JsonNode getNodeById(String ref, JsonNode node) {
184-
if (nodeContainsRef(ref, node)) {
185-
return node;
186-
} else {
187-
Iterator<JsonNode> children = node.elements();
188-
while (children.hasNext()) {
189-
JsonNode refNode = getNodeById(ref, children.next());
190-
if (refNode != null) {
191-
return refNode;
192-
}
193-
}
194-
}
195-
return null;
196-
}
197-
198-
private boolean nodeContainsRef(String ref, JsonNode node) {
199-
JsonNode id = node.get(idKeyword);
200-
if (id != null) {
201-
return ref.equals(id.asText());
202-
}
203-
return false;
204-
}
205-
206182
/**
207183
* Please note that the key in {@link #validators} map is a schema path. It is
208184
* used in {@link com.networknt.schema.walk.DefaultKeywordWalkListenerRunner} to derive the keyword.

0 commit comments

Comments
 (0)