Skip to content

Commit

Permalink
Makes JsonSchemaFactory solely responsible for creating JsonSchema in…
Browse files Browse the repository at this point in the history
…stances. (#781)

* Adds support for cross-draft validation

Resolves #778

* Makes JsonSchemaFactory solely responsible for creating JsonSchema instances.

Resolves #780

---------

Co-authored-by: Faron Dutton <[email protected]>
  • Loading branch information
fdutton and Faron Dutton authored May 22, 2023
1 parent 3cf9bb6 commit 77cd232
Show file tree
Hide file tree
Showing 23 changed files with 70 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public AdditionalPropertiesValidator(String schemaPath, JsonNode schemaNode, Jso
additionalPropertiesSchema = null;
} else if (schemaNode.isObject()) {
allowAdditionalProperties = true;
additionalPropertiesSchema = new JsonSchema(validationContext, getValidatorType().getValue(), parentSchema.getCurrentUri(), schemaNode, parentSchema);
additionalPropertiesSchema = validationContext.newSchema(getValidatorType().getValue(), schemaNode, parentSchema);
} else {
allowAdditionalProperties = false;
additionalPropertiesSchema = null;
Expand Down
6 changes: 1 addition & 5 deletions src/main/java/com/networknt/schema/AllOfValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,7 @@ public AllOfValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentS
this.validationContext = validationContext;
int size = schemaNode.size();
for (int i = 0; i < size; i++) {
this.schemas.add(new JsonSchema(validationContext,
schemaPath + "/" + i,
parentSchema.getCurrentUri(),
schemaNode.get(i),
parentSchema));
this.schemas.add(validationContext.newSchema(schemaPath + "/" + i, schemaNode.get(i), parentSchema));
}
}

Expand Down
6 changes: 1 addition & 5 deletions src/main/java/com/networknt/schema/AnyOfValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,7 @@ public AnyOfValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentS
this.validationContext = validationContext;
int size = schemaNode.size();
for (int i = 0; i < size; i++) {
this.schemas.add(new JsonSchema(validationContext,
schemaPath + "/" + i,
parentSchema.getCurrentUri(),
schemaNode.get(i),
parentSchema));
this.schemas.add(validationContext.newSchema(schemaPath + "/" + i, schemaNode.get(i), parentSchema));
}

if (this.validationContext.getConfig().isOpenAPI3StyleDiscriminators()) {
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/networknt/schema/BaseJsonValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public abstract class BaseJsonValidator implements JsonValidator {
protected String schemaPath;
protected JsonNode schemaNode;
protected JsonSchema parentSchema;
private final boolean suppressSubSchemaRetrieval;
protected final boolean suppressSubSchemaRetrieval;
private ValidatorTypeCode validatorType;
private ErrorMessageType errorMessageType;
protected ValidationContext validationContext;
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/networknt/schema/ContainsValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public ContainsValidator(String schemaPath, JsonNode schemaNode, JsonSchema pare
isMinV201909 = MinV201909.getVersions().contains(SpecVersionDetector.detectOptionalVersion(validationContext.getMetaSchema().getUri()).orElse(DEFAULT_VERSION));

if (schemaNode.isObject() || schemaNode.isBoolean()) {
this.schema = new JsonSchema(validationContext, getValidatorType().getValue(), parentSchema.getCurrentUri(), schemaNode, parentSchema);
this.schema = validationContext.newSchema(getValidatorType().getValue(), schemaNode, parentSchema);

JsonNode parentSchemaNode = parentSchema.getSchemaNode();
Optional.ofNullable(parentSchemaNode.get(ValidatorTypeCode.MAX_CONTAINS.getValue()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public DependenciesValidator(String schemaPath, JsonNode schemaNode, JsonSchema
depsProps.add(pvalue.get(i).asText());
}
} else if (pvalue.isObject() || pvalue.isBoolean()) {
schemaDeps.put(pname, new JsonSchema(validationContext, pname, parentSchema.getCurrentUri(), pvalue, parentSchema));
schemaDeps.put(pname, validationContext.newSchema(pname, pvalue, parentSchema));
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/networknt/schema/DependentSchemas.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public DependentSchemas(String schemaPath, JsonNode schemaNode, JsonSchema paren
String pname = it.next();
JsonNode pvalue = schemaNode.get(pname);
if (pvalue.isObject() || pvalue.isBoolean()) {
schemaDependencies.put(pname, new JsonSchema(validationContext, pname, parentSchema.getCurrentUri(), pvalue, parentSchema));
schemaDependencies.put(pname, validationContext.newSchema(pname, pvalue, parentSchema));
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/main/java/com/networknt/schema/IfValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,11 @@ public IfValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentSche
final JsonNode node = schemaNode.get(keyword);
final String schemaPathOfSchema = parentSchema.schemaPath + "/" + keyword;
if (keyword.equals("if")) {
foundIfSchema = new JsonSchema(validationContext, schemaPathOfSchema, parentSchema.getCurrentUri(), node, parentSchema);
foundIfSchema = validationContext.newSchema(schemaPathOfSchema, node, parentSchema);
} else if (keyword.equals("then") && node != null) {
foundThenSchema = new JsonSchema(validationContext, schemaPathOfSchema, parentSchema.getCurrentUri(), node, parentSchema);
foundThenSchema = validationContext.newSchema(schemaPathOfSchema, node, parentSchema);
} else if (keyword.equals("else") && node != null) {
foundElseSchema = new JsonSchema(validationContext, schemaPathOfSchema, parentSchema.getCurrentUri(), node, parentSchema);
foundElseSchema = validationContext.newSchema(schemaPathOfSchema, node, parentSchema);
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/main/java/com/networknt/schema/ItemsValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,18 @@ public ItemsValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentS
JsonSchema foundAdditionalSchema = null;

if (schemaNode.isObject() || schemaNode.isBoolean()) {
foundSchema = new JsonSchema(validationContext, schemaPath, parentSchema.getCurrentUri(), schemaNode, parentSchema);
foundSchema = validationContext.newSchema(schemaPath, schemaNode, parentSchema);
} else {
for (JsonNode s : schemaNode) {
this.tupleSchema.add(new JsonSchema(validationContext, schemaPath, parentSchema.getCurrentUri(), s, parentSchema));
this.tupleSchema.add(validationContext.newSchema(schemaPath, s, parentSchema));
}

JsonNode addItemNode = getParentSchema().getSchemaNode().get(PROPERTY_ADDITIONAL_ITEMS);
if (addItemNode != null) {
if (addItemNode.isBoolean()) {
this.additionalItems = addItemNode.asBoolean();
} else if (addItemNode.isObject()) {
foundAdditionalSchema = new JsonSchema(validationContext, "#", parentSchema.getCurrentUri(), addItemNode, parentSchema);
foundAdditionalSchema = validationContext.newSchema("#", addItemNode, parentSchema);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public ItemsValidator202012(String schemaPath, JsonNode schemaNode, JsonSchema p
}

if (schemaNode.isObject() || schemaNode.isBoolean()) {
this.schema = new JsonSchema(validationContext, schemaPath, parentSchema.getCurrentUri(), schemaNode, parentSchema);
this.schema = validationContext.newSchema(schemaPath, schemaNode, parentSchema);
} else {
throw new IllegalArgumentException("The value of 'items' MUST be a valid JSON Schema.");
}
Expand Down
22 changes: 21 additions & 1 deletion src/main/java/com/networknt/schema/JsonSchema.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,31 @@ public class JsonSchema extends BaseJsonValidator {

WalkListenerRunner keywordWalkListenerRunner = null;

static JsonSchema from(ValidationContext validationContext, String schemaPath, URI currentUri, JsonNode schemaNode, JsonSchema parent, boolean suppressSubSchemaRetrieval) {
return new JsonSchema(validationContext, schemaPath, currentUri, schemaNode, parent, suppressSubSchemaRetrieval);
}

/**
* @deprecated Use {@code JsonSchemaFactory#create(ValidationContext, String, JsonNode, JsonSchema)}
*/
@Deprecated
public JsonSchema(ValidationContext validationContext, URI baseUri, JsonNode schemaNode) {
this(validationContext, "#", baseUri, schemaNode, null);
}

/**
* @deprecated Use {@code JsonSchemaFactory#create(ValidationContext, String, JsonNode, JsonSchema)}
*/
@Deprecated
public JsonSchema(ValidationContext validationContext, String schemaPath, URI currentUri, JsonNode schemaNode,
JsonSchema parent) {
this(validationContext, schemaPath, currentUri, schemaNode, parent, false);
}

/**
* @deprecated Use {@code JsonSchemaFactory#create(ValidationContext, String, JsonNode, JsonSchema)}
*/
@Deprecated
public JsonSchema(ValidationContext validationContext, URI baseUri, JsonNode schemaNode, boolean suppressSubSchemaRetrieval) {
this(validationContext, "#", baseUri, schemaNode, null, suppressSubSchemaRetrieval);
}
Expand All @@ -92,6 +108,10 @@ private JsonSchema(ValidationContext validationContext, String schemaPath, URI c
}
}

public JsonSchema createChildSchema(String schemaPath, JsonNode schemaNode) {
return getValidationContext().newSchema(schemaPath, schemaNode, this);
}

ValidationContext getValidationContext() {
return this.validationContext;
}
Expand Down Expand Up @@ -143,7 +163,7 @@ private void updateThisAsSubschema(URI originalUri) {
} catch (URISyntaxException ex) {
throw new JsonSchemaException("Unable to create URI without fragment from " + this.currentUri + ": " + ex.getMessage());
}
this.parentSchema = new JsonSchema(this.validationContext, this.schemaPath, currentUriWithoutFragment, this.schemaNode, this.parentSchema);
this.parentSchema = new JsonSchema(this.validationContext, this.schemaPath, currentUriWithoutFragment, this.schemaNode, this.parentSchema, super.suppressSubSchemaRetrieval); // TODO: Should this be delegated to the factory?
this.schemaPath = fragment;
this.schemaNode = fragmentSchemaNode;
this.currentUri = combineCurrentUriWithIds(this.currentUri, fragmentSchemaNode);
Expand Down
17 changes: 12 additions & 5 deletions src/main/java/com/networknt/schema/JsonSchemaFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,15 @@ public static Builder builder(final JsonSchemaFactory blueprint) {
protected JsonSchema newJsonSchema(final URI schemaUri, final JsonNode schemaNode, final SchemaValidatorsConfig config) {
final ValidationContext validationContext = createValidationContext(schemaNode);
validationContext.setConfig(config);
return new JsonSchema(validationContext, schemaUri, schemaNode);
return doCreate(validationContext, "#", schemaUri, schemaNode, null, false);
}

public JsonSchema create(ValidationContext validationContext, String schemaPath, JsonNode schemaNode, JsonSchema parentSchema) {
return doCreate(validationContext, null == schemaPath ? "#" : schemaPath, parentSchema.getCurrentUri(), schemaNode, parentSchema, false);
}

private JsonSchema doCreate(ValidationContext validationContext, String schemaPath, URI currentUri, JsonNode schemaNode, JsonSchema parentSchema, boolean suppressSubSchemaRetrieval) {
return JsonSchema.from(validationContext, schemaPath, currentUri, schemaNode, parentSchema, suppressSubSchemaRetrieval);
}

protected ValidationContext createValidationContext(final JsonNode schemaNode) {
Expand Down Expand Up @@ -428,13 +436,12 @@ public JsonSchema getSchema(final URI schemaUri, final SchemaValidatorsConfig co

JsonSchema jsonSchema;
if (idMatchesSourceUri(jsonMetaSchema, schemaNode, schemaUri)) {
jsonSchema = new JsonSchema(
new ValidationContext(this.uriFactory, this.urnFactory, jsonMetaSchema, this, config),
mappedUri, schemaNode, true /* retrieved via id, resolving will not change anything */);
ValidationContext validationContext = new ValidationContext(this.uriFactory, this.urnFactory, jsonMetaSchema, this, config);
jsonSchema = doCreate(validationContext, "#", mappedUri, schemaNode, null, true /* retrieved via id, resolving will not change anything */);
} else {
final ValidationContext validationContext = createValidationContext(schemaNode);
validationContext.setConfig(config);
jsonSchema = new JsonSchema(validationContext, mappedUri, schemaNode);
jsonSchema = doCreate(validationContext, "#", mappedUri, schemaNode, null, false);
}

if (enableUriSchemaCache) {
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/networknt/schema/NotValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public class NotValidator extends BaseJsonValidator {

public NotValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) {
super(schemaPath, schemaNode, parentSchema, ValidatorTypeCode.NOT, validationContext);
this.schema = new JsonSchema(validationContext, schemaPath, parentSchema.getCurrentUri(), schemaNode, parentSchema);
this.schema = validationContext.newSchema(schemaPath, schemaNode, parentSchema);

parseErrorCode(getValidatorType().getErrorCodeKey());
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/networknt/schema/OneOfValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public OneOfValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentS
int size = schemaNode.size();
for (int i = 0; i < size; i++) {
JsonNode childNode = schemaNode.get(i);
this.schemas.add(new JsonSchema(validationContext, schemaPath + "/" + i, parentSchema.getCurrentUri(), childNode, parentSchema));
this.schemas.add(validationContext.newSchema( schemaPath + "/" + i, childNode, parentSchema));
}
parseErrorCode(getValidatorType().getErrorCodeKey());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public PatternPropertiesValidator(String schemaPath, JsonNode schemaNode, JsonSc
while (names.hasNext()) {
String name = names.next();
RegularExpression pattern = RegularExpression.compile(name, validationContext);
schemas.put(pattern, new JsonSchema(validationContext, name, parentSchema.getCurrentUri(), schemaNode.get(name), parentSchema));
schemas.put(pattern, validationContext.newSchema(name, schemaNode.get(name), parentSchema));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public PrefixItemsValidator(String schemaPath, JsonNode schemaNode, JsonSchema p

if (schemaNode instanceof ArrayNode && 0 < schemaNode.size()) {
for (JsonNode s : schemaNode) {
this.tupleSchema.add(new JsonSchema(validationContext, schemaPath, parentSchema.getCurrentUri(), s, parentSchema));
this.tupleSchema.add(validationContext.newSchema(schemaPath, s, parentSchema));
}
} else {
throw new IllegalArgumentException("The value of 'prefixItems' MUST be a non-empty array of valid JSON Schemas.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public PropertiesValidator(String schemaPath, JsonNode schemaNode, JsonSchema pa
this.validationContext = validationContext;
for (Iterator<String> it = schemaNode.fieldNames(); it.hasNext(); ) {
String pname = it.next();
schemas.put(pname, new JsonSchema(validationContext, schemaPath + "/" + pname, parentSchema.getCurrentUri(), schemaNode.get(pname), parentSchema));
schemas.put(pname, validationContext.newSchema(schemaPath + "/" + pname, schemaNode.get(pname), parentSchema));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public class PropertyNamesValidator extends BaseJsonValidator implements JsonVal
private final JsonSchema innerSchema;
public PropertyNamesValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) {
super(schemaPath, schemaNode, parentSchema, ValidatorTypeCode.PROPERTYNAMES, validationContext);
innerSchema = new JsonSchema(validationContext, schemaPath, parentSchema.getCurrentUri(), schemaNode, parentSchema);
innerSchema = validationContext.newSchema(schemaPath, schemaNode, parentSchema);
}

public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String at) {
Expand Down
22 changes: 10 additions & 12 deletions src/main/java/com/networknt/schema/RefValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -83,23 +83,21 @@ static JsonSchemaRef getRefSchema(JsonSchema parentSchema, ValidationContext val

if (index < 0) {
return new JsonSchemaRef(parentSchema.findAncestor());
} else {
refValue = refValue.substring(index);
}
refValue = refValue.substring(index);
}
if (refValue.equals(REF_CURRENT)) {
return new JsonSchemaRef(parentSchema.findAncestor());
} else {
JsonNode node = parentSchema.getRefSchemaNode(refValue);
if (node != null) {
JsonSchemaRef ref = validationContext.getReferenceParsingInProgress(refValueOriginal);
if (ref == null) {
final JsonSchema schema = new JsonSchema(validationContext, refValue, parentSchema.getCurrentUri(), node, parentSchema);
ref = new JsonSchemaRef(schema);
validationContext.setReferenceParsingInProgress(refValueOriginal, ref);
}
return ref;
}
JsonNode node = parentSchema.getRefSchemaNode(refValue);
if (node != null) {
JsonSchemaRef ref = validationContext.getReferenceParsingInProgress(refValueOriginal);
if (ref == null) {
final JsonSchema schema = validationContext.newSchema(refValue, node, parentSchema);
ref = new JsonSchemaRef(schema);
validationContext.setReferenceParsingInProgress(refValueOriginal, ref);
}
return ref;
}
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public UnevaluatedItemsValidator(String schemaPath, JsonNode schemaNode, JsonSch
super(schemaPath, schemaNode, parentSchema, ValidatorTypeCode.UNEVALUATED_ITEMS, validationContext);

if (schemaNode.isObject() || schemaNode.isBoolean()) {
this.schema = new JsonSchema(validationContext, schemaPath, parentSchema.getCurrentUri(), schemaNode, parentSchema);
this.schema = validationContext.newSchema(schemaPath, schemaNode, parentSchema);
} else {
throw new IllegalArgumentException("The value of 'unevaluatedItems' MUST be a valid JSON Schema.");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public UnevaluatedPropertiesValidator(String schemaPath, JsonNode schemaNode, Js
super(schemaPath, schemaNode, parentSchema, ValidatorTypeCode.UNEVALUATED_PROPERTIES, validationContext);

if (schemaNode.isObject() || schemaNode.isBoolean()) {
this.schema = new JsonSchema(validationContext, schemaPath, parentSchema.getCurrentUri(), schemaNode, parentSchema);
this.schema = validationContext.newSchema(schemaPath, schemaNode, parentSchema);
} else {
throw new IllegalArgumentException("The value of 'unevaluatedProperties' MUST be a valid JSON Schema.");
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/networknt/schema/UnionTypeValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public UnionTypeValidator(String schemaPath, JsonNode schemaNode, JsonSchema par
sep = ", ";

if (n.isObject())
schemas.add(new JsonSchema(validationContext, ValidatorTypeCode.TYPE.getValue(), parentSchema.getCurrentUri(), n, parentSchema));
schemas.add(validationContext.newSchema(ValidatorTypeCode.TYPE.getValue(), n, parentSchema));
else
schemas.add(new TypeValidator(schemaPath + "/" + i, n, parentSchema, validationContext));

Expand Down
4 changes: 4 additions & 0 deletions src/main/java/com/networknt/schema/ValidationContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ public ValidationContext(URIFactory uriFactory, URNFactory urnFactory, JsonMetaS
this.config = config;
}

public JsonSchema newSchema(String schemaPath, JsonNode schemaNode, JsonSchema parentSchema) {
return getJsonSchemaFactory().create(this, schemaPath, schemaNode, parentSchema);
}

public JsonValidator newValidator(String schemaPath, String keyword /* keyword */, JsonNode schemaNode,
JsonSchema parentSchema, String customMessage) {
return metaSchema.newValidator(this, schemaPath, keyword, schemaNode, parentSchema, customMessage);
Expand Down

0 comments on commit 77cd232

Please sign in to comment.