Skip to content

Commit da3b9f2

Browse files
committed
Refactor NodePath
1 parent 142d92f commit da3b9f2

17 files changed

+334
-89
lines changed

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

Lines changed: 12 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,7 @@
2020
/**
2121
* Represents a path to a JSON node.
2222
*/
23-
public class NodePath implements Comparable<NodePath> {
24-
private final PathType type;
23+
public abstract class NodePath implements Comparable<NodePath> {
2524
private final NodePath parent;
2625

2726
private final String pathSegment;
@@ -30,23 +29,20 @@ public class NodePath implements Comparable<NodePath> {
3029
private volatile String value = null; // computed lazily
3130
private int hash = 0; // computed lazily
3231

33-
public NodePath(PathType type) {
34-
this.type = type;
32+
public NodePath() {
3533
this.parent = null;
3634
this.pathSegment = null;
3735
this.pathSegmentIndex = -1;
3836
}
3937

40-
private NodePath(NodePath parent, String pathSegment) {
38+
protected NodePath(NodePath parent, String pathSegment) {
4139
this.parent = parent;
42-
this.type = parent.type;
4340
this.pathSegment = pathSegment;
4441
this.pathSegmentIndex = -1;
4542
}
4643

47-
private NodePath(NodePath parent, int pathSegmentIndex) {
44+
protected NodePath(NodePath parent, int pathSegmentIndex) {
4845
this.parent = parent;
49-
this.type = parent.type;
5046
this.pathSegment = null;
5147
this.pathSegmentIndex = pathSegmentIndex;
5248
}
@@ -66,28 +62,22 @@ public NodePath getParent() {
6662
* @param token the child token
6763
* @return the path
6864
*/
69-
public NodePath append(String token) {
70-
return new NodePath(this, token);
71-
}
65+
public abstract NodePath append(String token);
7266

7367
/**
7468
* Append the index to the path.
7569
*
7670
* @param index the index
7771
* @return the path
7872
*/
79-
public NodePath append(int index) {
80-
return new NodePath(this, index);
81-
}
73+
public abstract NodePath append(int index);
8274

8375
/**
8476
* Gets the {@link PathType}.
8577
*
8678
* @return the path type
8779
*/
88-
public PathType getPathType() {
89-
return this.type;
90-
}
80+
public abstract PathType getPathType();
9181

9282
/**
9383
* Gets the name element given an index.
@@ -202,11 +192,11 @@ public boolean contains(String segment) {
202192
@Override
203193
public String toString() {
204194
if (this.value == null) {
205-
String parentValue = this.parent == null ? type.getRoot() : this.parent.toString();
195+
String parentValue = this.parent == null ? getPathType().getRoot() : this.parent.toString();
206196
if (pathSegmentIndex != -1) {
207-
this.value = this.type.append(parentValue, pathSegmentIndex);
197+
this.value = this.getPathType().append(parentValue, pathSegmentIndex);
208198
} else if (pathSegment != null) {
209-
this.value = this.type.append(parentValue, pathSegment);
199+
this.value = this.getPathType().append(parentValue, pathSegment);
210200
} else {
211201
this.value = parentValue;
212202
}
@@ -218,7 +208,7 @@ public String toString() {
218208
public int hashCode() {
219209
int h = hash;
220210
if (h == 0) {
221-
h = Objects.hash(parent, pathSegment, pathSegmentIndex, type);
211+
h = Objects.hash(parent, pathSegment, pathSegmentIndex, getPathType());
222212
hash = h;
223213
}
224214
return h;
@@ -234,7 +224,7 @@ public boolean equals(Object obj) {
234224
return false;
235225
NodePath other = (NodePath) obj;
236226
return Objects.equals(pathSegment, other.pathSegment) && pathSegmentIndex == other.pathSegmentIndex
237-
&& type == other.type && Objects.equals(parent, other.parent);
227+
&& getPathType() == other.getPathType() && Objects.equals(parent, other.parent);
238228
}
239229

240230
@Override

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

Lines changed: 1 addition & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -120,26 +120,6 @@ private static Schema obtainSubSchemaNode(final JsonNode schemaNode, final Schem
120120
final SchemaLocation schemaLocation = SchemaLocation.of(node.textValue());
121121
return schemaContext.getSchemaRegistry().getSchema(schemaLocation);
122122
}
123-
public static class JsonNodePathLegacy {
124-
private static final NodePath INSTANCE = new NodePath(PathType.LEGACY);
125-
public static NodePath getInstance() {
126-
return INSTANCE;
127-
}
128-
}
129-
130-
public static class JsonNodePathJsonPointer {
131-
private static final NodePath INSTANCE = new NodePath(PathType.JSON_POINTER);
132-
public static NodePath getInstance() {
133-
return INSTANCE;
134-
}
135-
}
136-
137-
public static class JsonNodePathJsonPath {
138-
private static final NodePath INSTANCE = new NodePath(PathType.JSON_PATH);
139-
public static NodePath getInstance() {
140-
return INSTANCE;
141-
}
142-
}
143123

144124
public void validate(ExecutionContext executionContext, JsonNode node) {
145125
validate(executionContext, node, node, atRoot());
@@ -151,14 +131,7 @@ public void validate(ExecutionContext executionContext, JsonNode node) {
151131
* @return The path.
152132
*/
153133
protected NodePath atRoot() {
154-
if (this.schemaContext.getSchemaRegistryConfig().getPathType().equals(PathType.JSON_POINTER)) {
155-
return JsonNodePathJsonPointer.getInstance();
156-
} else if (this.schemaContext.getSchemaRegistryConfig().getPathType().equals(PathType.LEGACY)) {
157-
return JsonNodePathLegacy.getInstance();
158-
} else if (this.schemaContext.getSchemaRegistryConfig().getPathType().equals(PathType.JSON_PATH)) {
159-
return JsonNodePathJsonPath.getInstance();
160-
}
161-
return new NodePath(this.schemaContext.getSchemaRegistryConfig().getPathType());
134+
return this.schemaContext.getSchemaRegistryConfig().getNodePathFactory().get();
162135
}
163136

164137
static Schema from(SchemaContext schemaContext, SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, Schema parent, boolean suppressSubSchemaRetrieval) {

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,18 @@
2020
import java.nio.charset.StandardCharsets;
2121
import java.util.Objects;
2222

23+
import com.networknt.schema.path.JsonPointer;
24+
import com.networknt.schema.path.UriReferencePath;
25+
2326
/**
2427
* The schema location is the canonical IRI of the schema object plus a JSON
2528
* Pointer fragment indicating the subschema that produced a result. In contrast
2629
* with the evaluation path, the schema location MUST NOT include by-reference
2730
* applicators such as $ref or $dynamicRef.
2831
*/
2932
public class SchemaLocation {
30-
private static final NodePath JSON_POINTER = new NodePath(PathType.JSON_POINTER);
31-
private static final NodePath ANCHOR = new NodePath(PathType.URI_REFERENCE);
33+
private static final NodePath JSON_POINTER = JsonPointer.getRoot();
34+
private static final NodePath ANCHOR = UriReferencePath.getRoot();
3235

3336
/**
3437
* Represents a relative schema location to the current document.

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ public static Builder builder(final SchemaRegistry blueprint) {
292292
protected Schema newSchema(final SchemaLocation schemaUri, final JsonNode schemaNode) {
293293
final SchemaContext schemaContext = createSchemaContext(schemaNode);
294294
Schema jsonSchema = doCreate(schemaContext, getSchemaLocation(schemaUri),
295-
new NodePath(schemaContext.getSchemaRegistryConfig().getPathType()), schemaNode, null, false);
295+
schemaContext.getSchemaRegistryConfig().getNodePathFactory().get(), schemaNode, null, false);
296296
preload(jsonSchema);
297297
return jsonSchema;
298298
}
@@ -527,7 +527,7 @@ protected Schema getMappedSchema(final SchemaLocation schemaUri) {
527527
}
528528

529529
final Dialect dialect = getDialectOrDefault(schemaNode);
530-
NodePath evaluationPath = new NodePath(getSchemaRegistryConfig().getPathType());
530+
NodePath evaluationPath = getSchemaRegistryConfig().getNodePathFactory().get();
531531
if (schemaUri.getFragment() == null
532532
|| schemaUri.getFragment().getNameCount() == 0) {
533533
// Schema without fragment

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

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import com.networknt.schema.i18n.DefaultMessageSource;
2020
import com.networknt.schema.i18n.MessageSource;
21+
import com.networknt.schema.path.JsonPointer;
2122
import com.networknt.schema.regex.ECMAScriptRegularExpressionFactory;
2223
import com.networknt.schema.regex.JDKRegularExpressionFactory;
2324
import com.networknt.schema.regex.RegularExpressionFactory;
@@ -26,6 +27,7 @@
2627
import java.util.Locale;
2728
import java.util.Map;
2829
import java.util.Objects;
30+
import java.util.function.Supplier;
2931

3032
/**
3133
* Configuration for SchemaRegistry that applies to all the schemas its
@@ -98,7 +100,7 @@ public static SchemaRegistryConfig getInstance() {
98100
/**
99101
* The approach used to generate paths in reported messages, logs and errors. Default is the legacy "JSONPath-like" approach.
100102
*/
101-
private final PathType pathType;
103+
private final Supplier<NodePath> nodePathFactory;
102104

103105
/**
104106
* Controls if the schema will automatically be preloaded.
@@ -140,7 +142,7 @@ protected SchemaRegistryConfig(boolean cacheRefs,
140142
Boolean formatAssertionsEnabled,
141143
boolean javaSemantics,
142144
Locale locale, boolean losslessNarrowing,
143-
MessageSource messageSource, PathType pathType,
145+
MessageSource messageSource, Supplier<NodePath> nodePathFactory,
144146
boolean preloadSchema, int preloadSchemaRefMaxNestingDepth,
145147
RegularExpressionFactory regularExpressionFactory, SchemaIdValidator schemaIdValidator,
146148
Map<String, Boolean> strictness, boolean typeLoose) {
@@ -154,7 +156,7 @@ protected SchemaRegistryConfig(boolean cacheRefs,
154156
this.locale = locale;
155157
this.losslessNarrowing = losslessNarrowing;
156158
this.messageSource = messageSource;
157-
this.pathType = pathType;
159+
this.nodePathFactory = nodePathFactory;
158160
this.preloadSchema = preloadSchema;
159161
this.preloadSchemaRefMaxNestingDepth = preloadSchemaRefMaxNestingDepth;
160162
this.regularExpressionFactory = regularExpressionFactory;
@@ -216,8 +218,8 @@ public MessageSource getMessageSource() {
216218
*
217219
* @return The path generation approach.
218220
*/
219-
public PathType getPathType() {
220-
return this.pathType;
221+
public Supplier<NodePath> getNodePathFactory() {
222+
return this.nodePathFactory;
221223
}
222224

223225
/**
@@ -349,7 +351,7 @@ public static Builder builder(SchemaRegistryConfig config) {
349351
builder.locale = config.locale;
350352
builder.losslessNarrowing = config.losslessNarrowing;
351353
builder.messageSource = config.messageSource;
352-
builder.pathType = config.pathType;
354+
builder.nodePathFactory = config.nodePathFactory;
353355
builder.preloadSchema = config.preloadSchema;
354356
builder.preloadSchemaRefMaxNestingDepth = config.preloadSchemaRefMaxNestingDepth;
355357
builder.regularExpressionFactory = config.regularExpressionFactory;
@@ -382,7 +384,7 @@ public static abstract class BuilderSupport<T> {
382384
protected Locale locale = null; // This must be null to use Locale.getDefault() as the default can be changed
383385
protected boolean losslessNarrowing = false;
384386
protected MessageSource messageSource = null;
385-
protected PathType pathType = PathType.JSON_POINTER;
387+
protected Supplier<NodePath> nodePathFactory = JsonPointer::getRoot;
386388
protected boolean preloadSchema = true;
387389
protected int preloadSchemaRefMaxNestingDepth = DEFAULT_PRELOAD_SCHEMA_REF_MAX_NESTING_DEPTH;
388390
protected RegularExpressionFactory regularExpressionFactory = JDKRegularExpressionFactory.getInstance();
@@ -497,13 +499,13 @@ public T messageSource(MessageSource messageSource) {
497499
/**
498500
* Sets the path type to use when reporting the instance location of errors.
499501
* <p>
500-
* Defaults to {@link PathType#JSON_POINTER}.
502+
* Defaults to {@link JsonPointer#getRoot()}.
501503
*
502-
* @param pathType the path type
503-
* @return the path type
504+
* @param nodePathFactory the node path factory
505+
* @return the node path factory
504506
*/
505-
public T pathType(PathType pathType) {
506-
this.pathType = pathType;
507+
public T nodePathFactory(Supplier<NodePath> nodePathFactory) {
508+
this.nodePathFactory = nodePathFactory;
507509
return self();
508510
}
509511
/**
@@ -575,7 +577,7 @@ public SchemaRegistryConfig build() {
575577
return new SchemaRegistryConfig(cacheRefs, errorMessageKeyword,
576578
executionContextCustomizer, failFast, formatAssertionsEnabled,
577579
javaSemantics, locale, losslessNarrowing, messageSource,
578-
pathType, preloadSchema, preloadSchemaRefMaxNestingDepth,
580+
nodePathFactory, preloadSchema, preloadSchemaRefMaxNestingDepth,
579581
regularExpressionFactory, schemaIdValidator, strictness, typeLoose
580582
);
581583
}

src/main/java/com/networknt/schema/output/HierarchicalOutputUnitFormatter.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -108,19 +108,20 @@ public static OutputUnit format(OutputUnit root, OutputUnitData data, NodePath r
108108
return root;
109109
}
110110

111-
public static OutputUnit format(Schema jsonSchema, List<Error> errors,
111+
public static OutputUnit format(Schema schema, List<Error> errors,
112112
ExecutionContext executionContext, SchemaContext schemaContext,
113113
Function<Error, Object> errorMapper) {
114114
OutputUnit root = new OutputUnit();
115115
root.setValid(errors.isEmpty());
116-
117-
root.setInstanceLocation(schemaContext.getSchemaRegistryConfig().getPathType().getRoot());
118-
root.setEvaluationPath(schemaContext.getSchemaRegistryConfig().getPathType().getRoot());
119-
root.setSchemaLocation(jsonSchema.getSchemaLocation().toString());
116+
NodePath rootNodePath = schemaContext.getSchemaRegistryConfig().getNodePathFactory().get();
117+
String rootPath = rootNodePath.getPathType().getRoot();
118+
root.setInstanceLocation(rootPath);
119+
root.setEvaluationPath(rootPath);
120+
root.setSchemaLocation(schema.getSchemaLocation().toString());
120121

121122
OutputUnitData data = OutputUnitData.from(errors, executionContext, errorMapper);
122123

123-
return format(root, data, new NodePath(schemaContext.getSchemaRegistryConfig().getPathType()));
124+
return format(root, data, rootNodePath);
124125
}
125126

126127
/**
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright (c) 2025 the original author or authors.
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+
package com.networknt.schema.path;
17+
18+
import com.networknt.schema.NodePath;
19+
import com.networknt.schema.PathType;
20+
21+
/**
22+
* Json Path.
23+
*/
24+
public final class JsonPath extends NodePath {
25+
private static class Holder {
26+
private static JsonPath INSTANCE = new JsonPath();
27+
}
28+
29+
public static JsonPath getRoot() {
30+
return Holder.INSTANCE;
31+
}
32+
33+
public JsonPath() {
34+
super();
35+
}
36+
37+
public JsonPath(JsonPath jsonPath, String token) {
38+
super(jsonPath, token);
39+
}
40+
41+
public JsonPath(JsonPath jsonPath, int token) {
42+
super(jsonPath, token);
43+
}
44+
45+
@Override
46+
public NodePath append(String token) {
47+
return new JsonPath(this, token);
48+
}
49+
50+
@Override
51+
public NodePath append(int index) {
52+
return new JsonPath(this, index);
53+
}
54+
55+
@Override
56+
public PathType getPathType() {
57+
return PathType.JSON_PATH;
58+
}
59+
}

0 commit comments

Comments
 (0)