Skip to content

Commit

Permalink
Adds JsonNodeReader (#1065)
Browse files Browse the repository at this point in the history
* Add object reader

* Deprecate setting jsonMapper and yamlMapper on JsonSchemaFactory

* Fix javadoc

* Fix javadoc

* Rename to json node reader
  • Loading branch information
justin-tay authored Jun 14, 2024
1 parent 6621810 commit 45c0b8f
Show file tree
Hide file tree
Showing 19 changed files with 403 additions and 59 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -353,8 +353,8 @@ Assertions contains the following additional information
| Arguments | The arguments used for generating the message.
| Type | The keyword that generated the message.
| Property | The property name that caused the validation error for example for the `required` keyword. Note that this is not part of the instance location as that points to the instance node.
| Schema Node | The `JsonNode` pointed to by the Schema Location. This is the schema data that caused the input data to fail. It is possible to get the location information by configuring the `JsonSchemaFactory` with the `LocationJsonNodeFactoryFactory` and using `JsonNodes.tokenLocationOf(schemaNode)`.
| Instance Node | The `JsonNode` pointed to by the Instance Location. This is the input data that failed validation. It is possible to get the location information by configuring the `JsonSchemaFactory` with the `LocationJsonNodeFactoryFactory` and using `JsonNodes.tokenLocationOf(instanceNode)`.
| Schema Node | The `JsonNode` pointed to by the Schema Location. This is the schema data that caused the input data to fail. It is possible to get the location information by configuring the `JsonSchemaFactory` with a `JsonNodeReader` that uses the `LocationJsonNodeFactoryFactory` and using `JsonNodes.tokenLocationOf(schemaNode)`.
| Instance Node | The `JsonNode` pointed to by the Instance Location. This is the input data that failed validation. It is possible to get the location information by configuring the `JsonSchemaFactory` with a `JsonNodeReader` that uses the `LocationJsonNodeFactoryFactory` and using `JsonNodes.tokenLocationOf(instanceNode)`.
| Details | Additional details that can be set by custom keyword validator implementations. This is not used by the library.

Annotations contains the following additional information
Expand All @@ -367,7 +367,7 @@ Annotations contains the following additional information

The library can be configured to store line and column information in the `JsonNode` instances for the instance and schema nodes. This will adversely affect performance and is not configured by default.

This is done by configuring a `LocationJsonNodeFactoryFactory` on the `JsonSchemaFactory`. The `JsonLocation` information can then be retrieved using `JsonNodes.tokenLocationOf(jsonNode)`.
This is done by configuring a `JsonNodeReader` that uses the `LocationJsonNodeFactoryFactory`on the `JsonSchemaFactory`. The `JsonLocation` information can then be retrieved using `JsonNodes.tokenLocationOf(jsonNode)`.

```java
String schemaData = "{\r\n"
Expand All @@ -383,7 +383,7 @@ String inputData = "{\r\n"
+ " \"startDate\": \"1\"\r\n"
+ "}";
JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012,
builder -> builder.jsonNodeFactoryFactory(LocationJsonNodeFactoryFactory.getInstance()));
builder -> builder.jsonNodeReader(JsonNodeReader.builder().locationAware().build()));
SchemaValidatorsConfig config = new SchemaValidatorsConfig();
config.setPathType(PathType.JSON_POINTER);
JsonSchema schema = factory.getSchema(schemaData, InputFormat.JSON, config);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ private static class Holder {
private static DisallowUnknownJsonMetaSchemaFactory INSTANCE = new DisallowUnknownJsonMetaSchemaFactory();
}

/**
* Gets the instance of {@link DisallowUnknownJsonMetaSchemaFactory}.
*
* @return the json meta schema factory
*/
public static DisallowUnknownJsonMetaSchemaFactory getInstance() {
return Holder.INSTANCE;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ private static class Holder {
private static DisallowUnknownKeywordFactory INSTANCE = new DisallowUnknownKeywordFactory();
}

/**
* Gets the instance of {@link DisallowUnknownKeywordFactory}.
*
* @return the keyword factory
*/
public static DisallowUnknownKeywordFactory getInstance() {
return Holder.INSTANCE;
}
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/com/networknt/schema/JsonSchema.java
Original file line number Diff line number Diff line change
Expand Up @@ -1021,6 +1021,7 @@ public ValidationResult walk(ExecutionContext executionContext, JsonNode node, b
/**
* Walk the JSON node.
*
* @param <T> the result type
* @param executionContext the execution context
* @param node the input
* @param outputFormat the output format
Expand Down Expand Up @@ -1053,6 +1054,7 @@ public ValidationResult walk(ExecutionContext executionContext, JsonNode node, b
/**
* Walk the JSON node.
*
* @param <T> the result type
* @param executionContext the execution context
* @param node the input
* @param outputFormat the output format
Expand Down Expand Up @@ -1099,6 +1101,7 @@ public ValidationResult walk(ExecutionContext executionContext, String input, In
/**
* Walk the input.
*
* @param <T> the result type
* @param executionContext the execution context
* @param input the input
* @param inputFormat the input format
Expand Down Expand Up @@ -1132,6 +1135,7 @@ public ValidationResult walk(ExecutionContext executionContext, String input, In
/**
* Walk the input.
*
* @param <T> the result type
* @param executionContext the execution context
* @param input the input
* @param inputFormat the input format
Expand Down Expand Up @@ -1160,6 +1164,7 @@ public ValidationResult walk(JsonNode node, boolean validate) {
/**
* Walk the JSON node.
*
* @param <T> the result type
* @param node the input
* @param validate true to validate the input against the schema
* @param outputFormat the output format
Expand Down
63 changes: 40 additions & 23 deletions src/main/java/com/networknt/schema/JsonSchemaFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,8 @@
import com.networknt.schema.resource.SchemaMapper;
import com.networknt.schema.resource.SchemaMappers;
import com.networknt.schema.serialization.JsonMapperFactory;
import com.networknt.schema.serialization.JsonNodeReader;
import com.networknt.schema.serialization.YamlMapperFactory;
import com.networknt.schema.serialization.node.JsonNodeFactoryFactory;
import com.networknt.schema.utils.JsonNodes;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -56,7 +55,7 @@ public class JsonSchemaFactory {
public static class Builder {
private ObjectMapper jsonMapper = null;
private ObjectMapper yamlMapper = null;
private JsonNodeFactoryFactory jsonNodeFactoryFactory = null;
private JsonNodeReader jsonNodeReader = null;
private String defaultMetaSchemaIri;
private final ConcurrentMap<String, JsonMetaSchema> metaSchemas = new ConcurrentHashMap<String, JsonMetaSchema>();
private SchemaLoaders.Builder schemaLoadersBuilder = null;
Expand All @@ -65,25 +64,47 @@ public static class Builder {
private JsonMetaSchemaFactory metaSchemaFactory = null;

/**
* Configures the {@link JsonNodeFactoryFactory} to use.
* Sets the json node reader to read the data.
* <p>
* To get location information from {@link JsonNode} the
* {@link com.networknt.schema.serialization.node.LocationJsonNodeFactoryFactory}
* can be used.
* If set this takes precedence over the configured json mapper and yaml mapper.
* <p>
* A location aware object reader can be created using JsonNodeReader.builder().locationAware().build().
*
* @param jsonNodeFactoryFactory the factory to create json node factories
* @param jsonNodeReader the object reader
* @return the builder
*/
public Builder jsonNodeFactoryFactory(JsonNodeFactoryFactory jsonNodeFactoryFactory) {
this.jsonNodeFactoryFactory = jsonNodeFactoryFactory;
public Builder jsonNodeReader(JsonNodeReader jsonNodeReader) {
this.jsonNodeReader = jsonNodeReader;
return this;
}

/**
* Sets the json mapper to read the data.
* <p>
* If the object reader is set this will not be used.
* <p>
* This is deprecated use a object reader instead.
*
* @param jsonMapper the json mapper
* @return the builder
*/
@Deprecated
public Builder jsonMapper(final ObjectMapper jsonMapper) {
this.jsonMapper = jsonMapper;
return this;
}

/**
* Sets the yaml mapper to read the data.
* <p>
* If the object reader is set this will not be used.
* <p>
* This is deprecated use a object reader instead.
*
* @param yamlMapper the yaml mapper
* @return the builder
*/
@Deprecated
public Builder yamlMapper(final ObjectMapper yamlMapper) {
this.yamlMapper = yamlMapper;
return this;
Expand Down Expand Up @@ -151,7 +172,7 @@ public JsonSchemaFactory build() {
return new JsonSchemaFactory(
jsonMapper,
yamlMapper,
jsonNodeFactoryFactory,
jsonNodeReader,
defaultMetaSchemaIri,
schemaLoadersBuilder,
schemaMappersBuilder,
Expand All @@ -164,7 +185,7 @@ public JsonSchemaFactory build() {

private final ObjectMapper jsonMapper;
private final ObjectMapper yamlMapper;
private final JsonNodeFactoryFactory jsonNodeFactoryFactory;
private final JsonNodeReader jsonNodeReader;
private final String defaultMetaSchemaIri;
private final SchemaLoaders.Builder schemaLoadersBuilder;
private final SchemaMappers.Builder schemaMappersBuilder;
Expand All @@ -180,7 +201,7 @@ public JsonSchemaFactory build() {
private JsonSchemaFactory(
ObjectMapper jsonMapper,
ObjectMapper yamlMapper,
JsonNodeFactoryFactory jsonNodeFactoryFactory,
JsonNodeReader jsonNodeReader,
String defaultMetaSchemaIri,
SchemaLoaders.Builder schemaLoadersBuilder,
SchemaMappers.Builder schemaMappersBuilder,
Expand All @@ -197,7 +218,7 @@ private JsonSchemaFactory(
}
this.jsonMapper = jsonMapper;
this.yamlMapper = yamlMapper;
this.jsonNodeFactoryFactory = jsonNodeFactoryFactory;
this.jsonNodeReader = jsonNodeReader;
this.defaultMetaSchemaIri = defaultMetaSchemaIri;
this.schemaLoadersBuilder = schemaLoadersBuilder;
this.schemaMappersBuilder = schemaMappersBuilder;
Expand Down Expand Up @@ -290,7 +311,7 @@ public static Builder builder(final JsonSchemaFactory blueprint) {
.defaultMetaSchemaIri(blueprint.defaultMetaSchemaIri)
.jsonMapper(blueprint.jsonMapper)
.yamlMapper(blueprint.yamlMapper)
.jsonNodeFactoryFactory(blueprint.jsonNodeFactoryFactory);
.jsonNodeReader(blueprint.jsonNodeReader);
if (blueprint.schemaLoadersBuilder != null) {
builder.schemaLoadersBuilder = SchemaLoaders.builder().with(blueprint.schemaLoadersBuilder);
}
Expand Down Expand Up @@ -442,18 +463,18 @@ protected JsonMetaSchema loadMetaSchema(String iri, SchemaValidatorsConfig confi
}

JsonNode readTree(String content, InputFormat inputFormat) throws IOException {
if (this.jsonNodeFactoryFactory == null) {
if (this.jsonNodeReader == null) {
return getObjectMapper(inputFormat).readTree(content);
} else {
return JsonNodes.readTree(getObjectMapper(inputFormat), content, this.jsonNodeFactoryFactory);
return this.jsonNodeReader.readTree(content, inputFormat);
}
}

JsonNode readTree(InputStream content, InputFormat inputFormat) throws IOException {
if (this.jsonNodeFactoryFactory == null) {
if (this.jsonNodeReader == null) {
return getObjectMapper(inputFormat).readTree(content);
} else {
return JsonNodes.readTree(getObjectMapper(inputFormat), content, this.jsonNodeFactoryFactory);
return this.jsonNodeReader.readTree(content, inputFormat);
}
}

Expand Down Expand Up @@ -627,10 +648,6 @@ ObjectMapper getJsonMapper() {
return this.jsonMapper != null ? this.jsonMapper : JsonMapperFactory.getInstance();
}

JsonNodeFactoryFactory getJsonNodeFactoryFactory() {
return this.jsonNodeFactoryFactory;
}

/**
* Creates a schema validators config.
*
Expand Down
Loading

0 comments on commit 45c0b8f

Please sign in to comment.