diff --git a/doc/migration-2.0.0.md b/doc/migration-2.0.0.md new file mode 100644 index 000000000..8294847f9 --- /dev/null +++ b/doc/migration-2.0.0.md @@ -0,0 +1,138 @@ +## Migration to 2.0.0 from 1.5.x + +### Compatibility + +| Version | Java Compatibility | Jackson Version | Comments | +| ----------------- | ------------------ | --------------- | -------------------------------------------------------------------------------------------------- | +| `2.0.0` | Java 8 | Jackson 2 | This allows clients that still require to use Java 8 to have an incremental upgrade path to 3.0.0. | +| `3.0.0` (Planned) | Java 17 | Jackson 3 | The change to Java compatibility is because Jackson 3 requires Java 17. | + +### Major Changes + +- Removal of deprecated methods and functionality from 1.x. +- Major renaming of many of the public APIs and moving of classes into sub-packages. +- Errors are returned as a `List` instead of a `Set`. +- External resources will not be automatically fetched by default. This now requires opt-in via configuration. + - This is to conform to the specification that requires such functionality to be disabled by default to prefer offline operation. Note however that classpath resources will still be automatically loaded. + +#### Renaming and Refactoring + +| Old | New | Comments | +| ----------------------------------------------------- | ---------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `com.networknt.schema.JsonMetaSchema` | `com.networknt.schema.dialect.Dialect` | Renamed to convey that this represents the dialect which has a set of keywords and vocabularies with precise semantics. The dialect id is used to identify the meta-schema which can be used to validate that a schema conforms to this dialect. | +| `com.networknt.schema.JsonMetaSchemaFactory` | `com.networknt.schema.dialect.DialectRegistry` | Renamed to convey that this stores a set of registered dialects that will be used when `$schema` is found in a schema. For instance it is possible to override a standard dialect specified by a specification by registering a dialect using that dialect id. | +| `com.networknt.schema.JsonSchema` | `com.networknt.schema.Schema` | Simplify naming. It is no longer possible to associate a configuration with a specific schema. | +| `com.networknt.schema.JsonSchemaFactory` | `com.networknt.schema.SchemaRegistry` | Renamed to convey that this stores a set of registered schema resources. All schemas created will use the same configuration used for the registry. Therefore all the keywords of the schemas in the registry will be consistent configured. If there is a need for different configuration, a separate schema registry should be used. | +| `com.networknt.schema.ValidationMessage` | `com.networknt.schema.Error` | Renamed to convey the intent better as a validation error raised by assertion keywords when processing instance data, or as a parse error when processing the schema data. The instance location has also been removed from the message. Therefore calling `error.getMessage()` no longer has the instance location pre-pended to the message. Calling `error.toString()` will return the message with the instance location prepended if the instance location exists. | +| `com.networknt.schema.SchemaValidatorsConfig` | `com.networknt.schema.SchemaRegistryConfig` | Renamed to convey that this configuration is shared by all schemas from the same schema registry. The walk configuration has been moved out. | +| `com.networknt.schema.SchemaValidatorsConfig` | `com.networknt.schema.walk.WalkConfig` | The walk configuration has been moved to a separate class. | +| `com.networknt.schema.ErrorMessageType` | No replacement | The concept of error codes have been removed, instead the message keys used for generating the localised messages can be used instead to distinguish the error messages. | +| `com.networknt.schema.ValidationContext` | `com.networknt.schema.SchemaContext` | Renamed to convey that this is the schema context shared for all the schemas and validators for the same overall schema with the same dialect. | +| `com.networknt.schema.ValidatorTypeCode` | `com.networknt.schema.keyword.KeywordType` | Renamed to convey that these are keywords as the error codes have been removed. | +| `com.networknt.schema.JsonSchemaValidator` | `com.networknt.schema.Validator` | Simplify naming. | +| `com.networknt.schema.JsonValidator` | `com.networknt.schema.keyword.KeywordValidator` | Renamed to convey the intent that this is the validator created for keywords. | +| `com.networknt.schema.walk.JsonSchemaWalker` | `com.networknt.schema.walk.Walker` | Simplify naming. | +| `com.networknt.schema.SpecVersion.VersionFlag` | `com.networknt.schema.SpecificationVersion` | Renamed and flatten the hierarchy. | +| `com.networknt.schema.SchemaId` | `com.networknt.schema.dialect.DialectId` | Renamed to convey that this is the dialect id used for the `$schema` keyword in schemas and `$id` keyword in meta-schemas. | +| `com.networknt.schema.VocabularyFactory` | `com.networknt.schema.vocabulary.VocabularyRegistry` | Renamed to convey that this stores a set of registered vocabularies that contain keywords. | +| `com.networknt.schema.JsonSchemaIdValidator` | `com.networknt.schema.SchemaIdValidator` | Simplify naming. | +| `com.networknt.schema.JsonSchemaRef` | `com.networknt.schema.SchemaRef` | Simplify naming. | +| `com.networknt.schema.JsonSchemaException` | `com.networknt.schema.SchemaException` | Simplify naming. | +| `com.networknt.schema.JsonNodePath` | `com.networknt.schema.NodePath` | Simplify naming. | +| `com.networknt.schema.serialization.JsonNodeReader` | `com.networknt.schema.serialization.NodeReader` | Simplify naming. | +| `com.networknt.schema.annotation.JsonNodeAnnotation` | `com.networknt.schema.annotation.Annotation` | Simplify naming. | +| `com.networknt.schema.annotation.JsonNodeAnnotations` | `com.networknt.schema.annotation.Annotations` | Simplify naming. | +| `com.networknt.schema.ValidationResult` | `com.networknt.schema.Result` | Renamed to convey that this stores not just validation results but the output from walking. | +| `com.networknt.schema.VersionCode` | `com.networknt.schema.SpecificationVersionRange` | Renamed to convey that this contains specification version ranges. | + +#### Configuration + +##### Schema Validators Configuration + +The `com.networknt.schema.SchemaValidatorsConfig` file has been replaced by either `com.networknt.schema.SchemaRegistryConfig` or `com.networknt.schema.walk.WalkConfig` or moved to `com.networknt.schema.ExecutionConfig` and can no longer be configured on a per schema basis. + +| Name | Migration | +| ------------------------------------- | -------------------------------------------------------- | +| `applyDefaultsStrategy` | `com.networknt.schema.walk.WalkConfig` | +| `cacheRefs` | `com.networknt.schema.SchemaRegistryConfig` | +| `discriminatorKeywordEnabled` | Removed. Dialect must contain a `discriminator` keyword. | +| `errorMessageKeyword` | `com.networknt.schema.SchemaRegistryConfig` | +| `executionContextCustomizer` | `com.networknt.schema.SchemaRegistryConfig` | +| `failFast` | `com.networknt.schema.SchemaRegistryConfig` | +| `formatAssertionsEnabled` | `com.networknt.schema.SchemaRegistryConfig` | +| `javaSemantics` | `com.networknt.schema.SchemaRegistryConfig` | +| `locale` | `com.networknt.schema.SchemaRegistryConfig` | +| `losslessNarrowing` | `com.networknt.schema.SchemaRegistryConfig` | +| `messageSource` | `com.networknt.schema.SchemaRegistryConfig` | +| `nullableKeywordEnabled` | Removed. Dialect must contain a `nullable` keyword. | +| `pathType` | `com.networknt.schema.SchemaRegistryConfig` | +| `preloadJsonSchema` | `com.networknt.schema.SchemaRegistryConfig` | +| `preloadJsonSchemaRefMaxNestingDepth` | `com.networknt.schema.SchemaRegistryConfig` | +| `readOnly` | `com.networknt.schema.ExecutionConfig` | +| `regularExpressionFactory` | `com.networknt.schema.SchemaRegistryConfig` | +| `schemaIdValidator` | `com.networknt.schema.SchemaRegistryConfig` | +| `strict` | `com.networknt.schema.SchemaRegistryConfig` | +| `typeLoose` | `com.networknt.schema.SchemaRegistryConfig` | +| `writeOnly` | `com.networknt.schema.ExecutionConfig` | +| `itemWalkListeners` | `com.networknt.schema.walk.WalkConfig` | +| `keywordWalkListeners` | `com.networknt.schema.walk.WalkConfig` | +| `propertyWalkListeners` | `com.networknt.schema.walk.WalkConfig` | + +#### API + +```java +package com.example.demo; + +import java.util.List; +import java.util.Map; + +import com.networknt.schema.Error; +import com.networknt.schema.InputFormat; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.SchemaRegistry; +import com.networknt.schema.dialect.Dialects; + +public class Demo { + public static void main(String[] args) { + String schemaData = """ + { + "$id": "https://example.com/address.schema.json", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "streetAddress": { + "type": "string" + }, + "locality": { + "type": "string" + }, + "region": { + "type": "string" + }, + "postalCode": { + "type": "string" + }, + "countryName": { + "type": "string" + } + }, + "required": [ "locality", "region", "countryName" ] + } + """; + String instanceData = """ + { + "streetAddress": "456 Main St", + "region": "State", + "postalCode": "12345", + "countryName": "Country" + } + """; + SchemaRegistry schemaRegistry = SchemaRegistry.withDialect(Dialects.getDraft202012(), + builder -> builder.schemas(Map.of("https://example.com/address.schema.json", schemaData))); + Schema schema = schemaRegistry.getSchema(SchemaLocation.of("https://example.com/address.schema.json")); + List errors = schema.validate(instanceData, InputFormat.JSON); + System.out.println(errors); + } +} +``` diff --git a/src/main/java/com/networknt/schema/AbstractCollector.java b/src/main/java/com/networknt/schema/AbstractCollector.java deleted file mode 100644 index 3a45d81d0..000000000 --- a/src/main/java/com/networknt/schema/AbstractCollector.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2020 Network New Technologies Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.networknt.schema; - -/** - * Base collector. - * - * @param the type - */ -public abstract class AbstractCollector implements Collector { - - @Override - public void combine(Object object) { - // Do nothing. This is the default Implementation. - } -} diff --git a/src/main/java/com/networknt/schema/AllOfValidator.java b/src/main/java/com/networknt/schema/AllOfValidator.java deleted file mode 100644 index a74e7aeec..000000000 --- a/src/main/java/com/networknt/schema/AllOfValidator.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (c) 2016 Network New Technologies Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.networknt.schema; - -import java.util.*; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.node.ObjectNode; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * {@link JsonValidator} for allOf. - */ -public class AllOfValidator extends BaseJsonValidator { - private static final Logger logger = LoggerFactory.getLogger(AllOfValidator.class); - - private final List schemas; - - public AllOfValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.ALL_OF, validationContext); - if (!schemaNode.isArray()) { - JsonType nodeType = TypeFactory.getValueNodeType(schemaNode, this.validationContext.getConfig()); - throw new JsonSchemaException(message().instanceNode(schemaNode) - .instanceLocation(schemaLocation.getFragment()) - .messageKey("type") - .arguments(nodeType.toString(), "array") - .build()); - } - int size = schemaNode.size(); - this.schemas = new ArrayList<>(size); - for (int i = 0; i < size; i++) { - this.schemas.add(validationContext.newSchema(schemaLocation.append(i), evaluationPath.append(i), - schemaNode.get(i), parentSchema)); - } - } - - @Override - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) { - validate(executionContext, node, rootNode, instanceLocation, false); - } - - protected void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation, boolean walk) { - debug(logger, executionContext, node, rootNode, instanceLocation); - - for (JsonSchema schema : this.schemas) { - if (!walk) { - schema.validate(executionContext, node, rootNode, instanceLocation); - } else { - schema.walk(executionContext, node, rootNode, instanceLocation, true); - } - if (this.validationContext.getConfig().isDiscriminatorKeywordEnabled()) { - final Iterator arrayElements = this.schemaNode.elements(); - while (arrayElements.hasNext()) { - final ObjectNode allOfEntry = (ObjectNode) arrayElements.next(); - final JsonNode $ref = allOfEntry.get("$ref"); - if (null != $ref) { - final DiscriminatorContext currentDiscriminatorContext = executionContext - .getCurrentDiscriminatorContext(); - if (null != currentDiscriminatorContext) { - final ObjectNode discriminator = currentDiscriminatorContext - .getDiscriminatorForPath(allOfEntry.get("$ref").asText()); - if (null != discriminator) { - DiscriminatorValidator.registerAndMergeDiscriminator(currentDiscriminatorContext, discriminator, - this.parentSchema, instanceLocation); - // now we have to check whether we have hit the right target - final String discriminatorPropertyName = discriminator.get("propertyName").asText(); - final JsonNode discriminatorNode = node.get(discriminatorPropertyName); - final String discriminatorPropertyValue = discriminatorNode == null ? null - : discriminatorNode.textValue(); - - final JsonSchema jsonSchema = this.parentSchema; - DiscriminatorValidator.checkDiscriminatorMatch(currentDiscriminatorContext, discriminator, - discriminatorPropertyValue, jsonSchema); - } - } - } - } - } - } - } - - @Override - public void walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation, boolean shouldValidateSchema) { - if (shouldValidateSchema && node != null) { - validate(executionContext, node, rootNode, instanceLocation, true); - return; - } - for (JsonSchema schema : this.schemas) { - // Walk through the schema - schema.walk(executionContext, node, rootNode, instanceLocation, false); - } - } - - @Override - public void preloadJsonSchema() { - preloadJsonSchemas(this.schemas); - } -} diff --git a/src/main/java/com/networknt/schema/AnyOfValidator.java b/src/main/java/com/networknt/schema/AnyOfValidator.java deleted file mode 100644 index 8245b1673..000000000 --- a/src/main/java/com/networknt/schema/AnyOfValidator.java +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright (c) 2016 Network New Technologies Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.networknt.schema; - -import com.fasterxml.jackson.databind.JsonNode; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.*; - -/** - * {@link JsonValidator} for anyOf. - */ -public class AnyOfValidator extends BaseJsonValidator { - private static final Logger logger = LoggerFactory.getLogger(AnyOfValidator.class); - private static final String DISCRIMINATOR_REMARK = "and the discriminator-selected candidate schema didn't pass validation"; - - private final List schemas; - - private Boolean canShortCircuit = null; - - public AnyOfValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.ANY_OF, validationContext); - if (!schemaNode.isArray()) { - JsonType nodeType = TypeFactory.getValueNodeType(schemaNode, this.validationContext.getConfig()); - throw new JsonSchemaException(message().instanceNode(schemaNode) - .instanceLocation(schemaLocation.getFragment()) - .messageKey("type") - .arguments(nodeType.toString(), "array") - .build()); - } - int size = schemaNode.size(); - this.schemas = new ArrayList<>(size); - for (int i = 0; i < size; i++) { - this.schemas.add(validationContext.newSchema(schemaLocation.append(i), evaluationPath.append(i), - schemaNode.get(i), parentSchema)); - } - } - - @Override - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, - JsonNodePath instanceLocation) { - validate(executionContext, node, rootNode, instanceLocation, false); - } - - protected void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, - JsonNodePath instanceLocation, boolean walk) { - debug(logger, executionContext, node, rootNode, instanceLocation); - - if (this.validationContext.getConfig().isDiscriminatorKeywordEnabled()) { - executionContext.enterDiscriminatorContext(new DiscriminatorContext(), instanceLocation); - } - int numberOfValidSubSchemas = 0; - List existingErrors = executionContext.getErrors(); - List allErrors = null; - List errors = new ArrayList<>(); - executionContext.setErrors(errors); - try { - // Save flag as nested schema evaluation shouldn't trigger fail fast - boolean failFast = executionContext.isFailFast(); - try { - executionContext.setFailFast(false); - for (JsonSchema schema : this.schemas) { - errors.clear(); - TypeValidator typeValidator = schema.getTypeValidator(); - if (typeValidator != null) { - // If schema has type validator and node type doesn't match with schemaType then - // ignore it - // For union type, it is a must to call TypeValidator - if (typeValidator.getSchemaType() != JsonType.UNION && !typeValidator.equalsToSchemaType(node)) { - typeValidator.validate(executionContext, node, rootNode, instanceLocation); - if (allErrors == null) { - allErrors = new ArrayList<>(); - } - allErrors.addAll(errors); - continue; - } - } - if (!walk) { - schema.validate(executionContext, node, rootNode, instanceLocation); - } else { - schema.walk(executionContext, node, rootNode, instanceLocation, true); - } - - // check if any validation errors have occurred - if (errors.isEmpty()) { - // we found a valid subschema, so increase counter - numberOfValidSubSchemas++; - } - - if (errors.isEmpty() && (!this.validationContext.getConfig().isDiscriminatorKeywordEnabled()) - && canShortCircuit() && canShortCircuit(executionContext)) { - // Clear all errors. Note that this is checked in finally. - allErrors = null; - executionContext.setErrors(existingErrors); - return; - } else if (this.validationContext.getConfig().isDiscriminatorKeywordEnabled()) { - DiscriminatorContext currentDiscriminatorContext = executionContext.getCurrentDiscriminatorContext(); - if (currentDiscriminatorContext.isDiscriminatorMatchFound() - || currentDiscriminatorContext.isDiscriminatorIgnore()) { - if (!errors.isEmpty()) { - // The following is to match the previous logic adding to all errors - // which is generally discarded as it returns errors but the allErrors - // is getting processed in finally - if (allErrors == null) { - allErrors = new ArrayList<>(); - } - allErrors.add(message().instanceNode(node).instanceLocation(instanceLocation) - .locale(executionContext.getExecutionConfig().getLocale()) - .failFast(executionContext.isFailFast()).arguments(DISCRIMINATOR_REMARK) - .build()); - } else { - // Clear all errors. Note that this is checked in finally. - allErrors = null; - } - existingErrors.addAll(errors); - executionContext.setErrors(existingErrors); - return; - } - } - if (allErrors == null) { - allErrors = new ArrayList<>(); - } - allErrors.addAll(errors); - } - } finally { - // Restore flag - executionContext.setFailFast(failFast); - } - - if (this.validationContext.getConfig().isDiscriminatorKeywordEnabled() - && executionContext.getCurrentDiscriminatorContext().isActive() - && !executionContext.getCurrentDiscriminatorContext().isDiscriminatorIgnore()) { - existingErrors.add(message().instanceNode(node).instanceLocation(instanceLocation) - .locale(executionContext.getExecutionConfig().getLocale()) - .arguments( - "based on the provided discriminator. No alternative could be chosen based on the discriminator property") - .build()); - executionContext.setErrors(existingErrors); - return; - } - } finally { - if (this.validationContext.getConfig().isDiscriminatorKeywordEnabled()) { - executionContext.leaveDiscriminatorContextImmediately(instanceLocation); - } - } - if (numberOfValidSubSchemas >= 1) { - executionContext.setErrors(existingErrors); - } else { - if (allErrors != null) { - existingErrors.addAll(allErrors); - } - executionContext.setErrors(existingErrors); - } - } - - @Override - public void walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation, boolean shouldValidateSchema) { - if (shouldValidateSchema && node != null) { - validate(executionContext, node, rootNode, instanceLocation, true); - return; - } - for (JsonSchema schema : this.schemas) { - schema.walk(executionContext, node, rootNode, instanceLocation, false); - } - } - - /** - * If annotation collection is enabled cannot short circuit. - * - * @see anyOf - * @param executionContext the execution context - * @return true if can short circuit - */ - protected boolean canShortCircuit(ExecutionContext executionContext) { - return !executionContext.getExecutionConfig().isAnnotationCollectionEnabled(); - } - - /** - * If annotations are require for evaluation cannot short circuit. - * - * @return true if can short circuit - */ - protected boolean canShortCircuit() { - if (this.canShortCircuit == null) { - boolean canShortCircuit = true; - for (JsonValidator validator : getEvaluationParentSchema().getValidators()) { - if ("unevaluatedProperties".equals(validator.getKeyword()) - || "unevaluatedItems".equals(validator.getKeyword())) { - canShortCircuit = false; - } - } - this.canShortCircuit = canShortCircuit; - } - return this.canShortCircuit; - } - - @Override - public void preloadJsonSchema() { - preloadJsonSchemas(this.schemas); - canShortCircuit(); // cache flag - } -} \ No newline at end of file diff --git a/src/main/java/com/networknt/schema/BaseJsonValidator.java b/src/main/java/com/networknt/schema/BaseJsonValidator.java deleted file mode 100644 index c1313ff44..000000000 --- a/src/main/java/com/networknt/schema/BaseJsonValidator.java +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Copyright (c) 2016 Network New Technologies Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.networknt.schema; - -import com.fasterxml.jackson.databind.JsonNode; -import com.networknt.schema.annotation.JsonNodeAnnotation; - -import org.slf4j.Logger; - -import java.util.Collection; -import java.util.Map; -import java.util.function.Consumer; - -/** - * Base {@link JsonValidator}. - */ -public abstract class BaseJsonValidator implements JsonValidator { - protected final JsonNode schemaNode; - - protected final ValidationContext validationContext; - - protected final Keyword keyword; - protected final JsonSchema parentSchema; - protected final SchemaLocation schemaLocation; - protected final Map errorMessage; - - protected final JsonNodePath evaluationPath; - protected final JsonSchema evaluationParentSchema; - - // Pending removal - protected final ErrorMessageType errorMessageType; - - public BaseJsonValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, - JsonSchema parentSchema, ValidatorTypeCode validatorType, ValidationContext validationContext) { - this(schemaLocation, evaluationPath, schemaNode, parentSchema, validatorType, validatorType, validationContext); - } - - public BaseJsonValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, - JsonSchema parentSchema, ErrorMessageType errorMessageType, Keyword keyword, - ValidationContext validationContext) { - this.validationContext = validationContext; - this.schemaNode = schemaNode; - - this.keyword = keyword; - this.parentSchema = parentSchema; - this.schemaLocation = schemaLocation; - if (keyword != null && parentSchema != null && validationContext.getConfig().getErrorMessageKeyword() != null) { - this.errorMessage = ErrorMessages.getErrorMessage(parentSchema, - validationContext.getConfig().getErrorMessageKeyword(), keyword.getValue()); - } else { - this.errorMessage = null; - } - - this.errorMessageType = errorMessageType; - this.evaluationPath = evaluationPath; - this.evaluationParentSchema = null; - } - - /** - * Constructor to create a copy using fields. - * - * @param schemaNode the schema node - * @param validationContext the validation context - * @param errorMessageType the error message type - * @param keyword the keyword - * @param parentSchema the parent schema - * @param schemaLocation the schema location - * @param evaluationPath the evaluation path - * @param evaluationParentSchema the evaluation parent schema - * @param errorMessage the error message - */ - protected BaseJsonValidator( - /* Below from BaseJsonValidator */ - JsonNode schemaNode, - ValidationContext validationContext, - /* Below from ValidationMessageHandler */ - ErrorMessageType errorMessageType, - Keyword keyword, - JsonSchema parentSchema, - SchemaLocation schemaLocation, - JsonNodePath evaluationPath, - JsonSchema evaluationParentSchema, - Map errorMessage) { - this.schemaNode = schemaNode; - this.validationContext = validationContext; - - this.keyword = keyword; - this.parentSchema = parentSchema; - this.schemaLocation = schemaLocation; - this.errorMessage = errorMessage; - - this.errorMessageType = errorMessageType; - this.evaluationPath = evaluationPath; - this.evaluationParentSchema = evaluationParentSchema; - } - - protected static boolean equals(double n1, double n2) { - return Math.abs(n1 - n2) < 1e-12; - } - - public static void debug(Logger logger, ExecutionContext executionContext, JsonNode node, JsonNode rootNode, - JsonNodePath instanceLocation) { - //logger.debug("validate( {}, {}, {})", node, rootNode, instanceLocation); - // The below is equivalent to the above but as there are more than 2 arguments - // the var-arg method is used and an array needs to be allocated even if debug - // is not enabled - if (executionContext.getExecutionConfig().isDebugEnabled() && logger.isDebugEnabled()) { - StringBuilder builder = new StringBuilder(); - builder.append("validate( "); - builder.append(node.toString()); - builder.append(", "); - builder.append(rootNode.toString()); - builder.append(", "); - builder.append(instanceLocation.toString()); - builder.append(")"); - logger.debug(builder.toString()); - } - } - - @Override - public SchemaLocation getSchemaLocation() { - return this.schemaLocation; - } - - @Override - public JsonNodePath getEvaluationPath() { - return this.evaluationPath; - } - - @Override - public String getKeyword() { - return this.keyword.getValue(); - } - - public JsonNode getSchemaNode() { - return this.schemaNode; - } - - /** - * Gets the parent schema. - *

- * This is the lexical parent schema. - * - * @return the parent schema - */ - public JsonSchema getParentSchema() { - return this.parentSchema; - } - - /** - * Gets the evaluation parent schema. - *

- * This is the dynamic parent schema when following references. - * - * @see JsonSchema#fromRef(JsonSchema, JsonNodePath) - * @return the evaluation parent schema - */ - public JsonSchema getEvaluationParentSchema() { - if (this.evaluationParentSchema != null) { - return this.evaluationParentSchema; - } - return getParentSchema(); - } - - protected String getNodeFieldType() { - JsonNode typeField = this.getParentSchema().getSchemaNode().get("type"); - if (typeField != null) { - return typeField.asText(); - } - return null; - } - - protected void preloadJsonSchemas(final Collection schemas) { - for (final JsonSchema schema : schemas) { - schema.initializeValidators(); - } - } - - - - @Override - public String toString() { - return getEvaluationPath().getName(-1); - } - - /** - * Determines if the keyword exists adjacent in the evaluation path. - *

- * This does not check if the keyword exists in the current meta schema as this - * can be a cross-draft case where the properties keyword is in a Draft 7 schema - * and the unevaluatedProperties keyword is in an outer Draft 2020-12 schema. - *

- * The fact that the validator exists in the evaluation path implies that the - * keyword was valid in whatever meta schema for that schema it was created for. - * - * @param keyword the keyword to check - * @return true if found - */ - protected boolean hasAdjacentKeywordInEvaluationPath(String keyword) { - JsonSchema schema = getEvaluationParentSchema(); - while (schema != null) { - for (JsonValidator validator : schema.getValidators()) { - if (keyword.equals(validator.getKeyword())) { - return true; - } - } - Object element = schema.getEvaluationPath().getElement(-1); - if ("properties".equals(element) || "items".equals(element)) { - // If there is a change in instance location then return false - return false; - } - schema = schema.getEvaluationParentSchema(); - } - return false; - } - - protected MessageSourceValidationMessage.Builder message() { - return MessageSourceValidationMessage.builder(this.validationContext.getConfig().getMessageSource(), this.errorMessage, (message, failFast) -> { - if (failFast) { - throw new FailFastAssertionException(message); - } - }).code(this.errorMessageType.getErrorCode()).schemaNode(this.schemaNode).schemaLocation(this.schemaLocation) - .evaluationPath(this.evaluationPath).type(this.keyword != null ? this.keyword.getValue() : null) - .messageKey(this.errorMessageType.getErrorCodeValue()); - } - - /** - * Determine if annotations should be reported. - * - * @param executionContext the execution context - * @return true if annotations should be reported - */ - protected boolean collectAnnotations(ExecutionContext executionContext) { - return collectAnnotations(executionContext, getKeyword()); - } - - /** - * Determine if annotations should be reported. - * - * @param executionContext the execution context - * @param keyword the keyword - * @return true if annotations should be reported - */ - protected boolean collectAnnotations(ExecutionContext executionContext, String keyword) { - return executionContext.getExecutionConfig().isAnnotationCollectionEnabled() - && executionContext.getExecutionConfig().getAnnotationCollectionFilter().test(keyword); - } - - /** - * Puts an annotation. - * - * @param executionContext the execution context - * @param customizer to customize the annotation - */ - protected void putAnnotation(ExecutionContext executionContext, Consumer customizer) { - JsonNodeAnnotation.Builder builder = JsonNodeAnnotation.builder().evaluationPath(this.evaluationPath) - .schemaLocation(this.schemaLocation).keyword(getKeyword()); - customizer.accept(builder); - executionContext.getAnnotations().put(builder.build()); - } -} diff --git a/src/main/java/com/networknt/schema/Collector.java b/src/main/java/com/networknt/schema/Collector.java deleted file mode 100644 index f3e84f00b..000000000 --- a/src/main/java/com/networknt/schema/Collector.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2020 Network New Technologies Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.networknt.schema; - -/** - * Basic interface that allows the implementers to collect the information and - * return it. - * - * @param element - */ -public interface Collector { - - - /** - * This method should be called by the intermediate touch points that want to - * combine the data being collected by this collector. This is an optional - * method and could be used when the same collector is used for collecting data - * at multiple touch points or accumulating data at same touch point. - * @param object Object - */ - void combine(Object object); - - /** - * Final method called by the framework that returns the actual collected data. - * If the collector is not accumulating data or being used to collect data at - * multiple touch points, only this method can be implemented. - * @return E element - */ - E collect(); - - -} diff --git a/src/main/java/com/networknt/schema/CollectorContext.java b/src/main/java/com/networknt/schema/CollectorContext.java index 53e439faa..73bd1f33a 100644 --- a/src/main/java/com/networknt/schema/CollectorContext.java +++ b/src/main/java/com/networknt/schema/CollectorContext.java @@ -17,136 +17,86 @@ import java.util.HashMap; import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; +import java.util.function.Function; /** - * Context for holding the output returned by the {@link Collector} - * implementations. + * Context for holding data which can be set by custom walkers or validators and + * can be retrieved later from the execution context. */ public class CollectorContext { /** - * Map for holding the name and {@link Collector} or a simple Object. + * Map for the data. */ - private final Map collectorMap; - - /** - * Map for holding the name and {@link Collector} class collect method output. - */ - private final Map collectorLoadMap; + private final Map data; /** * Default constructor will use an unsynchronized HashMap to store data. This is * suitable if the collector context is not shared with multiple threads. */ public CollectorContext() { - this(new HashMap<>(), new HashMap<>()); + this(new HashMap<>()); } - /** - * Constructor that creates the context using the specified instances to store - * data. - *

- * If for instance the collector context needs to be shared with multiple - * threads a ConcurrentHashMap can be used. - * - * @param collectorMap the collector map - * @param collectorLoadMap the collector load map - */ - public CollectorContext(Map collectorMap, Map collectorLoadMap) { - this.collectorMap = collectorMap; - this.collectorLoadMap = collectorLoadMap; - } - - /** - * Adds a collector with give name. Preserving this method for backward - * compatibility. - * - * @param element - * @param name String - * @param collector Collector - */ - public void add(String name, Collector collector) { - this.collectorMap.put(name, collector); + /** + * Constructor that creates the context using the specified instances to store + * data. + *

+ * If for instance the collector context needs to be shared with multiple + * threads a ConcurrentHashMap can be used. + *

+ * It is however more likely that the data will only be used after the walk or + * validation is complete rather then during processing. + * + * @param data the data map + */ + public CollectorContext(Map data) { + this.data = data; } /** - * Adds a collector or a simple object with give name. + * Sets data associated with a given key. * - * @param element - * @param object Object - * @param name String + * @param the return type + * @param key the key + * @param value the value + * @return the previous value */ - public void add(String name, Object object) { - this.collectorMap.put(name, object); + @SuppressWarnings("unchecked") + public T put(Object key, Object value) { + return (T) this.data.put(key, value); } /** - * Gets the data associated with a given name. Please note if you are collecting - * {@link Collector} instances you should wait till the validation is complete - * to gather all data. - *

- * When {@link CollectorContext} is used to collect {@link Collector} instances - * for a particular key, this method will return the {@link Collector} instance - * as long as {@link #loadCollectors} method is not called. Once - * the {@link #loadCollectors} method is called this method will - * return the actual data collected by collector. - * - * @param name String - * @return Object - */ - public Object get(String name) { - Object object = this.collectorMap.get(name); - if (object instanceof Collector && (this.collectorLoadMap.get(name) != null)) { - return this.collectorLoadMap.get(name); - } - return this.collectorMap.get(name); - } - - /** - * Gets the collector map. + * Gets the data associated with a given key. * - * @return the collector map + * @param the return type + * @param key the key + * @return the value */ - public Map getCollectorMap() { - return this.collectorMap; + @SuppressWarnings("unchecked") + public T get(Object key) { + return (T) this.data.get(key); } /** - * Returns all the collected data. Please look into {@link #get(String)} method for more details. - * @return Map - */ - public Map getAll() { - Map mergedMap = new HashMap<>(); - mergedMap.putAll(this.collectorMap); - mergedMap.putAll(this.collectorLoadMap); - return mergedMap; - } - - /** - * Combines data with Collector identified by the given name. + * Computes the value if absent. * - * @param name String - * @param data Object + * @param the return type + * @param key the key + * @param mappingFunction the mapping function + * @return the value */ - public void combineWithCollector(String name, Object data) { - Object object = this.collectorMap.get(name); - if (object instanceof Collector) { - Collector collector = (Collector) object; - collector.combine(data); - } + @SuppressWarnings("unchecked") + public T computeIfAbsent(Object key, Function mappingFunction) { + return (T) this.data.computeIfAbsent(key, mappingFunction); } /** - * Loads data from all collectors. + * Gets the data map. + * + * @return the data map */ - public void loadCollectors() { - Set> entrySet = this.collectorMap.entrySet(); - for (Entry entry : entrySet) { - if (entry.getValue() instanceof Collector) { - Collector collector = (Collector) entry.getValue(); - this.collectorLoadMap.put(entry.getKey(), collector.collect()); - } - } + public Map getData() { + return this.data; } } diff --git a/src/main/java/com/networknt/schema/CustomErrorMessageType.java b/src/main/java/com/networknt/schema/CustomErrorMessageType.java deleted file mode 100644 index ef08734ec..000000000 --- a/src/main/java/com/networknt/schema/CustomErrorMessageType.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2016 Network New Technologies Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.networknt.schema; - -public class CustomErrorMessageType implements ErrorMessageType { - private final String errorCode; - - private CustomErrorMessageType(String errorCode) { - this.errorCode = errorCode; - } - - public static ErrorMessageType of(String errorCode) { - return new CustomErrorMessageType(errorCode); - } - - @Override - public String getErrorCode() { - return errorCode; - } - -} \ No newline at end of file diff --git a/src/main/java/com/networknt/schema/DefaultJsonMetaSchemaFactory.java b/src/main/java/com/networknt/schema/DefaultJsonMetaSchemaFactory.java deleted file mode 100644 index 69a41b631..000000000 --- a/src/main/java/com/networknt/schema/DefaultJsonMetaSchemaFactory.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.networknt.schema; - -import java.util.Map; -import java.util.Map.Entry; - -import com.fasterxml.jackson.databind.JsonNode; -import com.networknt.schema.SpecVersion.VersionFlag; - -/** - * Default {@link JsonMetaSchemaFactory}. - */ -public class DefaultJsonMetaSchemaFactory implements JsonMetaSchemaFactory { - @Override - public JsonMetaSchema getMetaSchema(String iri, JsonSchemaFactory schemaFactory, SchemaValidatorsConfig config) { - // Is it a well-known dialect? - return SpecVersionDetector.detectOptionalVersion(iri) - .map(JsonSchemaFactory::checkVersion) - .map(JsonSchemaVersion::getInstance) - .orElseGet(() -> { - // Custom meta schema - return loadMetaSchema(iri, schemaFactory, config); - }); - } - - protected JsonMetaSchema loadMetaSchema(String iri, JsonSchemaFactory schemaFactory, - SchemaValidatorsConfig config) { - try { - JsonMetaSchema result = loadMetaSchemaBuilder(iri, schemaFactory, config).build(); - return result; - } catch (InvalidSchemaException e) { - throw e; - } catch (Exception e) { - ValidationMessage validationMessage = ValidationMessage.builder() - .message("Failed to load meta-schema ''{1}''").arguments(iri).build(); - throw new InvalidSchemaException(validationMessage, e); - } - } - - protected JsonMetaSchema.Builder loadMetaSchemaBuilder(String iri, JsonSchemaFactory schemaFactory, - SchemaValidatorsConfig config) { - JsonSchema schema = schemaFactory.getSchema(SchemaLocation.of(iri), config); - JsonMetaSchema.Builder builder = JsonMetaSchema.builder(iri, schema.getValidationContext().getMetaSchema()); - VersionFlag specification = schema.getValidationContext().getMetaSchema().getSpecification(); - if (specification != null) { - if (specification.getVersionFlagValue() >= VersionFlag.V201909.getVersionFlagValue()) { - // Process vocabularies - JsonNode vocabulary = schema.getSchemaNode().get("$vocabulary"); - if (vocabulary != null) { - builder.vocabularies(Map::clear); - for (Entry vocabs : vocabulary.properties()) { - builder.vocabulary(vocabs.getKey(), vocabs.getValue().booleanValue()); - } - } - } - } - return builder; - } - - private static class Holder { - private static final DefaultJsonMetaSchemaFactory INSTANCE = new DefaultJsonMetaSchemaFactory(); - } - - public static DefaultJsonMetaSchemaFactory getInstance() { - return Holder.INSTANCE; - } -} diff --git a/src/main/java/com/networknt/schema/DisallowUnknownJsonMetaSchemaFactory.java b/src/main/java/com/networknt/schema/DisallowUnknownJsonMetaSchemaFactory.java deleted file mode 100644 index 6ef036c61..000000000 --- a/src/main/java/com/networknt/schema/DisallowUnknownJsonMetaSchemaFactory.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.networknt.schema; - -/** - * A {@link JsonMetaSchemaFactory} that does not meta-schemas that aren't - * explicitly configured in the {@link JsonSchemaFactory}. - */ -public class DisallowUnknownJsonMetaSchemaFactory implements JsonMetaSchemaFactory { - @Override - public JsonMetaSchema getMetaSchema(String iri, JsonSchemaFactory schemaFactory, SchemaValidatorsConfig config) { - throw new InvalidSchemaException(ValidationMessage.builder() - .message("Unknown meta-schema ''{1}''. Only meta-schemas that are explicitly configured can be used.") - .arguments(iri).build()); - } - - private static class Holder { - private static final DisallowUnknownJsonMetaSchemaFactory INSTANCE = new DisallowUnknownJsonMetaSchemaFactory(); - } - - /** - * Gets the instance of {@link DisallowUnknownJsonMetaSchemaFactory}. - * - * @return the json meta schema factory - */ - public static DisallowUnknownJsonMetaSchemaFactory getInstance() { - return Holder.INSTANCE; - } -} diff --git a/src/main/java/com/networknt/schema/DiscriminatorContext.java b/src/main/java/com/networknt/schema/DiscriminatorContext.java deleted file mode 100644 index 1ab2ddd76..000000000 --- a/src/main/java/com/networknt/schema/DiscriminatorContext.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.networknt.schema; - -import java.util.HashMap; -import java.util.Map; - -import com.fasterxml.jackson.databind.node.ObjectNode; - -public class DiscriminatorContext { - private final Map discriminators = new HashMap<>(); - - private boolean discriminatorMatchFound = false; - - private boolean discriminatorIgnore = false; - - public void registerDiscriminator(final SchemaLocation schemaLocation, final ObjectNode discriminator) { - this.discriminators.put("#" + schemaLocation.getFragment().toString(), discriminator); - } - - public ObjectNode getDiscriminatorForPath(final SchemaLocation schemaLocation) { - return this.discriminators.get("#" + schemaLocation.getFragment().toString()); - } - - public ObjectNode getDiscriminatorForPath(final String schemaLocation) { - return this.discriminators.get(schemaLocation); - } - - public void markMatch() { - this.discriminatorMatchFound = true; - } - - /** - * Indicate that discriminator processing should be ignored. - *

- * This is used when the discriminator property value is missing from the data. - *

- * See issue #436 for background. - */ - public void markIgnore() { - this.discriminatorIgnore = true; - } - - public boolean isDiscriminatorMatchFound() { - return this.discriminatorMatchFound; - } - - public boolean isDiscriminatorIgnore() { - return this.discriminatorIgnore; - } - - /** - * Returns true if we have a discriminator active. In this case no valid match in anyOf should lead to validation failure - * - * @return true in case there are discriminator candidates - */ - public boolean isActive() { - return !this.discriminators.isEmpty(); - } -} \ No newline at end of file diff --git a/src/main/java/com/networknt/schema/DiscriminatorValidator.java b/src/main/java/com/networknt/schema/DiscriminatorValidator.java deleted file mode 100644 index c87ef6f7a..000000000 --- a/src/main/java/com/networknt/schema/DiscriminatorValidator.java +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright (c) 2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.networknt.schema; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.Map.Entry; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.node.ObjectNode; - -/** - * {@link JsonValidator} that resolves discriminator. - */ -public class DiscriminatorValidator extends BaseJsonValidator { - private final String propertyName; - private final Map mapping; - - public DiscriminatorValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, - JsonSchema parentSchema, ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.DISCRIMINATOR, - validationContext); - ObjectNode discriminator = schemaNode.isObject() ? (ObjectNode) schemaNode : null; - if (discriminator != null) { - JsonNode propertyName = discriminator.get("propertyName"); - this.propertyName = propertyName != null ? propertyName.asText() : ""; - JsonNode mappingNode = discriminator.get("mapping"); - ObjectNode mapping = mappingNode != null && mappingNode.isObject() ? (ObjectNode) mappingNode : null; - if (mapping != null) { - this.mapping = new HashMap<>(); - for (Iterator> iter = mapping.fields(); iter.hasNext();) { - Entry entry = iter.next(); - this.mapping.put(entry.getKey(), entry.getValue().asText()); - } - } else { - this.mapping = Collections.emptyMap(); - } - } else { - this.propertyName = ""; - this.mapping = Collections.emptyMap(); - } - } - - @Override - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, - JsonNodePath instanceLocation) { - // Do nothing - } - - /** - * Gets the property name of the discriminator. - * - * @return the property name - */ - public String getPropertyName() { - return propertyName; - } - - /** - * Gets the mapping to map the property name value to the schema name. - * - * @return the discriminator mappings - */ - public Map getMapping() { - return mapping; - } - - /** - * Checks based on the current {@link DiscriminatorContext} whether the provided {@link JsonSchema} a match against - * the current discriminator. - * - * @param currentDiscriminatorContext the currently active {@link DiscriminatorContext} - * @param discriminator the discriminator to use for the check - * @param discriminatorPropertyValue the value of the discriminator/propertyName field - * @param jsonSchema the {@link JsonSchema} to check - */ - public static void checkDiscriminatorMatch(final DiscriminatorContext currentDiscriminatorContext, - final ObjectNode discriminator, - final String discriminatorPropertyValue, - final JsonSchema jsonSchema) { - if (discriminatorPropertyValue == null) { - currentDiscriminatorContext.markIgnore(); - return; - } - - final JsonNode discriminatorMapping = discriminator.get("mapping"); - if (null == discriminatorMapping) { - checkForImplicitDiscriminatorMappingMatch(currentDiscriminatorContext, - discriminatorPropertyValue, - jsonSchema); - } else { - checkForExplicitDiscriminatorMappingMatch(currentDiscriminatorContext, - discriminatorPropertyValue, - discriminatorMapping, - jsonSchema); - if (!currentDiscriminatorContext.isDiscriminatorMatchFound() - && noExplicitDiscriminatorKeyOverride(discriminatorMapping, jsonSchema)) { - checkForImplicitDiscriminatorMappingMatch(currentDiscriminatorContext, - discriminatorPropertyValue, - jsonSchema); - } - } - } - - /** - * Rolls up all nested and compatible discriminators to the root discriminator of the type. Detects attempts to redefine - * the propertyName or mappings. - * - * @param currentDiscriminatorContext the currently active {@link DiscriminatorContext} - * @param discriminator the discriminator to use for the check - * @param schema the value of the discriminator/propertyName field - * @param instanceLocation the logging prefix - */ - public static void registerAndMergeDiscriminator(final DiscriminatorContext currentDiscriminatorContext, - final ObjectNode discriminator, - final JsonSchema schema, - final JsonNodePath instanceLocation) { - final JsonNode discriminatorOnSchema = schema.schemaNode.get("discriminator"); - if (null != discriminatorOnSchema && null != currentDiscriminatorContext - .getDiscriminatorForPath(schema.schemaLocation)) { - // this is where A -> B -> C inheritance exists, A has the root discriminator and B adds to the mapping - final JsonNode propertyName = discriminatorOnSchema.get("propertyName"); - if (null != propertyName) { - throw new JsonSchemaException(instanceLocation + " schema " + schema + " attempts redefining the discriminator property"); - } - final ObjectNode mappingOnContextDiscriminator = (ObjectNode) discriminator.get("mapping"); - final ObjectNode mappingOnCurrentSchemaDiscriminator = (ObjectNode) discriminatorOnSchema.get("mapping"); - if (null == mappingOnContextDiscriminator && null != mappingOnCurrentSchemaDiscriminator) { - // here we have a mapping on a nested discriminator and none on the root discriminator, so we can simply - // make it the root's - discriminator.set("mapping", discriminatorOnSchema); - } else if (null != mappingOnContextDiscriminator && null != mappingOnCurrentSchemaDiscriminator) { - // here we have to merge. The spec doesn't specify anything on this, but here we don't accept redefinition of - // mappings that already exist - final Iterator> fieldsToAdd = mappingOnCurrentSchemaDiscriminator.fields(); - while (fieldsToAdd.hasNext()) { - final Map.Entry fieldToAdd = fieldsToAdd.next(); - final String mappingKeyToAdd = fieldToAdd.getKey(); - final JsonNode mappingValueToAdd = fieldToAdd.getValue(); - - final JsonNode currentMappingValue = mappingOnContextDiscriminator.get(mappingKeyToAdd); - if (null != currentMappingValue && currentMappingValue != mappingValueToAdd) { - throw new JsonSchemaException(instanceLocation + "discriminator mapping redefinition from " + mappingKeyToAdd - + "/" + currentMappingValue + " to " + mappingValueToAdd); - } else if (null == currentMappingValue) { - mappingOnContextDiscriminator.set(mappingKeyToAdd, mappingValueToAdd); - } - } - } - } - currentDiscriminatorContext.registerDiscriminator(schema.schemaLocation, discriminator); - } - - private static void checkForImplicitDiscriminatorMappingMatch(final DiscriminatorContext currentDiscriminatorContext, - final String discriminatorPropertyValue, - final JsonSchema schema) { - if (schema.schemaLocation.getFragment().getName(-1).equals(discriminatorPropertyValue)) { - currentDiscriminatorContext.markMatch(); - } - } - - private static void checkForExplicitDiscriminatorMappingMatch(final DiscriminatorContext currentDiscriminatorContext, - final String discriminatorPropertyValue, - final JsonNode discriminatorMapping, - final JsonSchema schema) { - final Iterator> explicitMappings = discriminatorMapping.fields(); - while (explicitMappings.hasNext()) { - final Map.Entry candidateExplicitMapping = explicitMappings.next(); - if (candidateExplicitMapping.getKey().equals(discriminatorPropertyValue) - && ("#" + schema.schemaLocation.getFragment().toString()) - .equals(candidateExplicitMapping.getValue().asText())) { - currentDiscriminatorContext.markMatch(); - break; - } - } - } - - private static boolean noExplicitDiscriminatorKeyOverride(final JsonNode discriminatorMapping, - final JsonSchema parentSchema) { - final Iterator> explicitMappings = discriminatorMapping.fields(); - while (explicitMappings.hasNext()) { - final Map.Entry candidateExplicitMapping = explicitMappings.next(); - if (candidateExplicitMapping.getValue().asText() - .equals(parentSchema.schemaLocation.getFragment().toString())) { - return false; - } - } - return true; - } -} diff --git a/src/main/java/com/networknt/schema/ValidationMessage.java b/src/main/java/com/networknt/schema/Error.java similarity index 74% rename from src/main/java/com/networknt/schema/ValidationMessage.java rename to src/main/java/com/networknt/schema/Error.java index 013d8e257..6e117af76 100644 --- a/src/main/java/com/networknt/schema/ValidationMessage.java +++ b/src/main/java/com/networknt/schema/Error.java @@ -24,35 +24,36 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.networknt.schema.i18n.MessageFormatter; +import com.networknt.schema.path.NodePath; import com.networknt.schema.utils.CachingSupplier; -import com.networknt.schema.utils.StringUtils; +import com.networknt.schema.utils.Strings; import java.text.MessageFormat; import java.util.Arrays; +import java.util.HashMap; import java.util.Map; import java.util.function.Supplier; /** - * The output format. + * Represents an error which could be when parsing a schema or when validating + * an instance. * * @see JSON + * "https://github.com/json-schema-org/json-schema-spec/blob/main/specs/output/jsonschema-validation-output-machines.md">JSON * Schema */ -@JsonIgnoreProperties({ "messageSupplier", "schemaNode", "instanceNode", "valid", "error" }) -@JsonPropertyOrder({ "type", "code", "message", "instanceLocation", "property", "evaluationPath", "schemaLocation", +@JsonIgnoreProperties({ "messageSupplier", "schemaNode", "instanceNode", "valid" }) +@JsonPropertyOrder({ "keyword", "instanceLocation", "message", "evaluationPath", "schemaLocation", "messageKey", "arguments", "details" }) @JsonInclude(Include.NON_NULL) -public class ValidationMessage { - private final String type; - private final String code; +public class Error { + private final String keyword; @JsonSerialize(using = ToStringSerializer.class) - private final JsonNodePath evaluationPath; + private final NodePath evaluationPath; @JsonSerialize(using = ToStringSerializer.class) private final SchemaLocation schemaLocation; @JsonSerialize(using = ToStringSerializer.class) - private final JsonNodePath instanceLocation; - private final String property; + private final NodePath instanceLocation; private final Object[] arguments; private final String messageKey; private final Supplier messageSupplier; @@ -60,16 +61,14 @@ public class ValidationMessage { private final JsonNode instanceNode; private final JsonNode schemaNode; - ValidationMessage(String type, String code, JsonNodePath evaluationPath, SchemaLocation schemaLocation, - JsonNodePath instanceLocation, String property, Object[] arguments, Map details, + Error(String keyword, NodePath evaluationPath, SchemaLocation schemaLocation, + NodePath instanceLocation, Object[] arguments, Map details, String messageKey, Supplier messageSupplier, JsonNode instanceNode, JsonNode schemaNode) { super(); - this.type = type; - this.code = code; + this.keyword = keyword; this.instanceLocation = instanceLocation; this.schemaLocation = schemaLocation; this.evaluationPath = evaluationPath; - this.property = property; this.arguments = arguments; this.details = details; this.messageKey = messageKey; @@ -78,17 +77,13 @@ public class ValidationMessage { this.schemaNode = schemaNode; } - public String getCode() { - return code; - } - /** * The instance location is the location of the JSON value within the root * instance being validated. * * @return The path to the input json */ - public JsonNodePath getInstanceLocation() { + public NodePath getInstanceLocation() { return instanceLocation; } @@ -99,7 +94,7 @@ public JsonNodePath getInstanceLocation() { * * @return the evaluation path */ - public JsonNodePath getEvaluationPath() { + public NodePath getEvaluationPath() { return evaluationPath; } @@ -147,7 +142,17 @@ public JsonNode getSchemaNode() { * @return the property name */ public String getProperty() { - return property; + if (details == null) { + return null; + } + return (String) getDetails().get("property"); + } + + public Integer getIndex() { + if (details == null) { + return null; + } + return (Integer) getDetails().get("index"); } public Object[] getArguments() { @@ -175,31 +180,19 @@ public boolean isValid() { return messageSupplier != null; } - /** - * Gets the error. - * - * @return the error - */ - public String getError() { - String message = getMessage(); - int index = message.indexOf(':'); - if (index != -1) { - int length = message.length(); - while (index + 1 < length) { - if (message.charAt(index + 1) == ' ') { - index++; - } else { - break; - } - } - return message.substring(index + 1); - } - return message; - } - @Override public String toString() { - return messageSupplier.get(); + StringBuilder builder = new StringBuilder(); + if (instanceLocation != null) { + // Validation Error + builder.append(instanceLocation.toString()); + } else if (schemaLocation != null) { + // Parse Error + builder.append(schemaLocation.toString()); + } + builder.append(": "); + builder.append(messageSupplier.get()); + return builder.toString(); } @Override @@ -207,10 +200,9 @@ public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; - ValidationMessage that = (ValidationMessage) o; + Error that = (Error) o; - if (type != null ? !type.equals(that.type) : that.type != null) return false; - if (code != null ? !code.equals(that.code) : that.code != null) return false; + if (keyword != null ? !keyword.equals(that.keyword) : that.keyword != null) return false; if (instanceLocation != null ? !instanceLocation.equals(that.instanceLocation) : that.instanceLocation != null) return false; if (evaluationPath != null ? !evaluationPath.equals(that.evaluationPath) : that.evaluationPath != null) return false; if (details != null ? !details.equals(that.details) : that.details != null) return false; @@ -220,8 +212,7 @@ public boolean equals(Object o) { @Override public int hashCode() { - int result = type != null ? type.hashCode() : 0; - result = 31 * result + (code != null ? code.hashCode() : 0); + int result = keyword != null ? keyword.hashCode() : 0; result = 31 * result + (instanceLocation != null ? instanceLocation.hashCode() : 0); result = 31 * result + (evaluationPath != null ? evaluationPath.hashCode() : 0); result = 31 * result + (details != null ? details.hashCode() : 0); @@ -230,8 +221,8 @@ public int hashCode() { return result; } - public String getType() { - return type; + public String getKeyword() { + return keyword; } public static Builder builder() { @@ -248,12 +239,10 @@ public Builder self() { public static abstract class BuilderSupport { public abstract S self(); - protected String type; - protected String code; - protected JsonNodePath evaluationPath; + protected String keyword; + protected NodePath evaluationPath; protected SchemaLocation schemaLocation; - protected JsonNodePath instanceLocation; - protected String property; + protected NodePath instanceLocation; protected Object[] arguments; protected Map details; protected MessageFormat format; @@ -264,16 +253,28 @@ public static abstract class BuilderSupport { protected JsonNode instanceNode; protected JsonNode schemaNode; - public S type(String type) { - this.type = type; + public S keyword(String keyword) { + this.keyword = keyword; + return self(); + } + + public S property(String properties) { + if (this.details == null) { + this.details = new HashMap<>(); + } + this.details.put("property", properties); return self(); } - public S code(String code) { - this.code = code; + public S index(Integer index) { + if (this.details == null) { + this.details = new HashMap<>(); + } + this.details.put("index", index); return self(); } + /** * The instance location is the location of the JSON value within the root * instance being validated. @@ -281,7 +282,7 @@ public S code(String code) { * @param instanceLocation the instance location * @return the builder */ - public S instanceLocation(JsonNodePath instanceLocation) { + public S instanceLocation(NodePath instanceLocation) { this.instanceLocation = instanceLocation; return self(); } @@ -308,16 +309,11 @@ public S schemaLocation(SchemaLocation schemaLocation) { * @param evaluationPath the evaluation path * @return the builder */ - public S evaluationPath(JsonNodePath evaluationPath) { + public S evaluationPath(NodePath evaluationPath) { this.evaluationPath = evaluationPath; return self(); } - public S property(String property) { - this.property = property; - return self(); - } - public S arguments(Object... arguments) { this.arguments = arguments; return self(); @@ -333,11 +329,6 @@ public S format(MessageFormat format) { return self(); } - @Deprecated - public S customMessage(String message) { - return message(message); - } - /** * Explicitly sets the message pattern to be used. *

@@ -376,11 +367,11 @@ public S schemaNode(JsonNode schemaNode) { return self(); } - public ValidationMessage build() { + public Error build() { Supplier messageSupplier = this.messageSupplier; String messageKey = this.messageKey; - if (StringUtils.isNotBlank(this.message)) { + if (!Strings.isBlank(this.message)) { messageKey = this.message; if (this.message.contains("{")) { messageSupplier = new CachingSupplier<>(() -> { @@ -396,28 +387,19 @@ public ValidationMessage build() { return formatter.format(getMessageArguments()); }); } - return new ValidationMessage(type, code, evaluationPath, schemaLocation, instanceLocation, - property, arguments, details, messageKey, messageSupplier, this.instanceNode, this.schemaNode); - } - - protected Object[] getMessageArguments() { - Object[] objs = new Object[(arguments == null ? 0 : arguments.length) + 1]; - objs[0] = instanceLocation; - if (arguments != null) { - System.arraycopy(arguments, 0, objs, 1, objs.length - 1); - } - return objs; + return new Error(keyword, evaluationPath, schemaLocation, instanceLocation, + arguments, details, messageKey, messageSupplier, this.instanceNode, this.schemaNode); } - protected String getType() { - return type; + protected Object[] getMessageArguments() { + return arguments; } - protected String getCode() { - return code; + protected String getKeyword() { + return keyword; } - protected JsonNodePath getEvaluationPath() { + protected NodePath getEvaluationPath() { return evaluationPath; } @@ -425,14 +407,10 @@ protected SchemaLocation getSchemaLocation() { return schemaLocation; } - protected JsonNodePath getInstanceLocation() { + protected NodePath getInstanceLocation() { return instanceLocation; } - protected String getProperty() { - return property; - } - protected Object[] getArguments() { return arguments; } diff --git a/src/main/java/com/networknt/schema/ErrorMessageType.java b/src/main/java/com/networknt/schema/ErrorMessageType.java deleted file mode 100644 index 72b0acbd0..000000000 --- a/src/main/java/com/networknt/schema/ErrorMessageType.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2016 Network New Technologies Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.networknt.schema; - -public interface ErrorMessageType { - /** - * Your error code. Please ensure global uniqueness. Builtin error codes are sequential numbers. - *

- * Customer error codes could have a prefix to denote the namespace of your custom keywords and errors. - * - * @return error code - */ - String getErrorCode(); - - /** - * Get the text representation of the error code. - * - * @return The error code value. - */ - default String getErrorCodeValue() { - return getErrorCode(); - } - -} diff --git a/src/main/java/com/networknt/schema/ErrorMessages.java b/src/main/java/com/networknt/schema/ErrorMessages.java index 3cda00848..aaff9bf2a 100644 --- a/src/main/java/com/networknt/schema/ErrorMessages.java +++ b/src/main/java/com/networknt/schema/ErrorMessages.java @@ -18,7 +18,7 @@ public class ErrorMessages { * @param keyword the keyword * @return the custom error message */ - public static Map getErrorMessage(JsonSchema parentSchema, String errorMessageKeyword, + public static Map getErrorMessage(Schema parentSchema, String errorMessageKeyword, String keyword) { final JsonNode message = getMessageNode(errorMessageKeyword, parentSchema.schemaNode, parentSchema, keyword); if (message != null) { @@ -39,7 +39,7 @@ public static Map getErrorMessage(JsonSchema parentSchema, Strin return Collections.emptyMap(); } - protected static JsonNode getMessageNode(String errorMessageKeyword, JsonNode schemaNode, JsonSchema parentSchema, + protected static JsonNode getMessageNode(String errorMessageKeyword, JsonNode schemaNode, Schema parentSchema, String pname) { if (schemaNode.get(errorMessageKeyword) != null && schemaNode.get(errorMessageKeyword).get(pname) != null) { return schemaNode.get(errorMessageKeyword); diff --git a/src/main/java/com/networknt/schema/ExecutionConfig.java b/src/main/java/com/networknt/schema/ExecutionConfig.java index e4f83ee0f..0c84b1826 100644 --- a/src/main/java/com/networknt/schema/ExecutionConfig.java +++ b/src/main/java/com/networknt/schema/ExecutionConfig.java @@ -24,10 +24,18 @@ * Configuration per execution. */ public class ExecutionConfig { + private static class Holder { + private static final ExecutionConfig INSTANCE = ExecutionConfig.builder().build(); + } + + public static ExecutionConfig getInstance() { + return Holder.INSTANCE; + } + /** * The locale to use for formatting messages. */ - private Locale locale = Locale.ROOT; + private final Locale locale; /** * Determines if annotation collection is enabled. @@ -35,7 +43,7 @@ public class ExecutionConfig { * This does not affect annotation collection required for evaluating keywords * such as unevaluatedItems or unevaluatedProperties and only affects reporting. */ - private boolean annotationCollectionEnabled = false; + private final boolean annotationCollectionEnabled; /** * If annotation collection is enabled, determine which annotations to collect. @@ -43,43 +51,50 @@ public class ExecutionConfig { * This does not affect annotation collection required for evaluating keywords * such as unevaluatedItems or unevaluatedProperties and only affects reporting. */ - private Predicate annotationCollectionFilter = keyword -> false; + private final Predicate annotationCollectionFilter; /** * Since Draft 2019-09 format assertions are not enabled by default. */ - private Boolean formatAssertionsEnabled = null; + private final Boolean formatAssertionsEnabled; /** * Determine if the validation execution can fail fast. */ - private boolean failFast = false; + private final boolean failFast; /** - * Determine if debugging features such that logging are switched on. - *

- * This is turned off by default. This is present because the library attempts - * to log debug logs at each validation node and the logger evaluation on - * whether the logger is turned on is impacting performance. + * When set to true assumes that schema is used to validate incoming data from + * an API. */ - private boolean debugEnabled = false; + private final Boolean readOnly; /** - * Gets the locale to use for formatting messages. - * - * @return the locale + * When set to true assumes that schema is used to validate outgoing data from + * an API. */ - public Locale getLocale() { - return locale; + private final Boolean writeOnly; + + protected ExecutionConfig(Locale locale, boolean annotationCollectionEnabled, + Predicate annotationCollectionFilter, Boolean formatAssertionsEnabled, boolean failFast, + Boolean readOnly, Boolean writeOnly) { + super(); + this.locale = locale; + this.annotationCollectionEnabled = annotationCollectionEnabled; + this.annotationCollectionFilter = annotationCollectionFilter; + this.formatAssertionsEnabled = formatAssertionsEnabled; + this.failFast = failFast; + this.readOnly = readOnly; + this.writeOnly = writeOnly; } /** - * Sets the locale to use for formatting messages. + * Gets the locale to use for formatting messages. * - * @param locale the locale + * @return the locale */ - public void setLocale(Locale locale) { - this.locale = Objects.requireNonNull(locale, "Locale must not be null"); + public Locale getLocale() { + return locale; } /** @@ -97,15 +112,6 @@ public Boolean getFormatAssertionsEnabled() { return formatAssertionsEnabled; } - /** - * Sets the format assertion enabled flag. - * - * @param formatAssertionsEnabled the format assertions enabled flag - */ - public void setFormatAssertionsEnabled(Boolean formatAssertionsEnabled) { - this.formatAssertionsEnabled = formatAssertionsEnabled; - } - /** * Return if fast fail is enabled. * @@ -115,15 +121,6 @@ public boolean isFailFast() { return failFast; } - /** - * Sets whether fast fail is enabled. - * - * @param failFast true to fast fail - */ - public void setFailFast(boolean failFast) { - this.failFast = failFast; - } - /** * Return if annotation collection is enabled. *

@@ -139,21 +136,6 @@ public boolean isAnnotationCollectionEnabled() { return annotationCollectionEnabled; } - /** - * Sets whether the annotation collection is enabled. - *

- * This does not affect annotation collection required for evaluating keywords - * such as unevaluatedItems or unevaluatedProperties and only affects reporting. - *

- * The annotations to collect can be customized using the annotation collection - * predicate. - * - * @param annotationCollectionEnabled true to enable annotation collection - */ - public void setAnnotationCollectionEnabled(boolean annotationCollectionEnabled) { - this.annotationCollectionEnabled = annotationCollectionEnabled; - } - /** * Gets the predicate to determine if annotation collection is allowed for a * particular keyword. This only has an effect if annotation collection is @@ -173,37 +155,155 @@ public Predicate getAnnotationCollectionFilter() { } /** - * Predicate to determine if annotation collection is allowed for a particular - * keyword. This only has an effect if annotation collection is enabled. - *

- * The default value is to not collect any annotation keywords if annotation - * collection is enabled. - *

- * This does not affect annotation collection required for evaluating keywords - * such as unevaluatedItems or unevaluatedProperties and only affects reporting. + * Returns the value of the read only flag. * - * @param annotationCollectionFilter the predicate accepting the keyword + * @return the value of read only flag or null if not set */ - public void setAnnotationCollectionFilter(Predicate annotationCollectionFilter) { - this.annotationCollectionFilter = Objects.requireNonNull(annotationCollectionFilter, - "annotationCollectionFilter must not be null"); + public Boolean getReadOnly() { + return this.readOnly; } /** - * Gets if debugging features such as logging is switched on. + * Returns the value of the write only flag. * - * @return true if debug is enabled + * @return the value of the write only flag or null if not set */ - public boolean isDebugEnabled() { - return debugEnabled; + public Boolean getWriteOnly() { + return this.writeOnly; + } + + public static Builder builder() { + return new Builder(); + } + + public static Builder builder(ExecutionConfig config) { + Builder copy = new Builder(); + copy.locale = config.locale; + copy.annotationCollectionEnabled = config.annotationCollectionEnabled; + copy.annotationCollectionFilter = config.annotationCollectionFilter; + copy.formatAssertionsEnabled = config.formatAssertionsEnabled; + copy.failFast = config.failFast; + copy.readOnly = config.readOnly; + copy.writeOnly = config.writeOnly; + return copy; } /** - * Sets if debugging features such as logging is switched on. - * - * @param debugEnabled true to enable debug + * Builder for {@link ExecutionConfig}. + */ + public static class Builder extends BuilderSupport { + + @Override + protected Builder self() { + return this; + } + } + + /** + * Builder for {@link ExecutionConfig}. */ - public void setDebugEnabled(boolean debugEnabled) { - this.debugEnabled = debugEnabled; + public static abstract class BuilderSupport { + protected Locale locale = Locale.ROOT; + protected boolean annotationCollectionEnabled = false; + protected Predicate annotationCollectionFilter = keyword -> false; + protected Boolean formatAssertionsEnabled = null; + protected boolean failFast = false; + protected Boolean readOnly = null; + protected Boolean writeOnly = null; + + protected abstract T self(); + + /** + * Sets the locale to use for formatting messages. + * + * @param locale the locale + * @return the builder + */ + public T locale(Locale locale) { + this.locale = locale; + return self(); + } + + /** + * Sets whether the annotation collection is enabled. + *

+ * This does not affect annotation collection required for evaluating keywords + * such as unevaluatedItems or unevaluatedProperties and only affects reporting. + *

+ * The annotations to collect can be customized using the annotation collection + * predicate. + * + * @param annotationCollectionEnabled true to enable annotation collection + * @return the builder + */ + public T annotationCollectionEnabled(boolean annotationCollectionEnabled) { + this.annotationCollectionEnabled = annotationCollectionEnabled; + return self(); + } + + /** + * Predicate to determine if annotation collection is allowed for a particular + * keyword. This only has an effect if annotation collection is enabled. + *

+ * The default value is to not collect any annotation keywords if annotation + * collection is enabled. + *

+ * This does not affect annotation collection required for evaluating keywords + * such as unevaluatedItems or unevaluatedProperties and only affects reporting. + * + * @param annotationCollectionFilter the predicate accepting the keyword + * @return the builder + */ + public T annotationCollectionFilter(Predicate annotationCollectionFilter) { + this.annotationCollectionFilter = annotationCollectionFilter; + return self(); + } + + /** + * Sets the format assertion enabled flag. + * + * @param formatAssertionsEnabled the format assertions enabled flag + * @return the builder + */ + public T formatAssertionsEnabled(Boolean formatAssertionsEnabled) { + this.formatAssertionsEnabled = formatAssertionsEnabled; + return self(); + } + + /** + * Sets whether fast fail is enabled. + * + * @param failFast true to fast fail + * @return the builder + */ + public T failFast(boolean failFast) { + this.failFast = failFast; + return self(); + } + + public T readOnly(Boolean readOnly) { + this.readOnly = readOnly; + return self(); + } + + public T writeOnly(Boolean writeOnly) { + this.writeOnly = writeOnly; + return self(); + } + + /** + * Builds the {@link ExecutionConfig}. + * + * @return the execution configuration + */ + public ExecutionConfig build() { + Locale locale = this.locale; + if (locale == null) { + locale = Locale.getDefault(); + } + Objects.requireNonNull(annotationCollectionFilter, "annotationCollectionFilter must not be null"); + return new ExecutionConfig(locale, annotationCollectionEnabled, annotationCollectionFilter, + formatAssertionsEnabled, failFast, readOnly, writeOnly); + } } } diff --git a/src/main/java/com/networknt/schema/ExecutionContext.java b/src/main/java/com/networknt/schema/ExecutionContext.java index 57e6b7ac8..5cb78dba1 100644 --- a/src/main/java/com/networknt/schema/ExecutionContext.java +++ b/src/main/java/com/networknt/schema/ExecutionContext.java @@ -16,26 +16,37 @@ package com.networknt.schema; -import com.networknt.schema.annotation.JsonNodeAnnotations; -import com.networknt.schema.result.JsonNodeResults; - import java.util.ArrayList; -import java.util.Collections; +import java.util.HashMap; import java.util.List; -import java.util.Stack; +import java.util.Map; +import java.util.function.Consumer; + +import com.networknt.schema.annotation.Annotations; +import com.networknt.schema.keyword.DiscriminatorState; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.result.InstanceResults; +import com.networknt.schema.walk.WalkConfig; /** * Stores the execution context for the validation run. */ public class ExecutionContext { private ExecutionConfig executionConfig; + private WalkConfig walkConfig = null; private CollectorContext collectorContext = null; - private Stack discriminatorContexts = null; - private JsonNodeAnnotations annotations = null; - private JsonNodeResults results = null; - private List errors = new ArrayList<>(); + + private Annotations annotations = null; + private InstanceResults instanceResults = null; + private List errors = new ArrayList<>(); + + private Map discriminatorMapping = new HashMap<>(); - /** + public Map getDiscriminatorMapping() { + return discriminatorMapping; + } + + /** * This is used during the execution to determine if the validator should fail fast. *

* This valid is determined by the previous validator. @@ -46,7 +57,7 @@ public class ExecutionContext { * Creates an execution context. */ public ExecutionContext() { - this(new ExecutionConfig(), null); + this(ExecutionConfig.getInstance(), null); } /** @@ -55,7 +66,7 @@ public ExecutionContext() { * @param collectorContext the collector context */ public ExecutionContext(CollectorContext collectorContext) { - this(new ExecutionConfig(), collectorContext); + this(ExecutionConfig.getInstance(), collectorContext); } /** @@ -78,6 +89,27 @@ public ExecutionContext(ExecutionConfig executionConfig, CollectorContext collec this.executionConfig = executionConfig; } + /** + * Sets the walk configuration. + * + * @param walkConfig the walk configuration + */ + public void setWalkConfig(WalkConfig walkConfig) { + this.walkConfig = walkConfig; + } + + /** + * Gets the walk configuration. + * + * @return the walk configuration + */ + public WalkConfig getWalkConfig() { + if (this.walkConfig == null) { + this.walkConfig = WalkConfig.getInstance(); + } + return this.walkConfig; + } + /** * Gets the collector context. * @@ -117,18 +149,18 @@ public void setExecutionConfig(ExecutionConfig executionConfig) { this.executionConfig = executionConfig; } - public JsonNodeAnnotations getAnnotations() { + public Annotations getAnnotations() { if (this.annotations == null) { - this.annotations = new JsonNodeAnnotations(); + this.annotations = new Annotations(); } return annotations; } - public JsonNodeResults getResults() { - if (this.results == null) { - this.results = new JsonNodeResults(); + public InstanceResults getInstanceResults() { + if (this.instanceResults == null) { + this.instanceResults = new InstanceResults(); } - return results; + return instanceResults; } /** @@ -156,41 +188,40 @@ public void setFailFast(boolean failFast) { this.failFast = failFast; } - public DiscriminatorContext getCurrentDiscriminatorContext() { - if (this.discriminatorContexts == null) { - return null; - } - - if (!this.discriminatorContexts.empty()) { - return this.discriminatorContexts.peek(); - } - return null; // this is the case when we get on a schema that has a discriminator, but it's not used in anyOf - } - - public void enterDiscriminatorContext(final DiscriminatorContext ctx, @SuppressWarnings("unused") JsonNodePath instanceLocation) { - if (this.discriminatorContexts == null) { - this.discriminatorContexts = new Stack<>(); - } - this.discriminatorContexts.push(ctx); - } - - public void leaveDiscriminatorContextImmediately(@SuppressWarnings("unused") JsonNodePath instanceLocation) { - this.discriminatorContexts.pop(); - } - - public List getErrors() { + public List getErrors() { return this.errors; } - public void addError(ValidationMessage error) { + public void addError(Error error) { + this.errors.add(error); if (this.isFailFast()) { - this.errors = Collections.singletonList(error); throw new FailFastAssertionException(error); } - this.errors.add(error); } - public void setErrors(List errors) { + public void setErrors(List errors) { this.errors = errors; } + + /** + * Customize the execution configuration. + * + * @param customizer the customizer + */ + public void executionConfig(Consumer customizer) { + ExecutionConfig.Builder builder = ExecutionConfig.builder(this.getExecutionConfig()); + customizer.accept(builder); + this.executionConfig = builder.build(); + } + + /** + * Customize the walk configuration. + * + * @param customizer the customizer + */ + public void walkConfig(Consumer customizer) { + WalkConfig.Builder builder = WalkConfig.builder(this.getWalkConfig()); + customizer.accept(builder); + this.walkConfig = builder.build(); + } } diff --git a/src/main/java/com/networknt/schema/ExecutionContextCustomizer.java b/src/main/java/com/networknt/schema/ExecutionContextCustomizer.java index edaa94953..e79e64e79 100644 --- a/src/main/java/com/networknt/schema/ExecutionContextCustomizer.java +++ b/src/main/java/com/networknt/schema/ExecutionContextCustomizer.java @@ -24,10 +24,10 @@ public interface ExecutionContextCustomizer { /** * Customize the execution context before validation. *

- * The validation context should only be used for reference as it is shared. + * The schema context should only be used for reference as it is shared. * * @param executionContext the execution context - * @param validationContext the validation context for reference + * @param schemaContext the schema context for reference */ - void customize(ExecutionContext executionContext, ValidationContext validationContext); + void customize(ExecutionContext executionContext, SchemaContext schemaContext); } \ No newline at end of file diff --git a/src/main/java/com/networknt/schema/FailFastAssertionException.java b/src/main/java/com/networknt/schema/FailFastAssertionException.java index 84f8f6e84..0e033d28e 100644 --- a/src/main/java/com/networknt/schema/FailFastAssertionException.java +++ b/src/main/java/com/networknt/schema/FailFastAssertionException.java @@ -23,23 +23,23 @@ /** * Thrown when an assertion happens and the evaluation can fail fast. *

- * This doesn't extend off JsonSchemaException as it is used for flow control + * This doesn't extend off SchemaException as it is used for flow control * and is intended to be caught in a specific place. *

- * This will be caught in the JsonSchema validate method to be passed to the + * This will be caught in the Schema validate method to be passed to the * output formatter. */ public class FailFastAssertionException extends RuntimeException { private static final long serialVersionUID = 1L; - private final ValidationMessage error; + private final Error error; /** * Constructor. * * @param error the validation message */ - public FailFastAssertionException(ValidationMessage error) { + public FailFastAssertionException(Error error) { this.error = Objects.requireNonNull(error); } @@ -48,7 +48,7 @@ public FailFastAssertionException(ValidationMessage error) { * * @return the validation message */ - public ValidationMessage getError() { + public Error getError() { return this.error; } @@ -57,7 +57,7 @@ public ValidationMessage getError() { * * @return the validation message */ - public List getErrors() { + public List getErrors() { return Collections.singletonList(this.error); } diff --git a/src/main/java/com/networknt/schema/InvalidSchemaException.java b/src/main/java/com/networknt/schema/InvalidSchemaException.java index e60a34811..d575429e5 100644 --- a/src/main/java/com/networknt/schema/InvalidSchemaException.java +++ b/src/main/java/com/networknt/schema/InvalidSchemaException.java @@ -21,15 +21,15 @@ /** * Thrown when an invalid schema is used. */ -public class InvalidSchemaException extends JsonSchemaException { +public class InvalidSchemaException extends SchemaException { private static final long serialVersionUID = 1L; - public InvalidSchemaException(ValidationMessage message, Exception cause) { + public InvalidSchemaException(Error message, Exception cause) { super(Objects.requireNonNull(message)); this.initCause(cause); } - public InvalidSchemaException(ValidationMessage message) { + public InvalidSchemaException(Error message) { super(Objects.requireNonNull(message)); } } diff --git a/src/main/java/com/networknt/schema/InvalidSchemaRefException.java b/src/main/java/com/networknt/schema/InvalidSchemaRefException.java index 9aad3a5c6..adb655718 100644 --- a/src/main/java/com/networknt/schema/InvalidSchemaRefException.java +++ b/src/main/java/com/networknt/schema/InvalidSchemaRefException.java @@ -22,11 +22,11 @@ public class InvalidSchemaRefException extends InvalidSchemaException { private static final long serialVersionUID = 1L; - public InvalidSchemaRefException(ValidationMessage message, Exception cause) { + public InvalidSchemaRefException(Error message, Exception cause) { super(message, cause); } - public InvalidSchemaRefException(ValidationMessage message) { + public InvalidSchemaRefException(Error message) { super(message); } } diff --git a/src/main/java/com/networknt/schema/JsonSchemaFactory.java b/src/main/java/com/networknt/schema/JsonSchemaFactory.java deleted file mode 100644 index 6e4d56787..000000000 --- a/src/main/java/com/networknt/schema/JsonSchemaFactory.java +++ /dev/null @@ -1,849 +0,0 @@ -/* - * Copyright (c) 2016 Network New Technologies Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.networknt.schema; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.networknt.schema.SpecVersion.VersionFlag; -import com.networknt.schema.resource.DefaultSchemaLoader; -import com.networknt.schema.resource.SchemaLoader; -import com.networknt.schema.resource.SchemaLoaders; -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 org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.io.InputStream; -import java.net.URI; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.function.Consumer; - -/** - * Factory for building {@link JsonSchema} instances. The factory should be - * typically be created using {@link #getInstance(VersionFlag, Consumer)} and - * should be cached for performance. - *

- * JsonSchemaFactory instances are thread-safe provided its configuration is not - * modified. - */ -public class JsonSchemaFactory { - private static final Logger logger = LoggerFactory.getLogger(JsonSchemaFactory.class); - - public static class Builder { - private ObjectMapper jsonMapper = null; - private ObjectMapper yamlMapper = null; - private JsonNodeReader jsonNodeReader = null; - private String defaultMetaSchemaIri; - private final ConcurrentMap metaSchemas = new ConcurrentHashMap<>(); - private SchemaLoaders.Builder schemaLoadersBuilder = null; - private SchemaMappers.Builder schemaMappersBuilder = null; - private boolean enableSchemaCache = true; - private JsonMetaSchemaFactory metaSchemaFactory = null; - - /** - * Sets the json node reader to read the data. - *

- * If set this takes precedence over the configured json mapper and yaml mapper. - *

- * A location aware object reader can be created using JsonNodeReader.builder().locationAware().build(). - * - * @param jsonNodeReader the object reader - * @return the builder - */ - public Builder jsonNodeReader(JsonNodeReader jsonNodeReader) { - this.jsonNodeReader = jsonNodeReader; - return this; - } - - /** - * Sets the json mapper to read the data. - *

- * If the object reader is set this will not be used. - *

- * This is deprecated use an 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. - *

- * If the object reader is set this will not be used. - *

- * This is deprecated use an object reader instead. - * - * @param yamlMapper the yaml mapper - * @return the builder - */ - @Deprecated - public Builder yamlMapper(final ObjectMapper yamlMapper) { - this.yamlMapper = yamlMapper; - return this; - } - - public Builder defaultMetaSchemaIri(final String defaultMetaSchemaIri) { - this.defaultMetaSchemaIri = defaultMetaSchemaIri; - return this; - } - - public Builder metaSchemaFactory(final JsonMetaSchemaFactory jsonMetaSchemaFactory) { - this.metaSchemaFactory = jsonMetaSchemaFactory; - return this; - } - - public Builder metaSchema(final JsonMetaSchema jsonMetaSchema) { - this.metaSchemas.put(normalizeMetaSchemaUri(jsonMetaSchema.getIri()), jsonMetaSchema); - return this; - } - - public Builder metaSchemas(final Collection jsonMetaSchemas) { - for (JsonMetaSchema jsonMetaSchema : jsonMetaSchemas) { - metaSchema(jsonMetaSchema); - } - return this; - } - - public Builder metaSchemas(Consumer> customizer) { - customizer.accept(this.metaSchemas); - return this; - } - - public Builder enableSchemaCache(boolean enableSchemaCache) { - this.enableSchemaCache = enableSchemaCache; - return this; - } - - public Builder schemaLoaders(Consumer schemaLoadersBuilderCustomizer) { - if (this.schemaLoadersBuilder == null) { - this.schemaLoadersBuilder = SchemaLoaders.builder(); - } - schemaLoadersBuilderCustomizer.accept(this.schemaLoadersBuilder); - return this; - } - - public Builder schemaMappers(Consumer schemaMappersBuilderCustomizer) { - if (this.schemaMappersBuilder == null) { - this.schemaMappersBuilder = SchemaMappers.builder(); - } - schemaMappersBuilderCustomizer.accept(this.schemaMappersBuilder); - return this; - } - - @Deprecated - public Builder addMetaSchema(final JsonMetaSchema jsonMetaSchema) { - return metaSchema(jsonMetaSchema); - } - - @Deprecated - public Builder addMetaSchemas(final Collection jsonMetaSchemas) { - return metaSchemas(jsonMetaSchemas); - } - - public JsonSchemaFactory build() { - return new JsonSchemaFactory( - jsonMapper, - yamlMapper, - jsonNodeReader, - defaultMetaSchemaIri, - schemaLoadersBuilder, - schemaMappersBuilder, - metaSchemas, - enableSchemaCache, - metaSchemaFactory - ); - } - } - - private final ObjectMapper jsonMapper; - private final ObjectMapper yamlMapper; - private final JsonNodeReader jsonNodeReader; - private final String defaultMetaSchemaIri; - private final SchemaLoaders.Builder schemaLoadersBuilder; - private final SchemaMappers.Builder schemaMappersBuilder; - private final SchemaLoader schemaLoader; - private final ConcurrentMap metaSchemas; - private final ConcurrentMap schemaCache = new ConcurrentHashMap<>(); - private final boolean enableSchemaCache; - private final JsonMetaSchemaFactory metaSchemaFactory; - - private static final List DEFAULT_SCHEMA_LOADERS = SchemaLoaders.builder().build(); - private static final List DEFAULT_SCHEMA_MAPPERS = SchemaMappers.builder().build(); - - private JsonSchemaFactory( - ObjectMapper jsonMapper, - ObjectMapper yamlMapper, - JsonNodeReader jsonNodeReader, - String defaultMetaSchemaIri, - SchemaLoaders.Builder schemaLoadersBuilder, - SchemaMappers.Builder schemaMappersBuilder, - ConcurrentMap metaSchemas, - boolean enableSchemaCache, - JsonMetaSchemaFactory metaSchemaFactory) { - this.metaSchemas = metaSchemas; - if (defaultMetaSchemaIri == null || defaultMetaSchemaIri.trim().isEmpty()) { - throw new IllegalArgumentException("defaultMetaSchemaIri must not be null or empty"); - } else if (metaSchemas == null || metaSchemas.isEmpty()) { - throw new IllegalArgumentException("Json Meta Schemas must not be null or empty"); - } else if (this.metaSchemas.get(normalizeMetaSchemaUri(defaultMetaSchemaIri)) == null) { - throw new IllegalArgumentException("Meta Schema for default Meta Schema URI must be provided"); - } - this.jsonMapper = jsonMapper; - this.yamlMapper = yamlMapper; - this.jsonNodeReader = jsonNodeReader; - this.defaultMetaSchemaIri = defaultMetaSchemaIri; - this.schemaLoadersBuilder = schemaLoadersBuilder; - this.schemaMappersBuilder = schemaMappersBuilder; - this.schemaLoader = new DefaultSchemaLoader( - schemaLoadersBuilder != null ? schemaLoadersBuilder.build() : DEFAULT_SCHEMA_LOADERS, - schemaMappersBuilder != null ? schemaMappersBuilder.build() : DEFAULT_SCHEMA_MAPPERS); - this.enableSchemaCache = enableSchemaCache; - this.metaSchemaFactory = metaSchemaFactory; - } - - public SchemaLoader getSchemaLoader() { - return this.schemaLoader; - } - - /** - * Builder without keywords or formats. - * - * Typically {@link #builder(JsonSchemaFactory)} is what is required. - * - * @return a builder instance without any keywords or formats - usually not what one needs. - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Creates a factory with a default schema dialect. The schema dialect will only - * be used if the input does not specify a $schema. - * - * @param versionFlag the default dialect - * @return the factory - */ - public static JsonSchemaFactory getInstance(SpecVersion.VersionFlag versionFlag) { - return getInstance(versionFlag, null); - } - - /** - * Creates a factory with a default schema dialect. The schema dialect will only - * be used if the input does not specify a $schema. - * - * @param versionFlag the default dialect - * @param customizer to customize the factory - * @return the factory - */ - public static JsonSchemaFactory getInstance(SpecVersion.VersionFlag versionFlag, - Consumer customizer) { - JsonSchemaVersion jsonSchemaVersion = checkVersion(versionFlag); - JsonMetaSchema metaSchema = jsonSchemaVersion.getInstance(); - JsonSchemaFactory.Builder builder = builder().defaultMetaSchemaIri(metaSchema.getIri()) - .metaSchema(metaSchema); - if (customizer != null) { - customizer.accept(builder); - } - return builder.build(); - } - - /** - * Gets the json schema version to get the meta schema. - *

- * This throws an {@link IllegalArgumentException} for an unsupported value. - * - * @param versionFlag the schema dialect - * @return the version - */ - public static JsonSchemaVersion checkVersion(SpecVersion.VersionFlag versionFlag){ - if (null == versionFlag) return null; - switch (versionFlag) { - case V202012: return new Version202012(); - case V201909: return new Version201909(); - case V7: return new Version7(); - case V6: return new Version6(); - case V4: return new Version4(); - default: throw new IllegalArgumentException("Unsupported value" + versionFlag); - } - } - - /** - * Builder from an existing {@link JsonSchemaFactory}. - *

- * - * JsonSchemaFactory.builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V201909)); - * - * - * @param blueprint the existing factory - * @return the builder - */ - public static Builder builder(final JsonSchemaFactory blueprint) { - Builder builder = builder() - .metaSchemas(blueprint.metaSchemas.values()) - .defaultMetaSchemaIri(blueprint.defaultMetaSchemaIri) - .jsonMapper(blueprint.jsonMapper) - .yamlMapper(blueprint.yamlMapper) - .jsonNodeReader(blueprint.jsonNodeReader); - if (blueprint.schemaLoadersBuilder != null) { - builder.schemaLoadersBuilder = SchemaLoaders.builder().with(blueprint.schemaLoadersBuilder); - } - if (blueprint.schemaMappersBuilder != null) { - builder.schemaMappersBuilder = SchemaMappers.builder().with(blueprint.schemaMappersBuilder); - } - return builder; - } - - /** - * Creates a json schema from initial input. - * - * @param schemaUri the schema location - * @param schemaNode the schema data node - * @param config the config to use - * @return the schema - */ - protected JsonSchema newJsonSchema(final SchemaLocation schemaUri, final JsonNode schemaNode, final SchemaValidatorsConfig config) { - final ValidationContext validationContext = createValidationContext(schemaNode, config); - JsonSchema jsonSchema = doCreate(validationContext, getSchemaLocation(schemaUri), - new JsonNodePath(validationContext.getConfig().getPathType()), schemaNode, null, false); - preload(jsonSchema, config); - return jsonSchema; - } - - /** - * Preloads the json schema if the configuration option is set. - * - * @param jsonSchema the schema to preload - * @param config containing the configuration option - */ - private void preload(JsonSchema jsonSchema, SchemaValidatorsConfig config) { - if (config.isPreloadJsonSchema()) { - try { - /* - * Attempt to preload and resolve $refs for performance. - */ - jsonSchema.initializeValidators(); - } catch (Exception e) { - /* - * Do nothing here to allow the schema to be cached even if the remote $ref - * cannot be resolved at this time. If the developer wants to ensure that all - * remote $refs are currently resolvable they need to call initializeValidators - * themselves. - */ - } - } - } - - public JsonSchema create(ValidationContext validationContext, SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, JsonSchema parentSchema) { - return doCreate(validationContext, schemaLocation, evaluationPath, schemaNode, parentSchema, false); - } - - private JsonSchema doCreate(ValidationContext validationContext, SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, JsonSchema parentSchema, boolean suppressSubSchemaRetrieval) { - return JsonSchema.from(withMetaSchema(validationContext, schemaNode), schemaLocation, evaluationPath, - schemaNode, parentSchema, suppressSubSchemaRetrieval); - } - - /** - * Determines the validation context to use for the schema given the parent - * validation context. - *

- * This is typically the same validation context unless the schema has a - * different $schema from the parent. - *

- * If the schema does not define a $schema, the parent should be used. - * - * @param validationContext the parent validation context - * @param schemaNode the schema node - * @return the validation context to use - */ - private ValidationContext withMetaSchema(ValidationContext validationContext, JsonNode schemaNode) { - JsonMetaSchema metaSchema = getMetaSchema(schemaNode, validationContext.getConfig()); - if (metaSchema != null && !metaSchema.getIri().equals(validationContext.getMetaSchema().getIri())) { - SchemaValidatorsConfig config = validationContext.getConfig(); - if (metaSchema.getKeywords().containsKey("discriminator") && !config.isDiscriminatorKeywordEnabled()) { - config = SchemaValidatorsConfig.builder(config) - .discriminatorKeywordEnabled(true) - .nullableKeywordEnabled(true) - .build(); - } - return new ValidationContext(metaSchema, validationContext.getJsonSchemaFactory(), config, - validationContext.getSchemaReferences(), validationContext.getSchemaResources(), - validationContext.getDynamicAnchors()); - } - return validationContext; - } - - /** - * Gets the base IRI from the schema retrieval IRI if present otherwise return - * one with a null base IRI. - *

- * Note that the resolving of the $id or id in the schema node will take place - * in the JsonSchema constructor. - * - * @param schemaLocation the schema retrieval uri - * @return the schema location - */ - protected SchemaLocation getSchemaLocation(SchemaLocation schemaLocation) { - return schemaLocation != null ? schemaLocation : SchemaLocation.DOCUMENT; - } - - protected ValidationContext createValidationContext(final JsonNode schemaNode, SchemaValidatorsConfig config) { - final JsonMetaSchema jsonMetaSchema = getMetaSchemaOrDefault(schemaNode, config); - SchemaValidatorsConfig configResult = config; - if (jsonMetaSchema.getKeywords().containsKey("discriminator") && !config.isDiscriminatorKeywordEnabled()) { - configResult = SchemaValidatorsConfig.builder(config) - .discriminatorKeywordEnabled(true) - .nullableKeywordEnabled(true) - .build(); - } - return new ValidationContext(jsonMetaSchema, this, configResult); - } - - private JsonMetaSchema getMetaSchema(final JsonNode schemaNode, SchemaValidatorsConfig config) { - final JsonNode iriNode = schemaNode.get("$schema"); - if (iriNode != null && iriNode.isTextual()) { - JsonMetaSchema result = metaSchemas.computeIfAbsent(normalizeMetaSchemaUri(iriNode.textValue()), - id -> loadMetaSchema(id, config)); - return result; - } - return null; - } - - private JsonMetaSchema getMetaSchemaOrDefault(final JsonNode schemaNode, SchemaValidatorsConfig config) { - final JsonNode iriNode = schemaNode.get("$schema"); - if (iriNode != null && !iriNode.isNull() && !iriNode.isTextual()) { - throw new JsonSchemaException("Unknown MetaSchema: " + iriNode); - } - final String iri = iriNode == null || iriNode.isNull() ? defaultMetaSchemaIri : iriNode.textValue(); - return getMetaSchema(iri, config); - } - - /** - * Gets the meta-schema that is available to the factory. - * - * @param iri the IRI of the meta-schema - * @param config the schema validators config - * @return the meta-schema - */ - public JsonMetaSchema getMetaSchema(String iri, SchemaValidatorsConfig config) { - String key = normalizeMetaSchemaUri(iri); - JsonMetaSchema result = metaSchemas.computeIfAbsent(key, id -> loadMetaSchema(id, config)); - return result; - } - - /** - * Loads the meta-schema from the configured meta-schema factory. - * - * @param iri the IRI of the meta-schema - * @param config the schema validators config - * @return the meta-schema - */ - protected JsonMetaSchema loadMetaSchema(String iri, SchemaValidatorsConfig config) { - return this.metaSchemaFactory != null ? this.metaSchemaFactory.getMetaSchema(iri, this, config) - : DefaultJsonMetaSchemaFactory.getInstance().getMetaSchema(iri, this, config); - } - - JsonNode readTree(String content, InputFormat inputFormat) throws IOException { - if (this.jsonNodeReader == null) { - return getObjectMapper(inputFormat).readTree(content); - } else { - return this.jsonNodeReader.readTree(content, inputFormat); - } - } - - JsonNode readTree(InputStream content, InputFormat inputFormat) throws IOException { - if (this.jsonNodeReader == null) { - return getObjectMapper(inputFormat).readTree(content); - } else { - return this.jsonNodeReader.readTree(content, inputFormat); - } - } - - ObjectMapper getObjectMapper(InputFormat inputFormat) { - if (InputFormat.JSON.equals(inputFormat)) { - return getJsonMapper(); - } else if (InputFormat.YAML.equals(inputFormat)) { - return getYamlMapper(); - } - throw new IllegalArgumentException("Unsupported input format "+inputFormat); - } - - /** - * Gets the schema. - *

- * Using this is not recommended as there is potentially no base IRI for - * resolving references to the absolute IRI. - * - * @param schema the schema data as a string - * @param config the config - * @return the schema - */ - public JsonSchema getSchema(final String schema, final SchemaValidatorsConfig config) { - return getSchema(schema, InputFormat.JSON, config); - } - - /** - * Gets the schema. - *

- * Using this is not recommended as there is potentially no base IRI for - * resolving references to the absolute IRI. - * - * @param schema the schema data as a string - * @param inputFormat input format - * @param config the config - * @return the schema - */ - public JsonSchema getSchema(final String schema, InputFormat inputFormat, final SchemaValidatorsConfig config) { - try { - final JsonNode schemaNode = readTree(schema, inputFormat); - return newJsonSchema(null, schemaNode, config); - } catch (IOException ioe) { - logger.error("Failed to load json schema!", ioe); - throw new JsonSchemaException(ioe); - } - } - - - /** - * Gets the schema. - *

- * Using this is not recommended as there is potentially no base IRI for - * resolving references to the absolute IRI. - * - * @param schema the schema data as a string - * @return the schema - */ - public JsonSchema getSchema(final String schema) { - return getSchema(schema, createSchemaValidatorsConfig()); - } - - /** - * Gets the schema. - *

- * Using this is not recommended as there is potentially no base IRI for - * resolving references to the absolute IRI. - * - * @param schema the schema data as a string - * @param inputFormat input format - * @return the schema - */ - public JsonSchema getSchema(final String schema, InputFormat inputFormat) { - return getSchema(schema, inputFormat, createSchemaValidatorsConfig()); - } - - /** - * Gets the schema. - *

- * Using this is not recommended as there is potentially no base IRI for - * resolving references to the absolute IRI. - * - * @param schemaStream the input stream with the schema data - * @param config the config - * @return the schema - */ - public JsonSchema getSchema(final InputStream schemaStream, final SchemaValidatorsConfig config) { - return getSchema(schemaStream, InputFormat.JSON, config); - } - - /** - * Gets the schema. - *

- * Using this is not recommended as there is potentially no base IRI for - * resolving references to the absolute IRI. - * - * @param schemaStream the input stream with the schema data - * @param inputFormat input format - * @param config the config - * @return the schema - */ - public JsonSchema getSchema(final InputStream schemaStream, InputFormat inputFormat, final SchemaValidatorsConfig config) { - try { - final JsonNode schemaNode = readTree(schemaStream, inputFormat); - return newJsonSchema(null, schemaNode, config); - } catch (IOException ioe) { - logger.error("Failed to load json schema!", ioe); - throw new JsonSchemaException(ioe); - } - } - - /** - * Gets the schema. - *

- * Using this is not recommended as there is potentially no base IRI for - * resolving references to the absolute IRI. - * - * @param schemaStream the input stream with the schema data - * @return the schema - */ - public JsonSchema getSchema(final InputStream schemaStream) { - return getSchema(schemaStream, createSchemaValidatorsConfig()); - } - - /** - * Gets the schema. - * - * @param schemaUri the absolute IRI of the schema which can map to the retrieval IRI. - * @param config the config - * @return the schema - */ - public JsonSchema getSchema(final SchemaLocation schemaUri, final SchemaValidatorsConfig config) { - JsonSchema schema = loadSchema(schemaUri, config); - preload(schema, config); - return schema; - } - - /** - * Loads the schema. - * - * @param schemaUri the absolute IRI of the schema which can map to the retrieval IRI. - * @param config the config - * @return the schema - */ - protected JsonSchema loadSchema(final SchemaLocation schemaUri, final SchemaValidatorsConfig config) { - if (enableSchemaCache) { - // ConcurrentHashMap computeIfAbsent does not allow calls that result in a - // recursive update to the map. - // The getMapperSchema potentially recurses to call back to getSchema again - JsonSchema cachedUriSchema = schemaCache.get(schemaUri); - if (cachedUriSchema == null) { - synchronized (this) { // acquire lock on shared factory object to prevent deadlock - cachedUriSchema = schemaCache.get(schemaUri); - if (cachedUriSchema == null) { - cachedUriSchema = getMappedSchema(schemaUri, config); - if (cachedUriSchema != null) { - schemaCache.put(schemaUri, cachedUriSchema); - } - } - } - } - return cachedUriSchema.withConfig(config); - } - return getMappedSchema(schemaUri, config); - } - - ObjectMapper getYamlMapper() { - return this.yamlMapper != null ? this.yamlMapper : YamlMapperFactory.getInstance(); - } - - ObjectMapper getJsonMapper() { - return this.jsonMapper != null ? this.jsonMapper : JsonMapperFactory.getInstance(); - } - - /** - * Creates a schema validators config. - * - * @return the schema validators config - */ - protected SchemaValidatorsConfig createSchemaValidatorsConfig() { - // Remain as constructor until constructor is removed - return new SchemaValidatorsConfig(); - } - - protected JsonSchema getMappedSchema(final SchemaLocation schemaUri, SchemaValidatorsConfig config) { - try (InputStream inputStream = this.schemaLoader.getSchema(schemaUri.getAbsoluteIri()).getInputStream()) { - if (inputStream == null) { - throw new IOException("Cannot load schema at " + schemaUri); - } - final JsonNode schemaNode; - if (isYaml(schemaUri)) { - schemaNode = readTree(inputStream, InputFormat.YAML); - } else { - schemaNode = readTree(inputStream, InputFormat.JSON); - } - - final JsonMetaSchema jsonMetaSchema = getMetaSchemaOrDefault(schemaNode, config); - JsonNodePath evaluationPath = new JsonNodePath(config.getPathType()); - if (schemaUri.getFragment() == null - || schemaUri.getFragment().getNameCount() == 0) { - // Schema without fragment - ValidationContext validationContext = new ValidationContext(jsonMetaSchema, this, config); - return doCreate(validationContext, schemaUri, evaluationPath, schemaNode, null, true /* retrieved via id, resolving will not change anything */); - } else { - // Schema with fragment pointing to sub schema - final ValidationContext validationContext = createValidationContext(schemaNode, config); - SchemaLocation documentLocation = new SchemaLocation(schemaUri.getAbsoluteIri()); - JsonSchema document = doCreate(validationContext, documentLocation, evaluationPath, schemaNode, null, false); - return document.getRefSchema(schemaUri.getFragment()); - } - } catch (IOException e) { - logger.error("Failed to load json schema from {}", schemaUri.getAbsoluteIri(), e); - JsonSchemaException exception = new JsonSchemaException("Failed to load json schema from "+schemaUri.getAbsoluteIri()); - exception.initCause(e); - throw exception; - } - } - - /** - * Gets the schema. - * - * @param schemaUri the absolute IRI of the schema which can map to the retrieval IRI. - * @return the schema - */ - public JsonSchema getSchema(final URI schemaUri) { - return getSchema(SchemaLocation.of(schemaUri.toString()), createSchemaValidatorsConfig()); - } - - /** - * Gets the schema. - * - * @param schemaUri the absolute IRI of the schema which can map to the retrieval IRI. - * @param jsonNode the node - * @param config the config - * @return the schema - */ - public JsonSchema getSchema(final URI schemaUri, final JsonNode jsonNode, final SchemaValidatorsConfig config) { - return newJsonSchema(SchemaLocation.of(schemaUri.toString()), jsonNode, config); - } - - /** - * Gets the schema. - * - * @param schemaUri the absolute IRI of the schema which can map to the retrieval IRI. - * @param jsonNode the node - * @return the schema - */ - public JsonSchema getSchema(final URI schemaUri, final JsonNode jsonNode) { - return newJsonSchema(SchemaLocation.of(schemaUri.toString()), jsonNode, createSchemaValidatorsConfig()); - } - - /** - * Gets the schema. - * - * @param schemaUri the absolute IRI of the schema which can map to the retrieval IRI. - * @return the schema - */ - public JsonSchema getSchema(final SchemaLocation schemaUri) { - return getSchema(schemaUri, createSchemaValidatorsConfig()); - } - - /** - * Gets the schema. - * - * @param schemaUri the base absolute IRI - * @param jsonNode the node - * @param config the config - * @return the schema - */ - public JsonSchema getSchema(final SchemaLocation schemaUri, final JsonNode jsonNode, final SchemaValidatorsConfig config) { - return newJsonSchema(schemaUri, jsonNode, config); - } - - /** - * Gets the schema. - * - * @param schemaUri the base absolute IRI - * @param jsonNode the node - * @return the schema - */ - public JsonSchema getSchema(final SchemaLocation schemaUri, final JsonNode jsonNode) { - return newJsonSchema(schemaUri, jsonNode, createSchemaValidatorsConfig()); - } - - /** - * Gets the schema. - *

- * Using this is not recommended as there is potentially no base IRI for - * resolving references to the absolute IRI. - *

- * Prefer {@link #getSchema(SchemaLocation, JsonNode, SchemaValidatorsConfig)} - * instead to ensure the base IRI if no id is present. - * - * @param jsonNode the node - * @param config the config - * @return the schema - */ - public JsonSchema getSchema(final JsonNode jsonNode, final SchemaValidatorsConfig config) { - return newJsonSchema(null, jsonNode, config); - } - - /** - * Gets the schema. - *

- * Using this is not recommended as there is potentially no base IRI for - * resolving references to the absolute IRI. - *

- * Prefer {@link #getSchema(SchemaLocation, JsonNode)} instead to ensure the - * base IRI if no id is present. - * - * @param jsonNode the node - * @return the schema - */ - public JsonSchema getSchema(final JsonNode jsonNode) { - return newJsonSchema(null, jsonNode, createSchemaValidatorsConfig()); - } - - private boolean isYaml(final SchemaLocation schemaUri) { - final String schemeSpecificPart = schemaUri.getAbsoluteIri().toString(); - final int idx = schemeSpecificPart.lastIndexOf('.'); - - if (idx == -1) { - // no extension; assume json - return false; - } - - final String extension = schemeSpecificPart.substring(idx); - return (".yml".equals(extension) || ".yaml".equals(extension)); - } - - /** - * Normalizes the standard JSON schema dialects. - *

- * This should not normalize any other unrecognized dialects. - * - * @param id the $schema identifier - * @return the normalized uri - */ - static protected String normalizeMetaSchemaUri(String id) { - boolean found = false; - for (VersionFlag flag : SpecVersion.VersionFlag.values()) { - if(flag.getId().equals(id)) { - found = true; - break; - } - } - if (!found) { - if (id.contains("://json-schema.org/draft")) { - // unnormalized $schema - if (id.contains("/draft-07/")) { - id = SchemaId.V7; - } else if (id.contains("/draft/2019-09/")) { - id = SchemaId.V201909; - } else if (id.contains("/draft/2020-12/")) { - id = SchemaId.V202012; - } else if (id.contains("/draft-04/")) { - id = SchemaId.V4; - } else if (id.contains("/draft-06/")) { - id = SchemaId.V6; - } - } - } - return id; - } -} diff --git a/src/main/java/com/networknt/schema/JsonSchemaVersion.java b/src/main/java/com/networknt/schema/JsonSchemaVersion.java deleted file mode 100644 index 47f9f6404..000000000 --- a/src/main/java/com/networknt/schema/JsonSchemaVersion.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.networknt.schema; - -/** - * Json schema version. - */ -public interface JsonSchemaVersion { - /** - * Gets the meta-schema. - * - * @return the instance - */ - JsonMetaSchema getInstance(); -} diff --git a/src/main/java/com/networknt/schema/MessageSourceValidationMessage.java b/src/main/java/com/networknt/schema/MessageSourceError.java similarity index 64% rename from src/main/java/com/networknt/schema/MessageSourceValidationMessage.java rename to src/main/java/com/networknt/schema/MessageSourceError.java index 1871236a2..eb8ca652a 100644 --- a/src/main/java/com/networknt/schema/MessageSourceValidationMessage.java +++ b/src/main/java/com/networknt/schema/MessageSourceError.java @@ -17,24 +17,21 @@ import java.util.Locale; import java.util.Map; -import java.util.function.BiConsumer; import com.networknt.schema.i18n.MessageSource; /** - * MessageSourceValidationMessage. + * MessageSourceError. */ -public class MessageSourceValidationMessage { +public class MessageSourceError { - public static Builder builder(MessageSource messageSource, Map errorMessage, - BiConsumer observer) { - return new Builder(messageSource, errorMessage, observer); + public static Builder builder(MessageSource messageSource, Map errorMessage) { + return new Builder(messageSource, errorMessage); } public static class Builder extends BuilderSupport { - public Builder(MessageSource messageSource, Map errorMessage, - BiConsumer observer) { - super(messageSource, errorMessage, observer); + public Builder(MessageSource messageSource, Map errorMessage) { + super(messageSource, errorMessage); } @Override @@ -43,28 +40,24 @@ public Builder self() { } } - public abstract static class BuilderSupport extends ValidationMessage.BuilderSupport { - private final BiConsumer observer; + public abstract static class BuilderSupport extends Error.BuilderSupport { private final MessageSource messageSource; private final Map errorMessage; - private boolean failFast; private Locale locale; - public BuilderSupport(MessageSource messageSource, Map errorMessage, - BiConsumer observer) { + public BuilderSupport(MessageSource messageSource, Map errorMessage) { this.messageSource = messageSource; - this.observer = observer; this.errorMessage = errorMessage; } @Override - public ValidationMessage build() { + public Error build() { // Use custom error message if present String messagePattern = null; if (this.errorMessage != null) { messagePattern = this.errorMessage.get(""); - if (this.property != null) { - String specificMessagePattern = this.errorMessage.get(this.property); + if (this.details != null && this.details.get("property") != null) { + String specificMessagePattern = this.errorMessage.get(this.details.get("property")); if (specificMessagePattern != null) { messagePattern = specificMessagePattern; } @@ -79,21 +72,12 @@ public ValidationMessage build() { this.messageFormatter = args -> this.messageSource.getMessage(this.messageKey, this.locale == null ? Locale.ROOT : this.locale, args); } - ValidationMessage validationMessage = super.build(); - if (this.observer != null) { - this.observer.accept(validationMessage, this.failFast); - } - return validationMessage; + return super.build(); } public S locale(Locale locale) { this.locale = locale; return self(); } - - public S failFast(boolean failFast) { - this.failFast = failFast; - return self(); - } } } diff --git a/src/main/java/com/networknt/schema/OneOfValidator.java b/src/main/java/com/networknt/schema/OneOfValidator.java deleted file mode 100644 index 0ad80e99c..000000000 --- a/src/main/java/com/networknt/schema/OneOfValidator.java +++ /dev/null @@ -1,244 +0,0 @@ -/* - * Copyright (c) 2016 Network New Technologies Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.networknt.schema; - -import java.util.ArrayList; -import java.util.List; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.node.ObjectNode; - -/** - * {@link JsonValidator} for oneOf. - */ -public class OneOfValidator extends BaseJsonValidator { - private static final Logger logger = LoggerFactory.getLogger(OneOfValidator.class); - - private final List schemas; - - private Boolean canShortCircuit = null; - - public OneOfValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.ONE_OF, validationContext); - if (!schemaNode.isArray()) { - JsonType nodeType = TypeFactory.getValueNodeType(schemaNode, this.validationContext.getConfig()); - throw new JsonSchemaException(message().instanceNode(schemaNode) - .instanceLocation(schemaLocation.getFragment()) - .messageKey("type") - .arguments(nodeType.toString(), "array") - .build()); - } - int size = schemaNode.size(); - this.schemas = new ArrayList<>(size); - for (int i = 0; i < size; i++) { - JsonNode childNode = schemaNode.get(i); - this.schemas.add(validationContext.newSchema( schemaLocation.append(i), evaluationPath.append(i), childNode, parentSchema)); - } - } - - @Override - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, - JsonNodePath instanceLocation) { - validate(executionContext, node, rootNode, instanceLocation, false); - } - - protected void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, - JsonNodePath instanceLocation, boolean walk) { - debug(logger, executionContext, node, rootNode, instanceLocation); - int numberOfValidSchema = 0; - int index = 0; - List indexes = null; - List existingErrors = executionContext.getErrors(); - List childErrors = null; - List schemaErrors = new ArrayList<>(); - executionContext.setErrors(schemaErrors); - // Save flag as nested schema evaluation shouldn't trigger fail fast - boolean failFast = executionContext.isFailFast(); - boolean addMessages = true; - try { - DiscriminatorValidator discriminator = null; - if (this.validationContext.getConfig().isDiscriminatorKeywordEnabled()) { - DiscriminatorContext discriminatorContext = new DiscriminatorContext(); - executionContext.enterDiscriminatorContext(discriminatorContext, instanceLocation); - - // check if discriminator present - discriminator = (DiscriminatorValidator) this.getParentSchema().getValidators().stream() - .filter(v -> "discriminator".equals(v.getKeyword())).findFirst().orElse(null); - if (discriminator != null) { - // this is just to make the discriminator context active - discriminatorContext.registerDiscriminator(discriminator.getSchemaLocation(), - (ObjectNode) discriminator.getSchemaNode()); - } - } - executionContext.setFailFast(false); - for (JsonSchema schema : this.schemas) { - schemaErrors.clear(); - if (!walk) { - schema.validate(executionContext, node, rootNode, instanceLocation); - } else { - schema.walk(executionContext, node, rootNode, instanceLocation, true); - } - - // check if any validation errors have occurred - if (schemaErrors.isEmpty()) { // No new errors - numberOfValidSchema++; - if (indexes == null) { - indexes = new ArrayList<>(); - } - indexes.add(Integer.toString(index)); - } - - if (numberOfValidSchema > 1 && canShortCircuit()) { - // short-circuit - // note that the short circuit means that only 2 valid schemas are reported even if could be more - break; - } - - if (this.validationContext.getConfig().isDiscriminatorKeywordEnabled()) { - // The discriminator will cause all messages other than the one with the - // matching discriminator to be discarded. Note that the discriminator cannot - // affect the actual validation result. - if (discriminator != null && !discriminator.getPropertyName().isEmpty()) { - JsonNode discriminatorPropertyNode = node.get(discriminator.getPropertyName()); - if (discriminatorPropertyNode != null) { - String discriminatorPropertyValue = discriminatorPropertyNode.asText(); - discriminatorPropertyValue = discriminator.getMapping().getOrDefault(discriminatorPropertyValue, - discriminatorPropertyValue); - JsonNode refNode = schema.getSchemaNode().get("$ref"); - if (refNode != null) { - String ref = refNode.asText(); - if (ref.equals(discriminatorPropertyValue) || ref.endsWith("/" + discriminatorPropertyValue)) { - executionContext.getCurrentDiscriminatorContext().markMatch(); - } - } - } else { - // See issue 436 where the condition was relaxed to not cause an assertion - // due to missing discriminator property value - // Also see BaseJsonValidator#checkDiscriminatorMatch - executionContext.getCurrentDiscriminatorContext().markIgnore(); - } - } - DiscriminatorContext currentDiscriminatorContext = executionContext.getCurrentDiscriminatorContext(); - if (currentDiscriminatorContext.isDiscriminatorMatchFound() && childErrors == null) { - // Note that the match is set if found and not reset so checking if childErrors - // found is null triggers on the correct schema - childErrors = new ArrayList<>(); - childErrors.addAll(schemaErrors); - } else if (currentDiscriminatorContext.isDiscriminatorIgnore() - || !currentDiscriminatorContext.isActive()) { - // This is the normal handling when discriminators aren't enabled - if (childErrors == null) { - childErrors = new ArrayList<>(); - } - childErrors.addAll(schemaErrors); - } - } else if (!schemaErrors.isEmpty() && reportChildErrors(executionContext)) { - // This is the normal handling when discriminators aren't enabled - if (childErrors == null) { - childErrors = new ArrayList<>(); - } - childErrors.addAll(schemaErrors); - } - index++; - } - - if (this.validationContext.getConfig().isDiscriminatorKeywordEnabled() - && (discriminator != null || executionContext.getCurrentDiscriminatorContext().isActive()) - && !executionContext.getCurrentDiscriminatorContext().isDiscriminatorMatchFound() - && !executionContext.getCurrentDiscriminatorContext().isDiscriminatorIgnore()) { - addMessages = false; - existingErrors.add(message().instanceNode(node).instanceLocation(instanceLocation) - .locale(executionContext.getExecutionConfig().getLocale()) - .arguments( - "based on the provided discriminator. No alternative could be chosen based on the discriminator property") - .build()); - } - } finally { - // Restore flag - executionContext.setFailFast(failFast); - - if (this.validationContext.getConfig().isDiscriminatorKeywordEnabled()) { - executionContext.leaveDiscriminatorContextImmediately(instanceLocation); - } - } - - // ensure there is always an "OneOf" error reported if number of valid schemas - // is not equal to 1. - // errors will only not be null in the discriminator case where no match is found - if (numberOfValidSchema != 1 && addMessages) { - ValidationMessage message = message().instanceNode(node).instanceLocation(instanceLocation) - .messageKey(numberOfValidSchema > 1 ? "oneOf.indexes" : "oneOf") - .locale(executionContext.getExecutionConfig().getLocale()) - .failFast(executionContext.isFailFast()) - .arguments(Integer.toString(numberOfValidSchema), numberOfValidSchema > 1 ? String.join(", ", indexes) : "").build(); - existingErrors.add(message); - if (childErrors != null) { - existingErrors.addAll(childErrors); - } - } - executionContext.setErrors(existingErrors); - return; - } - - /** - * Determines if child errors should be reported. - * - * @param executionContext the execution context - * @return true if child errors should be reported - */ - protected boolean reportChildErrors(ExecutionContext executionContext) { - // check the original flag if it's going to fail fast anyway - // no point aggregating all the errors - return !executionContext.getExecutionConfig().isFailFast(); - } - - protected boolean canShortCircuit() { - if (this.canShortCircuit == null) { - boolean canShortCircuit = true; - for (JsonValidator validator : getEvaluationParentSchema().getValidators()) { - if ("unevaluatedProperties".equals(validator.getKeyword()) - || "unevaluatedItems".equals(validator.getKeyword())) { - canShortCircuit = false; - } - } - this.canShortCircuit = canShortCircuit; - } - return this.canShortCircuit; - } - - @Override - public void walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation, boolean shouldValidateSchema) { - if (shouldValidateSchema && node != null) { - validate(executionContext, node, rootNode, instanceLocation, true); - } else { - for (JsonSchema schema : this.schemas) { - schema.walk(executionContext, node, rootNode, instanceLocation, false); - } - } - } - - @Override - public void preloadJsonSchema() { - for (JsonSchema schema: this.schemas) { - schema.initializeValidators(); - } - canShortCircuit(); // cache the flag - } -} diff --git a/src/main/java/com/networknt/schema/OutputFormat.java b/src/main/java/com/networknt/schema/OutputFormat.java index 93d1da44e..9a64c71c2 100644 --- a/src/main/java/com/networknt/schema/OutputFormat.java +++ b/src/main/java/com/networknt/schema/OutputFormat.java @@ -32,12 +32,12 @@ public interface OutputFormat { /** * Customize the execution context before validation. *

- * The validation context should only be used for reference as it is shared. + * The schema context should only be used for reference as it is shared. * * @param executionContext the execution context - * @param validationContext the validation context for reference + * @param schemaContext the schema context for reference */ - default void customize(ExecutionContext executionContext, ValidationContext validationContext) { + default void customize(ExecutionContext executionContext, SchemaContext schemaContext) { } /** @@ -45,12 +45,12 @@ default void customize(ExecutionContext executionContext, ValidationContext vali * * @param jsonSchema the schema * @param executionContext the execution context - * @param validationContext the validation context + * @param schemaContext the schema context * * @return the result */ - T format(JsonSchema jsonSchema, - ExecutionContext executionContext, ValidationContext validationContext); + T format(Schema jsonSchema, + ExecutionContext executionContext, SchemaContext schemaContext); /** * The Default output format. @@ -88,15 +88,15 @@ T format(JsonSchema jsonSchema, /** * The Default output format. */ - class Default implements OutputFormat> { + class Default implements OutputFormat> { @Override - public void customize(ExecutionContext executionContext, ValidationContext validationContext) { - executionContext.getExecutionConfig().setAnnotationCollectionEnabled(false); - } + public void customize(ExecutionContext executionContext, SchemaContext schemaContext) { + executionContext.executionConfig(executionConfig -> executionConfig.annotationCollectionEnabled(false)); + } @Override - public java.util.List format(JsonSchema jsonSchema, - ExecutionContext executionContext, ValidationContext validationContext) { + public java.util.List format(Schema jsonSchema, + ExecutionContext executionContext, SchemaContext schemaContext) { return executionContext.getErrors(); } } @@ -106,14 +106,14 @@ public java.util.List format(JsonSchema jsonSchema, */ class Flag implements OutputFormat { @Override - public void customize(ExecutionContext executionContext, ValidationContext validationContext) { - executionContext.getExecutionConfig().setAnnotationCollectionEnabled(false); - executionContext.getExecutionConfig().setFailFast(true); - } + public void customize(ExecutionContext executionContext, SchemaContext schemaContext) { + executionContext.executionConfig( + executionConfig -> executionConfig.annotationCollectionEnabled(false).failFast(true)); + } @Override - public OutputFlag format(JsonSchema jsonSchema, - ExecutionContext executionContext, ValidationContext validationContext) { + public OutputFlag format(Schema jsonSchema, + ExecutionContext executionContext, SchemaContext schemaContext) { return new OutputFlag(executionContext.getErrors().isEmpty()); } } @@ -123,14 +123,14 @@ public OutputFlag format(JsonSchema jsonSchema, */ class Boolean implements OutputFormat { @Override - public void customize(ExecutionContext executionContext, ValidationContext validationContext) { - executionContext.getExecutionConfig().setAnnotationCollectionEnabled(false); - executionContext.getExecutionConfig().setFailFast(true); + public void customize(ExecutionContext executionContext, SchemaContext schemaContext) { + executionContext.executionConfig( + executionConfig -> executionConfig.annotationCollectionEnabled(false).failFast(true)); } @Override - public java.lang.Boolean format(JsonSchema jsonSchema, - ExecutionContext executionContext, ValidationContext validationContext) { + public java.lang.Boolean format(Schema jsonSchema, + ExecutionContext executionContext, SchemaContext schemaContext) { return executionContext.getErrors().isEmpty(); } } @@ -139,30 +139,30 @@ public java.lang.Boolean format(JsonSchema jsonSchema, * The List output format. */ class List implements OutputFormat { - private final Function assertionMapper; + private final Function errorMapper; public List() { - this(OutputUnitData::formatAssertion); + this(OutputUnitData::formatError); } /** * Constructor. * - * @param assertionMapper to map the assertion + * @param errorMapper to map the error */ - public List(Function assertionMapper) { - this.assertionMapper = assertionMapper; + public List(Function errorMapper) { + this.errorMapper = errorMapper; } @Override - public void customize(ExecutionContext executionContext, ValidationContext validationContext) { + public void customize(ExecutionContext executionContext, SchemaContext schemaContext) { } @Override - public OutputUnit format(JsonSchema jsonSchema, - ExecutionContext executionContext, ValidationContext validationContext) { - return ListOutputUnitFormatter.format(executionContext.getErrors(), executionContext, validationContext, - this.assertionMapper); + public OutputUnit format(Schema jsonSchema, + ExecutionContext executionContext, SchemaContext schemaContext) { + return ListOutputUnitFormatter.format(executionContext.getErrors(), executionContext, schemaContext, + this.errorMapper); } } @@ -170,30 +170,30 @@ public OutputUnit format(JsonSchema jsonSchema, * The Hierarchical output format. */ class Hierarchical implements OutputFormat { - private final Function assertionMapper; + private final Function errorMapper; public Hierarchical() { - this(OutputUnitData::formatAssertion); + this(OutputUnitData::formatError); } /** * Constructor. * - * @param assertionMapper to map the assertion + * @param errorMapper to map the error */ - public Hierarchical(Function assertionMapper) { - this.assertionMapper = assertionMapper; + public Hierarchical(Function errorMapper) { + this.errorMapper = errorMapper; } @Override - public void customize(ExecutionContext executionContext, ValidationContext validationContext) { + public void customize(ExecutionContext executionContext, SchemaContext schemaContext) { } @Override - public OutputUnit format(JsonSchema jsonSchema, - ExecutionContext executionContext, ValidationContext validationContext) { + public OutputUnit format(Schema jsonSchema, + ExecutionContext executionContext, SchemaContext schemaContext) { return HierarchicalOutputUnitFormatter.format(jsonSchema, executionContext.getErrors(), executionContext, - validationContext, this.assertionMapper); + schemaContext, this.errorMapper); } } @@ -202,14 +202,15 @@ public OutputUnit format(JsonSchema jsonSchema, *

* This is currently not exposed to consumers. */ - class Result implements OutputFormat { + class Result implements OutputFormat { @Override - public void customize(ExecutionContext executionContext, ValidationContext validationContext) { + public void customize(ExecutionContext executionContext, SchemaContext schemaContext) { } @Override - public ValidationResult format(JsonSchema jsonSchema,ExecutionContext executionContext, ValidationContext validationContext) { - return new ValidationResult(executionContext); + public com.networknt.schema.Result format(Schema jsonSchema, ExecutionContext executionContext, + SchemaContext schemaContext) { + return new com.networknt.schema.Result(executionContext); } } } diff --git a/src/main/java/com/networknt/schema/ValidationResult.java b/src/main/java/com/networknt/schema/Result.java similarity index 87% rename from src/main/java/com/networknt/schema/ValidationResult.java rename to src/main/java/com/networknt/schema/Result.java index 5495fedb1..028d6bd2b 100644 --- a/src/main/java/com/networknt/schema/ValidationResult.java +++ b/src/main/java/com/networknt/schema/Result.java @@ -20,15 +20,15 @@ /** * Represents a validation result. */ -public class ValidationResult { +public class Result { private final ExecutionContext executionContext; - public ValidationResult(ExecutionContext executionContext) { + public Result(ExecutionContext executionContext) { super(); this.executionContext = executionContext; } - public List getValidationMessages() { + public List getErrors() { return getExecutionContext().getErrors(); } diff --git a/src/main/java/com/networknt/schema/JsonSchema.java b/src/main/java/com/networknt/schema/Schema.java similarity index 57% rename from src/main/java/com/networknt/schema/JsonSchema.java rename to src/main/java/com/networknt/schema/Schema.java index 69626417f..b11dd60ee 100644 --- a/src/main/java/com/networknt/schema/JsonSchema.java +++ b/src/main/java/com/networknt/schema/Schema.java @@ -16,7 +16,10 @@ package com.networknt.schema; +import java.io.FileNotFoundException; import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.util.ArrayList; @@ -30,42 +33,48 @@ import java.util.function.Consumer; import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.node.ObjectNode; -import com.networknt.schema.SpecVersion.VersionFlag; +import com.networknt.schema.keyword.KeywordValidator; +import com.networknt.schema.keyword.TypeValidator; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.path.PathType; +import com.networknt.schema.resource.ClasspathResourceLoader; +import com.networknt.schema.resource.InputStreamSource; +import com.networknt.schema.resource.ResourceLoader; +import com.networknt.schema.keyword.KeywordType; import com.networknt.schema.utils.JsonNodes; /** * Used for creating a schema with validators for validating inputs. This is - * created using {@link JsonSchemaFactory#getInstance(VersionFlag, Consumer)} - * and should be cached for performance. + * created using SchemaRegistry#withDefaultDialect(Version, Consumer) and should + * be cached for performance. *

* This is the core of json constraint implementation. It parses json constraint - * file and generates JsonValidators. The class is thread safe, once it is + * file and generates KeywordValidators. The class is thread safe, once it is * constructed, it can be used to validate multiple json data concurrently. *

- * JsonSchema instances are thread-safe provided its configuration is not + * Schema instances are thread-safe provided its configuration is not * modified. */ -public class JsonSchema implements JsonSchemaValidator { - private static final long V201909_VALUE = VersionFlag.V201909.getVersionFlagValue(); +public class Schema implements Validator { + private static final long DRAFT_2019_09_VALUE = SpecificationVersion.DRAFT_2019_09.getOrder(); private final String id; /** * The validators sorted and indexed by evaluation path. */ - private List validators = null; + private List validators = null; private boolean validatorsLoaded = false; private boolean recursiveAnchor = false; private TypeValidator typeValidator = null; protected final JsonNode schemaNode; - protected final JsonSchema parentSchema; + protected final Schema parentSchema; protected final SchemaLocation schemaLocation; - protected final ValidationContext validationContext; + protected final SchemaContext schemaContext; protected final boolean suppressSubSchemaRetrieval; - protected final JsonNodePath evaluationPath; - protected final JsonSchema evaluationParentSchema; + protected final NodePath evaluationPath; + protected final Schema evaluationParentSchema; public JsonNode getSchemaNode() { return this.schemaNode; @@ -75,7 +84,7 @@ public SchemaLocation getSchemaLocation() { return this.schemaLocation; } - public JsonSchema getParentSchema() { + public Schema getParentSchema() { return parentSchema; } @@ -83,22 +92,22 @@ public boolean isSuppressSubSchemaRetrieval() { return suppressSubSchemaRetrieval; } - public JsonNodePath getEvaluationPath() { + public NodePath getEvaluationPath() { return evaluationPath; } - public JsonSchema getEvaluationParentSchema() { + public Schema getEvaluationParentSchema() { if (this.evaluationParentSchema != null) { return this.evaluationParentSchema; } return getParentSchema(); } - protected JsonSchema fetchSubSchemaNode(ValidationContext validationContext) { - return this.suppressSubSchemaRetrieval ? null : obtainSubSchemaNode(this.schemaNode, validationContext); + protected Schema fetchSubSchemaNode(SchemaContext schemaContext) { + return this.suppressSubSchemaRetrieval ? null : obtainSubSchemaNode(this.schemaNode, schemaContext); } - private static JsonSchema obtainSubSchemaNode(final JsonNode schemaNode, final ValidationContext validationContext) { + private static Schema obtainSubSchemaNode(final JsonNode schemaNode, final SchemaContext schemaContext) { final JsonNode node = schemaNode.get("id"); if (node == null) { @@ -113,28 +122,26 @@ private static JsonSchema obtainSubSchemaNode(final JsonNode schemaNode, final V if (text == null) { return null; } - final SchemaLocation schemaLocation = SchemaLocation.of(node.textValue()); - - return validationContext.getJsonSchemaFactory().getSchema(schemaLocation, validationContext.getConfig()); + return schemaContext.getSchemaRegistry().getSchema(schemaLocation); } public static class JsonNodePathLegacy { - private static final JsonNodePath INSTANCE = new JsonNodePath(PathType.LEGACY); - public static JsonNodePath getInstance() { + private static final NodePath INSTANCE = new NodePath(PathType.LEGACY); + public static NodePath getInstance() { return INSTANCE; } } public static class JsonNodePathJsonPointer { - private static final JsonNodePath INSTANCE = new JsonNodePath(PathType.JSON_POINTER); - public static JsonNodePath getInstance() { + private static final NodePath INSTANCE = new NodePath(PathType.JSON_POINTER); + public static NodePath getInstance() { return INSTANCE; } } public static class JsonNodePathJsonPath { - private static final JsonNodePath INSTANCE = new JsonNodePath(PathType.JSON_PATH); - public static JsonNodePath getInstance() { + private static final NodePath INSTANCE = new NodePath(PathType.JSON_PATH); + public static NodePath getInstance() { return INSTANCE; } } @@ -148,29 +155,29 @@ public void validate(ExecutionContext executionContext, JsonNode node) { * * @return The path. */ - protected JsonNodePath atRoot() { - if (this.validationContext.getConfig().getPathType().equals(PathType.JSON_POINTER)) { + protected NodePath atRoot() { + if (this.schemaContext.getSchemaRegistryConfig().getPathType().equals(PathType.JSON_POINTER)) { return JsonNodePathJsonPointer.getInstance(); - } else if (this.validationContext.getConfig().getPathType().equals(PathType.LEGACY)) { + } else if (this.schemaContext.getSchemaRegistryConfig().getPathType().equals(PathType.LEGACY)) { return JsonNodePathLegacy.getInstance(); - } else if (this.validationContext.getConfig().getPathType().equals(PathType.JSON_PATH)) { + } else if (this.schemaContext.getSchemaRegistryConfig().getPathType().equals(PathType.JSON_PATH)) { return JsonNodePathJsonPath.getInstance(); } - return new JsonNodePath(this.validationContext.getConfig().getPathType()); + return new NodePath(this.schemaContext.getSchemaRegistryConfig().getPathType()); } - static JsonSchema from(ValidationContext validationContext, SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, JsonSchema parent, boolean suppressSubSchemaRetrieval) { - return new JsonSchema(validationContext, schemaLocation, evaluationPath, schemaNode, parent, suppressSubSchemaRetrieval); + static Schema from(SchemaContext schemaContext, SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, Schema parent, boolean suppressSubSchemaRetrieval) { + return new Schema(schemaContext, schemaLocation, evaluationPath, schemaNode, parent, suppressSubSchemaRetrieval); } private boolean hasNoFragment(SchemaLocation schemaLocation) { - JsonNodePath fragment = this.schemaLocation.getFragment(); + NodePath fragment = this.schemaLocation.getFragment(); return fragment == null || (fragment.getParent() == null && fragment.getNameCount() == 0); } private static SchemaLocation resolve(SchemaLocation schemaLocation, JsonNode schemaNode, boolean rootSchema, - ValidationContext validationContext) { - String id = validationContext.resolveSchemaId(schemaNode); + SchemaContext schemaContext) { + String id = schemaContext.resolveSchemaId(schemaNode); if (id != null) { String resolve = id; int fragment = id.indexOf('#'); @@ -180,20 +187,20 @@ private static SchemaLocation resolve(SchemaLocation schemaLocation, JsonNode sc resolve = id.substring(0, fragment); } SchemaLocation result = !"".equals(resolve) ? schemaLocation.resolve(resolve) : schemaLocation; - JsonSchemaIdValidator validator = validationContext.getConfig().getSchemaIdValidator(); + SchemaIdValidator validator = schemaContext.getSchemaRegistryConfig().getSchemaIdValidator(); if (validator != null) { - if (!validator.validate(id, rootSchema, schemaLocation, result, validationContext)) { - SchemaLocation idSchemaLocation = schemaLocation.append(validationContext.getMetaSchema().getIdKeyword()); - ValidationMessage validationMessage = ValidationMessage.builder() - .code(ValidatorTypeCode.ID.getValue()).type(ValidatorTypeCode.ID.getValue()) + if (!validator.validate(id, rootSchema, schemaLocation, result, schemaContext)) { + SchemaLocation idSchemaLocation = schemaLocation.append(schemaContext.getDialect().getIdKeyword()); + Error error = Error.builder() + .messageKey(KeywordType.ID.getValue()).keyword(KeywordType.ID.getValue()) .instanceLocation(idSchemaLocation.getFragment()) - .arguments(id, validationContext.getMetaSchema().getIdKeyword(), idSchemaLocation) + .arguments(id, schemaContext.getDialect().getIdKeyword(), idSchemaLocation) .schemaLocation(idSchemaLocation) .schemaNode(schemaNode) - .messageFormatter(args -> validationContext.getConfig().getMessageSource().getMessage( - ValidatorTypeCode.ID.getValue(), validationContext.getConfig().getLocale(), args)) + .messageFormatter(args -> schemaContext.getSchemaRegistryConfig().getMessageSource().getMessage( + KeywordType.ID.getValue(), schemaContext.getSchemaRegistryConfig().getLocale(), args)) .build(); - throw new InvalidSchemaException(validationMessage); + throw new InvalidSchemaException(error); } } return result; @@ -202,21 +209,21 @@ private static SchemaLocation resolve(SchemaLocation schemaLocation, JsonNode sc } } - private JsonSchema(ValidationContext validationContext, SchemaLocation schemaLocation, JsonNodePath evaluationPath, - JsonNode schemaNode, JsonSchema parent, boolean suppressSubSchemaRetrieval) { + private Schema(SchemaContext schemaContext, SchemaLocation schemaLocation, NodePath evaluationPath, + JsonNode schemaNode, Schema parent, boolean suppressSubSchemaRetrieval) { /* - super(resolve(schemaLocation, schemaNode, parent == null, validationContext), evaluationPath, schemaNode, parent, - null, null, validationContext, suppressSubSchemaRetrieval); + super(resolve(schemaLocation, schemaNode, parent == null, schemaContext), evaluationPath, schemaNode, parent, + null, null, schemaContext, suppressSubSchemaRetrieval); */ - this.validationContext = validationContext; - this.schemaLocation = resolve(schemaLocation, schemaNode, parent == null, validationContext); + this.schemaContext = schemaContext; + this.schemaLocation = resolve(schemaLocation, schemaNode, parent == null, schemaContext); this.schemaNode = schemaNode; this.parentSchema = parent; this.suppressSubSchemaRetrieval = suppressSubSchemaRetrieval; this.evaluationPath = evaluationPath; this.evaluationParentSchema = null; - String id = this.validationContext.resolveSchemaId(this.schemaNode); + String id = this.schemaContext.resolveSchemaId(this.schemaNode); if (id != null) { // In earlier drafts $id may contain an anchor fragment see draft4/idRef.json // Note that json pointer fragments in $id are not allowed @@ -228,31 +235,31 @@ private JsonSchema(ValidationContext validationContext, SchemaLocation schemaLoc // This will be added to schema resources later this.id = null; } - this.validationContext.getSchemaResources().putIfAbsent(result != null ? result.toString() : id, this); + this.schemaContext.getSchemaResources().putIfAbsent(result != null ? result.toString() : id, this); } else { if (hasNoFragment(schemaLocation)) { // No $id but there is no fragment and is thus a schema resource this.id = schemaLocation.getAbsoluteIri() != null ? schemaLocation.getAbsoluteIri().toString() : ""; - this.validationContext.getSchemaResources() + this.schemaContext.getSchemaResources() .putIfAbsent(schemaLocation != null ? schemaLocation.toString() : this.id, this); } else { this.id = null; } } - String anchor = this.validationContext.getMetaSchema().readAnchor(this.schemaNode); + String anchor = this.schemaContext.getDialect().readAnchor(this.schemaNode); if (anchor != null) { String absoluteIri = this.schemaLocation.getAbsoluteIri() != null ? this.schemaLocation.getAbsoluteIri().toString() : ""; - this.validationContext.getSchemaResources() + this.schemaContext.getSchemaResources() .putIfAbsent(absoluteIri + "#" + anchor, this); } - String dynamicAnchor = this.validationContext.getMetaSchema().readDynamicAnchor(schemaNode); + String dynamicAnchor = this.schemaContext.getDialect().readDynamicAnchor(schemaNode); if (dynamicAnchor != null) { String absoluteIri = this.schemaLocation.getAbsoluteIri() != null ? this.schemaLocation.getAbsoluteIri().toString() : ""; - this.validationContext.getDynamicAnchors() + this.schemaContext.getDynamicAnchors() .putIfAbsent(absoluteIri + "#" + dynamicAnchor, this); } getValidators(); @@ -268,18 +275,16 @@ private JsonSchema(ValidationContext validationContext, SchemaLocation schemaLoc * @param id the id * @param suppressSubSchemaRetrieval to suppress sub schema retrieval * @param schemaNode the schema node - * @param validationContext the validation context - * @param errorMessageType the error message type - * @param keyword the keyword + * @param schemaContext the schema context * @param parentSchema the parent schema * @param schemaLocation the schema location * @param evaluationPath the evaluation path * @param evaluationParentSchema the evaluation parent schema * @param errorMessage the error message */ - protected JsonSchema( + protected Schema( /* Below from JsonSchema */ - List validators, + List validators, boolean validatorsLoaded, boolean recursiveAnchor, TypeValidator typeValidator, @@ -287,16 +292,13 @@ protected JsonSchema( /* Below from BaseJsonValidator */ boolean suppressSubSchemaRetrieval, JsonNode schemaNode, - ValidationContext validationContext, - /* Below from ValidationMessageHandler */ - ErrorMessageType errorMessageType, - Keyword keyword, - JsonSchema parentSchema, + SchemaContext schemaContext, + Schema parentSchema, SchemaLocation schemaLocation, - JsonNodePath evaluationPath, - JsonSchema evaluationParentSchema, + NodePath evaluationPath, + Schema evaluationParentSchema, Map errorMessage) { -// super(suppressSubSchemaRetrieval, schemaNode, validationContext, errorMessageType, keyword, +// super(suppressSubSchemaRetrieval, schemaNode, schemaContext, errorMessageType, keyword, // parentSchema, schemaLocation, evaluationPath, evaluationParentSchema, errorMessage); this.validators = validators; this.validatorsLoaded = validatorsLoaded; @@ -304,7 +306,7 @@ protected JsonSchema( this.typeValidator = typeValidator; this.id = id; - this.validationContext = validationContext; + this.schemaContext = schemaContext; this.schemaLocation = schemaLocation; this.schemaNode = schemaNode; this.parentSchema = parentSchema; @@ -324,21 +326,20 @@ protected JsonSchema( * @param refEvaluationPath the ref evaluation path * @return the schema */ - public JsonSchema fromRef(JsonSchema refEvaluationParentSchema, JsonNodePath refEvaluationPath) { - ValidationContext validationContext = new ValidationContext(this.getValidationContext().getMetaSchema(), - this.getValidationContext().getJsonSchemaFactory(), - refEvaluationParentSchema.validationContext.getConfig(), - refEvaluationParentSchema.getValidationContext().getSchemaReferences(), - refEvaluationParentSchema.getValidationContext().getSchemaResources(), - refEvaluationParentSchema.getValidationContext().getDynamicAnchors()); - JsonNodePath evaluationPath = refEvaluationPath; - JsonSchema evaluationParentSchema = refEvaluationParentSchema; + public Schema fromRef(Schema refEvaluationParentSchema, NodePath refEvaluationPath) { + SchemaContext schemaContext = new SchemaContext(this.getSchemaContext().getDialect(), + this.getSchemaContext().getSchemaRegistry(), + refEvaluationParentSchema.getSchemaContext().getSchemaReferences(), + refEvaluationParentSchema.getSchemaContext().getSchemaResources(), + refEvaluationParentSchema.getSchemaContext().getDynamicAnchors()); + NodePath evaluationPath = refEvaluationPath; + Schema evaluationParentSchema = refEvaluationParentSchema; // Validator state is reset due to the changes in evaluation path boolean validatorsLoaded = false; TypeValidator typeValidator = null; - List validators = null; + List validators = null; - return new JsonSchema( + return new Schema( /* Below from JsonSchema */ validators, validatorsLoaded, @@ -348,56 +349,51 @@ public JsonSchema fromRef(JsonSchema refEvaluationParentSchema, JsonNodePath ref /* Below from BaseJsonValidator */ suppressSubSchemaRetrieval, schemaNode, - validationContext, - /* Below from ValidationMessageHandler */ - /*errorMessageType*/ null, - /*keyword*/ null, parentSchema, schemaLocation, evaluationPath, + schemaContext, + parentSchema, schemaLocation, evaluationPath, evaluationParentSchema, /* errorMessage */ null); } - public JsonSchema withConfig(SchemaValidatorsConfig config) { - if (this.getValidationContext().getMetaSchema().getKeywords().containsKey("discriminator") - && !config.isDiscriminatorKeywordEnabled()) { - config = SchemaValidatorsConfig.builder(config) - .discriminatorKeywordEnabled(true) - .nullableKeywordEnabled(true) - .build(); - } - if (!this.getValidationContext().getConfig().equals(config)) { - ValidationContext validationContext = new ValidationContext(this.getValidationContext().getMetaSchema(), - this.getValidationContext().getJsonSchemaFactory(), config, - this.getValidationContext().getSchemaReferences(), - this.getValidationContext().getSchemaResources(), - this.getValidationContext().getDynamicAnchors()); - boolean validatorsLoaded = false; - TypeValidator typeValidator = null; - List validators = null; - return new JsonSchema( - /* Below from JsonSchema */ - validators, - validatorsLoaded, - recursiveAnchor, - typeValidator, - id, - /* Below from BaseJsonValidator */ - suppressSubSchemaRetrieval, - schemaNode, - validationContext, - /* Below from ValidationMessageHandler */ - /* errorMessageType */ null, - /* keyword */ null, - parentSchema, - schemaLocation, - evaluationPath, - evaluationParentSchema, - /* errorMessage */ null); - - } - return this; - } - - public ValidationContext getValidationContext() { - return this.validationContext; +// public Schema withConfig(SchemaValidatorsConfig config) { +// if (this.getValidationContext().getMetaSchema().getKeywords().containsKey("discriminator") +// && !config.isDiscriminatorKeywordEnabled()) { +// config = SchemaValidatorsConfig.builder(config) +// .discriminatorKeywordEnabled(true) +// .nullableKeywordEnabled(true) +// .build(); +// } +// if (!this.getValidationContext().getSchemaRegistryConfig().equals(config)) { +// ValidationContext schemaContext = new ValidationContext(this.getValidationContext().getMetaSchema(), +// this.getValidationContext().getSchemaRegistry(), config, +// this.getValidationContext().getSchemaReferences(), +// this.getValidationContext().getSchemaResources(), +// this.getValidationContext().getDynamicAnchors()); +// boolean validatorsLoaded = false; +// TypeValidator typeValidator = null; +// List validators = null; +// return new Schema( +// /* Below from JsonSchema */ +// validators, +// validatorsLoaded, +// recursiveAnchor, +// typeValidator, +// id, +// /* Below from BaseJsonValidator */ +// suppressSubSchemaRetrieval, +// schemaNode, +// schemaContext, +// parentSchema, +// schemaLocation, +// evaluationPath, +// evaluationParentSchema, +// /* errorMessage */ null); +// +// } +// return this; +// } + + public SchemaContext getSchemaContext() { + return this.schemaContext; } /** @@ -407,7 +403,7 @@ public ValidationContext getValidationContext() { * @return JsonNode */ public JsonNode getRefSchemaNode(String ref) { - JsonSchema schema = findSchemaResourceRoot(); + Schema schema = findSchemaResourceRoot(); JsonNode node = schema.getSchemaNode(); String jsonPointer = ref; @@ -434,7 +430,7 @@ public JsonNode getRefSchemaNode(String ref) { return node; } - public JsonSchema getRefSchema(JsonNodePath fragment) { + public Schema getRefSchema(NodePath fragment) { if (PathType.JSON_POINTER.equals(fragment.getPathType())) { // Json Pointer return getSubSchema(fragment); @@ -442,12 +438,12 @@ public JsonSchema getRefSchema(JsonNodePath fragment) { // Anchor String base = this.getSchemaLocation().getAbsoluteIri() != null ? this.schemaLocation.getAbsoluteIri().toString() : ""; String anchor = base + "#" + fragment; - JsonSchema result = this.validationContext.getSchemaResources().get(anchor); + Schema result = this.schemaContext.getSchemaResources().get(anchor); if (result == null) { - result = this.validationContext.getDynamicAnchors().get(anchor); + result = this.schemaContext.getDynamicAnchors().get(anchor); } if (result == null) { - throw new JsonSchemaException("Unable to find anchor "+anchor); + throw new SchemaException("Unable to find anchor "+anchor); } return result; } @@ -459,13 +455,13 @@ public JsonSchema getRefSchema(JsonNodePath fragment) { * @param fragment the json pointer fragment * @return the schema */ - public JsonSchema getSubSchema(JsonNodePath fragment) { - JsonSchema document = findSchemaResourceRoot(); - JsonSchema parent = document; - JsonSchema subSchema = null; + public Schema getSubSchema(NodePath fragment) { + Schema document = findSchemaResourceRoot(); + Schema parent = document; + Schema subSchema = null; JsonNode parentNode = parent.getSchemaNode(); SchemaLocation schemaLocation = document.getSchemaLocation(); - JsonNodePath evaluationPath = document.getEvaluationPath(); + NodePath evaluationPath = document.getEvaluationPath(); int nameCount = fragment.getNameCount(); for (int x = 0; x < nameCount; x++) { /* @@ -488,15 +484,15 @@ public JsonSchema getSubSchema(JsonNodePath fragment) { evaluationPath = evaluationPath.append(segment.toString()); } /* - * The parent validation context is used to create as there can be changes in - * $schema is later drafts which means the validation context can change. + * The parent schema context is used to create as there can be changes in + * $schema is later drafts which means the schema context can change. */ // This may need a redesign see Issue 939 and 940 - String id = parent.getValidationContext().resolveSchemaId(subSchemaNode); + String id = parent.getSchemaContext().resolveSchemaId(subSchemaNode); // if (!("definitions".equals(segment.toString()) || "$defs".equals(segment.toString()) // )) { if (id != null || x == nameCount - 1) { - subSchema = parent.getValidationContext().newSchema(schemaLocation, evaluationPath, subSchemaNode, + subSchema = parent.getSchemaContext().newSchema(schemaLocation, evaluationPath, subSchemaNode, parent); parent = subSchema; schemaLocation = subSchema.getSchemaLocation(); @@ -510,19 +506,19 @@ public JsonSchema getSubSchema(JsonNodePath fragment) { * * See test for draft4\extra\classpath\schema.json */ - JsonSchema found = document.findSchemaResourceRoot().fetchSubSchemaNode(this.validationContext); + Schema found = document.findSchemaResourceRoot().fetchSubSchemaNode(this.schemaContext); if (found != null) { found = found.getSubSchema(fragment); } if (found == null) { - ValidationMessage validationMessage = ValidationMessage.builder() - .type(ValidatorTypeCode.REF.getValue()).code("internal.unresolvedRef") - .message("{0}: Reference {1} cannot be resolved") + Error error = Error.builder() + .keyword(KeywordType.REF.getValue()).messageKey("internal.unresolvedRef") + .message("Reference {0} cannot be resolved") .instanceLocation(schemaLocation.getFragment()) .schemaLocation(schemaLocation) .evaluationPath(evaluationPath) .arguments(fragment).build(); - throw new InvalidSchemaRefException(validationMessage); + throw new InvalidSchemaRefException(error); } return found; } @@ -538,8 +534,8 @@ protected JsonNode getNode(JsonNode node, Object propertyOrIndex) { return JsonNodes.get(node, propertyOrIndex); } - public JsonSchema findLexicalRoot() { - JsonSchema ancestor = this; + public Schema findLexicalRoot() { + Schema ancestor = this; while (ancestor.getId() == null) { if (null == ancestor.getParentSchema()) break; ancestor = ancestor.getParentSchema(); @@ -554,8 +550,8 @@ public JsonSchema findLexicalRoot() { * * @return the root of the schema */ - public JsonSchema findSchemaResourceRoot() { - JsonSchema ancestor = this; + public Schema findSchemaResourceRoot() { + Schema ancestor = this; while (!ancestor.isSchemaResourceRoot()) { ancestor = ancestor.getParentSchema(); } @@ -585,16 +581,16 @@ public String getId() { return this.id; } - public JsonSchema findAncestor() { - JsonSchema ancestor = this; + public Schema findAncestor() { + Schema ancestor = this; if (this.getParentSchema() != null) { ancestor = this.getParentSchema().findAncestor(); } return ancestor; } - private JsonNode handleNullNode(String ref, JsonSchema schema) { - JsonSchema subSchema = schema.fetchSubSchemaNode(this.validationContext); + private JsonNode handleNullNode(String ref, Schema schema) { + Schema subSchema = schema.fetchSubSchemaNode(this.schemaContext); if (subSchema != null) { return subSchema.getRefSchemaNode(ref); } @@ -604,23 +600,23 @@ private JsonNode handleNullNode(String ref, JsonSchema schema) { /** * Please note that the key in {@link #validators} map is the evaluation path. */ - private List read(JsonNode schemaNode) { - List validators; + private List read(JsonNode schemaNode) { + List validators; if (schemaNode.isBoolean()) { validators = new ArrayList<>(1); if (schemaNode.booleanValue()) { - JsonNodePath path = getEvaluationPath().append("true"); - JsonValidator validator = this.validationContext.newValidator(getSchemaLocation().append("true"), path, + NodePath path = getEvaluationPath().append("true"); + KeywordValidator validator = this.schemaContext.newValidator(getSchemaLocation().append("true"), path, "true", schemaNode, this); validators.add(validator); } else { - JsonNodePath path = getEvaluationPath().append("false"); - JsonValidator validator = this.validationContext.newValidator(getSchemaLocation().append("false"), + NodePath path = getEvaluationPath().append("false"); + KeywordValidator validator = this.schemaContext.newValidator(getSchemaLocation().append("false"), path, "false", schemaNode, this); validators.add(validator); } } else { - JsonValidator refValidator = null; + KeywordValidator refValidator = null; Iterator> iterator = schemaNode.fields(); validators = new ArrayList<>(schemaNode.size()); @@ -629,26 +625,26 @@ private List read(JsonNode schemaNode) { String pname = entry.getKey(); JsonNode nodeToUse = entry.getValue(); - JsonNodePath path = getEvaluationPath().append(pname); + NodePath path = getEvaluationPath().append(pname); SchemaLocation schemaPath = getSchemaLocation().append(pname); if ("$recursiveAnchor".equals(pname)) { if (!nodeToUse.isBoolean()) { - ValidationMessage validationMessage = ValidationMessage.builder().type("$recursiveAnchor") - .code("internal.invalidRecursiveAnchor") + Error error = Error.builder().keyword("$recursiveAnchor") + .messageKey("internal.invalidRecursiveAnchor") .message( - "{0}: The value of a $recursiveAnchor must be a Boolean literal but is {1}") + "The value of a $recursiveAnchor must be a Boolean literal but is {0}") .instanceLocation(path) .evaluationPath(path) .schemaLocation(schemaPath) .arguments(nodeToUse.getNodeType().toString()) .build(); - throw new JsonSchemaException(validationMessage); + throw new SchemaException(error); } this.recursiveAnchor = nodeToUse.booleanValue(); } - JsonValidator validator = this.validationContext.newValidator(schemaPath, path, + KeywordValidator validator = this.schemaContext.newValidator(schemaPath, path, pname, nodeToUse, this); if (validator != null) { validators.add(validator); @@ -665,7 +661,7 @@ private List read(JsonNode schemaNode) { } // Ignore siblings for older drafts - if (null != refValidator && activeDialect() < V201909_VALUE) { + if (null != refValidator && getSchemaContext().getDialect().getSpecificationVersion().getOrder() < DRAFT_2019_09_VALUE) { validators.clear(); validators.add(refValidator); } @@ -676,23 +672,20 @@ private List read(JsonNode schemaNode) { return validators; } - private long activeDialect() { - return this.validationContext - .activeDialect() - .map(VersionFlag::getVersionFlagValue) - .orElse(Long.MAX_VALUE); - } - /** * A comparator that sorts validators, such that 'properties' comes before 'required', * so that we can apply default values before validating required. */ - private static final Comparator VALIDATOR_SORT = (lhs, rhs) -> { + private static final Comparator VALIDATOR_SORT = (lhs, rhs) -> { String lhsName = lhs.getEvaluationPath().getName(-1); String rhsName = rhs.getEvaluationPath().getName(-1); if (lhsName.equals(rhsName)) return 0; + // Discriminator needs to run first to set state in the execution context + if (lhsName.equals("discriminator")) return -1; + if (rhsName.equals("discriminator")) return 1; + if (lhsName.equals("properties")) return -1; if (rhsName.equals("properties")) return 1; if (lhsName.equals("patternProperties")) return -1; @@ -708,52 +701,15 @@ private long activeDialect() { /************************ START OF VALIDATE METHODS **********************************/ @Override - public void validate(ExecutionContext executionContext, JsonNode jsonNode, JsonNode rootNode, JsonNodePath instanceLocation) { - if (this.validationContext.getConfig().isDiscriminatorKeywordEnabled()) { - ObjectNode discriminator = (ObjectNode) schemaNode.get("discriminator"); - if (null != discriminator && null != executionContext.getCurrentDiscriminatorContext()) { - executionContext.getCurrentDiscriminatorContext().registerDiscriminator(schemaLocation, - discriminator); - } - } + public void validate(ExecutionContext executionContext, JsonNode jsonNode, JsonNode rootNode, NodePath instanceLocation) { int currentErrors = executionContext.getErrors().size(); - for (JsonValidator v : getValidators()) { + for (KeywordValidator v : getValidators()) { v.validate(executionContext, jsonNode, rootNode, instanceLocation); } - - if (this.validationContext.getConfig().isDiscriminatorKeywordEnabled()) { - ObjectNode discriminator = (ObjectNode) this.schemaNode.get("discriminator"); - if (null != discriminator) { - final DiscriminatorContext discriminatorContext = executionContext - .getCurrentDiscriminatorContext(); - if (null != discriminatorContext) { - final ObjectNode discriminatorToUse; - final ObjectNode discriminatorFromContext = discriminatorContext - .getDiscriminatorForPath(this.schemaLocation); - if (null == discriminatorFromContext) { - // register the current discriminator. This can only happen when the current context discriminator - // was not registered via allOf. In that case we have a $ref to the schema with discriminator that gets - // used for validation before allOf validation has kicked in - discriminatorContext.registerDiscriminator(this.schemaLocation, discriminator); - discriminatorToUse = discriminator; - } else { - discriminatorToUse = discriminatorFromContext; - } - - final String discriminatorPropertyName = discriminatorToUse.get("propertyName").asText(); - final JsonNode discriminatorNode = jsonNode.get(discriminatorPropertyName); - final String discriminatorPropertyValue = discriminatorNode == null ? null - : discriminatorNode.asText(); - DiscriminatorValidator.checkDiscriminatorMatch(discriminatorContext, discriminatorToUse, discriminatorPropertyValue, - this); - } - } - } - if (executionContext.getErrors().size() > currentErrors) { // Failed with assertion set result and drop all annotations from this schema // and all subschemas - executionContext.getResults().setResult(instanceLocation, getSchemaLocation(), getEvaluationPath(), false); + executionContext.getInstanceResults().setResult(instanceLocation, getSchemaLocation(), getEvaluationPath(), false); } } @@ -763,14 +719,14 @@ public void validate(ExecutionContext executionContext, JsonNode jsonNode, JsonN * Note that since Draft 2019-09 by default format generates only annotations * and not assertions. *

- * Use {@link ExecutionConfig#setFormatAssertionsEnabled(Boolean)} to override + * Use {@link ExecutionConfig.Builder#formatAssertionsEnabled(Boolean)} to override * the default. * * @param rootNode the root node - * @return A list of ValidationMessage if there is any validation error, or an + * @return A list of Error if there is any validation error, or an * empty list if there is no error. */ - public List validate(JsonNode rootNode) { + public List validate(JsonNode rootNode) { return validate(rootNode, OutputFormat.DEFAULT); } @@ -780,14 +736,14 @@ public List validate(JsonNode rootNode) { * Note that since Draft 2019-09 by default format generates only annotations * and not assertions. *

- * Use {@link ExecutionConfig#setFormatAssertionsEnabled(Boolean)} to override + * Use {@link ExecutionConfig.Builder#formatAssertionsEnabled(Boolean)} to override * the default. * * @param rootNode the root node * @param executionCustomizer the execution customizer * @return the assertions */ - public List validate(JsonNode rootNode, ExecutionContextCustomizer executionCustomizer) { + public List validate(JsonNode rootNode, ExecutionContextCustomizer executionCustomizer) { return validate(rootNode, OutputFormat.DEFAULT, executionCustomizer); } @@ -797,14 +753,14 @@ public List validate(JsonNode rootNode, ExecutionContextCusto * Note that since Draft 2019-09 by default format generates only annotations * and not assertions. *

- * Use {@link ExecutionConfig#setFormatAssertionsEnabled(Boolean)} to override + * Use {@link ExecutionConfig.Builder#formatAssertionsEnabled(Boolean)} to override * the default. * * @param rootNode the root node * @param executionCustomizer the execution customizer * @return the assertions */ - public List validate(JsonNode rootNode, Consumer executionCustomizer) { + public List validate(JsonNode rootNode, Consumer executionCustomizer) { return validate(rootNode, OutputFormat.DEFAULT, executionCustomizer); } @@ -815,7 +771,7 @@ public List validate(JsonNode rootNode, Consumer - * Use {@link ExecutionConfig#setFormatAssertionsEnabled(Boolean)} to override + * Use {@link ExecutionConfig.Builder#formatAssertionsEnabled(Boolean)} to override * the default. * * @param the result type @@ -834,7 +790,7 @@ public T validate(JsonNode rootNode, OutputFormat format) { * Note that since Draft 2019-09 by default format generates only annotations * and not assertions. *

- * Use {@link ExecutionConfig#setFormatAssertionsEnabled(Boolean)} to override + * Use {@link ExecutionConfig.Builder#formatAssertionsEnabled(Boolean)} to override * the default. * * @param the result type @@ -854,7 +810,7 @@ public T validate(JsonNode rootNode, OutputFormat format, ExecutionContex * Note that since Draft 2019-09 by default format generates only annotations * and not assertions. *

- * Use {@link ExecutionConfig#setFormatAssertionsEnabled(Boolean)} to override + * Use {@link ExecutionConfig.Builder#formatAssertionsEnabled(Boolean)} to override * the default. * * @param the result type @@ -864,7 +820,7 @@ public T validate(JsonNode rootNode, OutputFormat format, ExecutionContex * @return the result */ public T validate(JsonNode rootNode, OutputFormat format, Consumer executionCustomizer) { - return validate(createExecutionContext(), rootNode, format, (executionContext, validationContext) -> executionCustomizer.accept(executionContext)); + return validate(createExecutionContext(), rootNode, format, (executionContext, schemaContext) -> executionCustomizer.accept(executionContext)); } /** @@ -874,15 +830,15 @@ public T validate(JsonNode rootNode, OutputFormat format, Consumer - * Use {@link ExecutionConfig#setFormatAssertionsEnabled(Boolean)} to override + * Use {@link ExecutionConfig.Builder#formatAssertionsEnabled(Boolean)} to override * the default. * * @param input the input * @param inputFormat the inputFormat - * @return A list of ValidationMessage if there is any validation error, or an + * @return A list of Error if there is any validation error, or an * empty list if there is no error. */ - public List validate(String input, InputFormat inputFormat) { + public List validate(String input, InputFormat inputFormat) { return validate(deserialize(input, inputFormat), OutputFormat.DEFAULT); } @@ -893,7 +849,7 @@ public List validate(String input, InputFormat inputFormat) { * Note that since Draft 2019-09 by default format generates only annotations * and not assertions. *

- * Use {@link ExecutionConfig#setFormatAssertionsEnabled(Boolean)} to override + * Use {@link ExecutionConfig.Builder#formatAssertionsEnabled(Boolean)} to override * the default. * * @param input the input @@ -901,7 +857,7 @@ public List validate(String input, InputFormat inputFormat) { * @param executionCustomizer the execution customizer * @return the assertions */ - public List validate(String input, InputFormat inputFormat, ExecutionContextCustomizer executionCustomizer) { + public List validate(String input, InputFormat inputFormat, ExecutionContextCustomizer executionCustomizer) { return validate(deserialize(input, inputFormat), OutputFormat.DEFAULT, executionCustomizer); } @@ -912,7 +868,7 @@ public List validate(String input, InputFormat inputFormat, E * Note that since Draft 2019-09 by default format generates only annotations * and not assertions. *

- * Use {@link ExecutionConfig#setFormatAssertionsEnabled(Boolean)} to override + * Use {@link ExecutionConfig.Builder#formatAssertionsEnabled(Boolean)} to override * the default. * * @param input the input @@ -920,7 +876,7 @@ public List validate(String input, InputFormat inputFormat, E * @param executionCustomizer the execution customizer * @return the assertions */ - public List validate(String input, InputFormat inputFormat, Consumer executionCustomizer) { + public List validate(String input, InputFormat inputFormat, Consumer executionCustomizer) { return validate(deserialize(input, inputFormat), OutputFormat.DEFAULT, executionCustomizer); } @@ -931,7 +887,7 @@ public List validate(String input, InputFormat inputFormat, C * Note that since Draft 2019-09 by default format generates only annotations * and not assertions. *

- * Use {@link ExecutionConfig#setFormatAssertionsEnabled(Boolean)} to override + * Use {@link ExecutionConfig.Builder#formatAssertionsEnabled(Boolean)} to override * the default. * * @param the result type @@ -951,7 +907,7 @@ public T validate(String input, InputFormat inputFormat, OutputFormat for * Note that since Draft 2019-09 by default format generates only annotations * and not assertions. *

- * Use {@link ExecutionConfig#setFormatAssertionsEnabled(Boolean)} to override + * Use {@link ExecutionConfig.Builder#formatAssertionsEnabled(Boolean)} to override * the default. * * @param the result type @@ -972,7 +928,7 @@ public T validate(String input, InputFormat inputFormat, OutputFormat for * Note that since Draft 2019-09 by default format generates only annotations * and not assertions. *

- * Use {@link ExecutionConfig#setFormatAssertionsEnabled(Boolean)} to override + * Use {@link ExecutionConfig.Builder#formatAssertionsEnabled(Boolean)} to override * the default. * * @param the result type @@ -983,7 +939,251 @@ public T validate(String input, InputFormat inputFormat, OutputFormat for * @return the result */ public T validate(String input, InputFormat inputFormat, OutputFormat format, Consumer executionCustomizer) { - return validate(createExecutionContext(), deserialize(input, inputFormat), format, (executionContext, validationContext) -> executionCustomizer.accept(executionContext)); + return validate(createExecutionContext(), deserialize(input, inputFormat), format, (executionContext, schemaContext) -> executionCustomizer.accept(executionContext)); + } + + /** + * Validate the given input string using the input format, starting at the root + * of the data path. + *

+ * Note that since Draft 2019-09 by default format generates only annotations + * and not assertions. + *

+ * Use {@link ExecutionConfig.Builder#formatAssertionsEnabled(Boolean)} to override + * the default. + * + * @param input the input + * @param inputFormat the inputFormat + * @return A list of Error if there is any validation error, or an + * empty list if there is no error. + */ + public List validate(AbsoluteIri input, InputFormat inputFormat) { + return validate(deserialize(input, inputFormat), OutputFormat.DEFAULT); + } + + /** + * Validate the given input string using the input format, starting at the root + * of the data path. + *

+ * Note that since Draft 2019-09 by default format generates only annotations + * and not assertions. + *

+ * Use {@link ExecutionConfig.Builder#formatAssertionsEnabled(Boolean)} to override + * the default. + * + * @param input the input + * @param inputFormat the inputFormat + * @param executionCustomizer the execution customizer + * @return the assertions + */ + public List validate(AbsoluteIri input, InputFormat inputFormat, ExecutionContextCustomizer executionCustomizer) { + return validate(deserialize(input, inputFormat), OutputFormat.DEFAULT, executionCustomizer); + } + + /** + * Validate the given input string using the input format, starting at the root + * of the data path. + *

+ * Note that since Draft 2019-09 by default format generates only annotations + * and not assertions. + *

+ * Use {@link ExecutionConfig.Builder#formatAssertionsEnabled(Boolean)} to override + * the default. + * + * @param input the input + * @param inputFormat the inputFormat + * @param executionCustomizer the execution customizer + * @return the assertions + */ + public List validate(AbsoluteIri input, InputFormat inputFormat, Consumer executionCustomizer) { + return validate(deserialize(input, inputFormat), OutputFormat.DEFAULT, executionCustomizer); + } + + /** + * Validates the given input string using the input format, starting at the root + * of the data path. The output will be formatted using the formatter specified. + *

+ * Note that since Draft 2019-09 by default format generates only annotations + * and not assertions. + *

+ * Use {@link ExecutionConfig.Builder#formatAssertionsEnabled(Boolean)} to override + * the default. + * + * @param the result type + * @param input the input + * @param inputFormat the inputFormat + * @param format the formatter + * @return the result + */ + public T validate(AbsoluteIri input, InputFormat inputFormat, OutputFormat format) { + return validate(deserialize(input, inputFormat), format, (ExecutionContextCustomizer) null); + } + + /** + * Validates the given input string using the input format, starting at the root + * of the data path. The output will be formatted using the formatter specified. + *

+ * Note that since Draft 2019-09 by default format generates only annotations + * and not assertions. + *

+ * Use {@link ExecutionConfig.Builder#formatAssertionsEnabled(Boolean)} to override + * the default. + * + * @param the result type + * @param input the input + * @param inputFormat the inputFormat + * @param format the formatter + * @param executionCustomizer the execution customizer + * @return the result + */ + public T validate(AbsoluteIri input, InputFormat inputFormat, OutputFormat format, ExecutionContextCustomizer executionCustomizer) { + return validate(createExecutionContext(), deserialize(input, inputFormat), format, executionCustomizer); + } + + /** + * Validates the given input string using the input format, starting at the root + * of the data path. The output will be formatted using the formatter specified. + *

+ * Note that since Draft 2019-09 by default format generates only annotations + * and not assertions. + *

+ * Use {@link ExecutionConfig.Builder#formatAssertionsEnabled(Boolean)} to override + * the default. + * + * @param the result type + * @param input the input + * @param inputFormat the inputFormat + * @param format the formatter + * @param executionCustomizer the execution customizer + * @return the result + */ + public T validate(AbsoluteIri input, InputFormat inputFormat, OutputFormat format, Consumer executionCustomizer) { + return validate(createExecutionContext(), deserialize(input, inputFormat), format, (executionContext, schemaContext) -> executionCustomizer.accept(executionContext)); + } + + /** + * Validate the given input string using the input format, starting at the root + * of the data path. + *

+ * Note that since Draft 2019-09 by default format generates only annotations + * and not assertions. + *

+ * Use {@link ExecutionConfig.Builder#formatAssertionsEnabled(Boolean)} to override + * the default. + * + * @param executionContext the execution context + * @param input the input + * @param inputFormat the inputFormat + * @return A list of Error if there is any validation error, or an + * empty list if there is no error. + */ + public List validate(ExecutionContext executionContext, String input, InputFormat inputFormat) { + return validate(executionContext, deserialize(input, inputFormat), OutputFormat.DEFAULT); + } + + /** + * Validate the given input string using the input format, starting at the root + * of the data path. + *

+ * Note that since Draft 2019-09 by default format generates only annotations + * and not assertions. + *

+ * Use {@link ExecutionConfig.Builder#formatAssertionsEnabled(Boolean)} to override + * the default. + * + * @param executionContext the execution context + * @param input the input + * @param inputFormat the inputFormat + * @param executionCustomizer the execution customizer + * @return the assertions + */ + public List validate(ExecutionContext executionContext, String input, InputFormat inputFormat, ExecutionContextCustomizer executionCustomizer) { + return validate(executionContext, deserialize(input, inputFormat), OutputFormat.DEFAULT, executionCustomizer); + } + + /** + * Validate the given input string using the input format, starting at the root + * of the data path. + *

+ * Note that since Draft 2019-09 by default format generates only annotations + * and not assertions. + *

+ * Use {@link ExecutionConfig.Builder#formatAssertionsEnabled(Boolean)} to override + * the default. + * + * @param executionContext the execution context + * @param input the input + * @param inputFormat the inputFormat + * @param executionCustomizer the execution customizer + * @return the assertions + */ + public List validate(ExecutionContext executionContext, String input, InputFormat inputFormat, Consumer executionCustomizer) { + return validate(executionContext, deserialize(input, inputFormat), OutputFormat.DEFAULT, executionCustomizer); + } + + /** + * Validates the given input string using the input format, starting at the root + * of the data path. The output will be formatted using the formatter specified. + *

+ * Note that since Draft 2019-09 by default format generates only annotations + * and not assertions. + *

+ * Use {@link ExecutionConfig.Builder#formatAssertionsEnabled(Boolean)} to override + * the default. + * + * @param the result type + * @param executionContext the execution context + * @param input the input + * @param inputFormat the inputFormat + * @param format the formatter + * @return the result + */ + public T validate(ExecutionContext executionContext, String input, InputFormat inputFormat, OutputFormat format) { + return validate(executionContext, deserialize(input, inputFormat), format, (ExecutionContextCustomizer) null); + } + + /** + * Validates the given input string using the input format, starting at the root + * of the data path. The output will be formatted using the formatter specified. + *

+ * Note that since Draft 2019-09 by default format generates only annotations + * and not assertions. + *

+ * Use {@link ExecutionConfig.Builder#formatAssertionsEnabled(Boolean)} to override + * the default. + * + * @param the result type + * @param executionContext the execution context + * @param input the input + * @param inputFormat the inputFormat + * @param format the formatter + * @param executionCustomizer the execution customizer + * @return the result + */ + public T validate(ExecutionContext executionContext, String input, InputFormat inputFormat, OutputFormat format, ExecutionContextCustomizer executionCustomizer) { + return validate(executionContext, deserialize(input, inputFormat), format, executionCustomizer); + } + + /** + * Validates the given input string using the input format, starting at the root + * of the data path. The output will be formatted using the formatter specified. + *

+ * Note that since Draft 2019-09 by default format generates only annotations + * and not assertions. + *

+ * Use {@link ExecutionConfig.Builder#formatAssertionsEnabled(Boolean)} to override + * the default. + * + * @param the result type + * @param executionContext the execution context + * @param input the input + * @param inputFormat the inputFormat + * @param format the formatter + * @param executionCustomizer the execution customizer + * @return the result + */ + public T validate(ExecutionContext executionContext, String input, InputFormat inputFormat, OutputFormat format, Consumer executionCustomizer) { + return validate(executionContext, deserialize(input, inputFormat), format, (execContext, schemaContext) -> executionCustomizer.accept(execContext)); } /** @@ -996,7 +1196,28 @@ public T validate(String input, InputFormat inputFormat, OutputFormat for * @return the result */ public T validate(ExecutionContext executionContext, JsonNode node, OutputFormat format) { - return validate(executionContext, node, format, null); + return validate(executionContext, node, format, (ExecutionContextCustomizer) null); + } + + /** + * Validates the given input string using the input format, starting at the root + * of the data path. The output will be formatted using the formatter specified. + *

+ * Note that since Draft 2019-09 by default format generates only annotations + * and not assertions. + *

+ * Use {@link ExecutionConfig.Builder#formatAssertionsEnabled(Boolean)} to override + * the default. + * + * @param the result type + * @param executionContext the execution context + * @param node the node + * @param format the formatter + * @param executionCustomizer the execution customizer + * @return the result + */ + public T validate(ExecutionContext executionContext, JsonNode node, OutputFormat format, Consumer executionCustomizer) { + return validate(executionContext, node, format, (execContext, schemaContext) -> executionCustomizer.accept(execContext)); } /** @@ -1011,16 +1232,16 @@ public T validate(ExecutionContext executionContext, JsonNode node, OutputFo */ public T validate(ExecutionContext executionContext, JsonNode node, OutputFormat format, ExecutionContextCustomizer executionCustomizer) { - format.customize(executionContext, this.validationContext); + format.customize(executionContext, this.schemaContext); if (executionCustomizer != null) { - executionCustomizer.customize(executionContext, this.validationContext); + executionCustomizer.customize(executionContext, this.schemaContext); } try { validate(executionContext, node); } catch (FailFastAssertionException e) { executionContext.setErrors(e.getErrors()); } - return format.format(this, executionContext, this.validationContext); + return format.format(this, executionContext, this.schemaContext); } /** @@ -1032,66 +1253,50 @@ public T validate(ExecutionContext executionContext, JsonNode node, OutputFo */ private JsonNode deserialize(String input, InputFormat inputFormat) { try { - return this.getValidationContext().getJsonSchemaFactory().readTree(input, inputFormat); + return this.getSchemaContext().getSchemaRegistry().readTree(input, inputFormat); } catch (IOException e) { - throw new IllegalArgumentException("Invalid input", e); + throw new UncheckedIOException("Invalid input", e); } } /** - * Deprecated. Initialize the CollectorContext externally and call loadCollectors when done. - *

- * @param executionContext ExecutionContext - * @param node JsonNode - * @return ValidationResult - */ - @Deprecated - public ValidationResult validateAndCollect(ExecutionContext executionContext, JsonNode node) { - return validateAndCollect(executionContext, node, node, atRoot()); - } - - /** - * Deprecated. Initialize the CollectorContext externally and call loadCollectors when done. - *

- * This method both validates and collects the data in a CollectorContext. - * Unlike others this methods cleans and removes everything from collector - * context before returning. - * @param executionContext ExecutionContext - * @param jsonNode JsonNode - * @param rootNode JsonNode - * @param instanceLocation JsonNodePath - * - * @return ValidationResult + * Loads the resource from the input iri and deserialize to JsonNode. + * + * @param input the input + * @param inputFormat the format + * @return the JsonNode. */ - @Deprecated - private ValidationResult validateAndCollect(ExecutionContext executionContext, JsonNode jsonNode, JsonNode rootNode, JsonNodePath instanceLocation) { - // Validate. - validate(executionContext, jsonNode, rootNode, instanceLocation); - - // Get the config. - SchemaValidatorsConfig config = this.validationContext.getConfig(); - - // When walk is called in series of nested call we don't want to load the collectors every time. Leave to the API to decide when to call collectors. - if (config.doLoadCollectors()) { - // Get the collector context. - CollectorContext collectorContext = executionContext.getCollectorContext(); - - // Load all the data from collectors into the context. - collectorContext.loadCollectors(); + private JsonNode deserialize(AbsoluteIri input, InputFormat inputFormat) { + try { + InputStreamSource result = getInputResource(input); + if (result == null) { + throw new UncheckedIOException(new FileNotFoundException(input.toString() + " not found")); + } + try (InputStream inputStream = result.getInputStream()) { + return this.getSchemaContext().getSchemaRegistry().readTree(inputStream, inputFormat); + } + } catch (IOException e) { + throw new UncheckedIOException("Invalid input", e); } - // Collect errors and collector context into validation result. - return new ValidationResult(executionContext); } /** - * Deprecated. Initialize the CollectorContext externally and call loadCollectors when done. - * - * @param node JsonNode - * @return ValidationResult + * Loads the resource from the input iri. + * + * @param input the input + * @return the input stream source */ - @Deprecated - public ValidationResult validateAndCollect(JsonNode node) { - return validateAndCollect(createExecutionContext(), node, node, atRoot()); + private InputStreamSource getInputResource(AbsoluteIri input) { + InputStreamSource result = null; + List resourceLoaders = this.getSchemaContext().getSchemaRegistry().getSchemaLoader() + .getResourceLoaders(); + for (ResourceLoader loader : resourceLoaders) { + result = loader.getResource(input); + if (result != null) { + return result; + } + } + return ClasspathResourceLoader.getInstance().getResource(input); } /************************ END OF VALIDATE METHODS **********************************/ @@ -1108,7 +1313,7 @@ public ValidationResult validateAndCollect(JsonNode node) { * * @return the validation result */ - public ValidationResult walk(ExecutionContext executionContext, JsonNode node, boolean validate, + public Result walk(ExecutionContext executionContext, JsonNode node, boolean validate, ExecutionContextCustomizer executionCustomizer) { return walkAtNodeInternal(executionContext, node, node, atRoot(), validate, OutputFormat.RESULT, executionCustomizer); @@ -1141,7 +1346,7 @@ public T walk(ExecutionContext executionContext, JsonNode node, OutputFormat * * @return the validation result */ - public ValidationResult walk(ExecutionContext executionContext, JsonNode node, boolean validate, + public Result walk(ExecutionContext executionContext, JsonNode node, boolean validate, Consumer executionCustomizer) { return walkAtNodeInternal(executionContext, node, node, atRoot(), validate, OutputFormat.RESULT, executionCustomizer); @@ -1173,7 +1378,7 @@ public T walk(ExecutionContext executionContext, JsonNode node, OutputFormat * * @return the validation result */ - public ValidationResult walk(ExecutionContext executionContext, JsonNode node, boolean validate) { + public Result walk(ExecutionContext executionContext, JsonNode node, boolean validate) { return walkAtNodeInternal(executionContext, node, node, atRoot(), validate, OutputFormat.RESULT, (ExecutionContextCustomizer) null); } @@ -1187,7 +1392,7 @@ public ValidationResult walk(ExecutionContext executionContext, JsonNode node, b * @param validate true to validate the input against the schema * @return the validation result */ - public ValidationResult walk(ExecutionContext executionContext, String input, InputFormat inputFormat, + public Result walk(ExecutionContext executionContext, String input, InputFormat inputFormat, boolean validate) { JsonNode node = deserialize(input, inputFormat); return walkAtNodeInternal(executionContext, node, node, atRoot(), validate, OutputFormat.RESULT, @@ -1222,7 +1427,7 @@ public T walk(ExecutionContext executionContext, String input, InputFormat i * @param executionCustomizer the customizer * @return the validation result */ - public ValidationResult walk(ExecutionContext executionContext, String input, InputFormat inputFormat, + public Result walk(ExecutionContext executionContext, String input, InputFormat inputFormat, boolean validate, ExecutionContextCustomizer executionCustomizer) { JsonNode node = deserialize(input, inputFormat); return walkAtNodeInternal(executionContext, node, node, atRoot(), validate, OutputFormat.RESULT, executionCustomizer); @@ -1253,10 +1458,34 @@ public T walk(ExecutionContext executionContext, String input, InputFormat i * @param validate true to validate the input against the schema * @return the validation result */ - public ValidationResult walk(JsonNode node, boolean validate) { + public Result walk(JsonNode node, boolean validate) { return walk(createExecutionContext(), node, validate); } + /** + * Walk the JSON node. + * + * @param node the input + * @param validate true to validate the input against the schema + * @param executionCustomizer the customizer + * @return the validation result + */ + public Result walk(JsonNode node, boolean validate, ExecutionContextCustomizer executionCustomizer) { + return walk(createExecutionContext(), node, validate, executionCustomizer); + } + + /** + * Walk the JSON node. + * + * @param node the input + * @param validate true to validate the input against the schema + * @param executionCustomizer the customizer + * @return the validation result + */ + public Result walk(JsonNode node, boolean validate, Consumer executionCustomizer) { + return walk(createExecutionContext(), node, validate, executionCustomizer); + } + /** * Walk the JSON node. * @@ -1269,7 +1498,7 @@ public ValidationResult walk(JsonNode node, boolean validate) { public T walk(JsonNode node, OutputFormat outputFormat, boolean validate) { return walk(createExecutionContext(), node, outputFormat, validate, (ExecutionContextCustomizer) null); } - + /** * Walk the input. * @@ -1278,7 +1507,7 @@ public T walk(JsonNode node, OutputFormat outputFormat, boolean validate) * @param validate true to validate the input against the schema * @return the validation result */ - public ValidationResult walk(String input, InputFormat inputFormat, boolean validate) { + public Result walk(String input, InputFormat inputFormat, boolean validate) { return walk(createExecutionContext(), deserialize(input, inputFormat), validate); } @@ -1291,7 +1520,7 @@ public ValidationResult walk(String input, InputFormat inputFormat, boolean vali * @param executionCustomizer the customizer * @return the validation result */ - public ValidationResult walk(String input, InputFormat inputFormat, boolean validate, + public Result walk(String input, InputFormat inputFormat, boolean validate, ExecutionContextCustomizer executionCustomizer) { return walk(createExecutionContext(), deserialize(input, inputFormat), validate, executionCustomizer); } @@ -1305,7 +1534,7 @@ public ValidationResult walk(String input, InputFormat inputFormat, boolean vali * @param executionCustomizer the customizer * @return the validation result */ - public ValidationResult walk(String input, InputFormat inputFormat, boolean validate, + public Result walk(String input, InputFormat inputFormat, boolean validate, Consumer executionCustomizer) { return walk(createExecutionContext(), deserialize(input, inputFormat), validate, executionCustomizer); } @@ -1320,59 +1549,47 @@ public ValidationResult walk(String input, InputFormat inputFormat, boolean vali * @param validate true to validate the input against the schema * @return the validation result */ - public ValidationResult walkAtNode(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, - JsonNodePath instanceLocation, boolean validate) { + public Result walkAtNode(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, + NodePath instanceLocation, boolean validate) { return walkAtNodeInternal(executionContext, node, rootNode, instanceLocation, validate, OutputFormat.RESULT, (ExecutionContextCustomizer) null); } private T walkAtNodeInternal(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, - JsonNodePath instanceLocation, boolean validate, OutputFormat format, Consumer executionCustomizer) { + NodePath instanceLocation, boolean validate, OutputFormat format, Consumer executionCustomizer) { return walkAtNodeInternal(executionContext, node, rootNode, instanceLocation, validate, format, - (executeContext, validationContext) -> executionCustomizer.accept(executeContext)); + (executeContext, schemaContext) -> executionCustomizer.accept(executeContext)); } private T walkAtNodeInternal(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, - JsonNodePath instanceLocation, boolean validate, OutputFormat format, + NodePath instanceLocation, boolean validate, OutputFormat format, ExecutionContextCustomizer executionCustomizer) { if (executionCustomizer != null) { - executionCustomizer.customize(executionContext, this.validationContext); + executionCustomizer.customize(executionContext, this.schemaContext); } // Walk through the schema. - walk(executionContext, node, rootNode, instanceLocation, validate); - - // Get the config. - SchemaValidatorsConfig config = this.validationContext.getConfig(); - // When walk is called in series of nested call we don't want to load the collectors every time. Leave to the API to decide when to call collectors. - /* When doLoadCollectors is removed after the deprecation period the following block should be removed */ - if (config.doLoadCollectors()) { - // Get the collector context. - CollectorContext collectorContext = executionContext.getCollectorContext(); - - // Load all the data from collectors into the context. - collectorContext.loadCollectors(); - } - return format.format(this, executionContext, this.validationContext); + walk(executionContext, node, rootNode, instanceLocation, validate); + return format.format(this, executionContext, this.schemaContext); } @Override public void walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, - JsonNodePath instanceLocation, boolean shouldValidateSchema) { + NodePath instanceLocation, boolean shouldValidateSchema) { // Walk through all the JSONWalker's. int currentErrors = executionContext.getErrors().size(); - for (JsonValidator validator : getValidators()) { - JsonNodePath evaluationPathWithKeyword = validator.getEvaluationPath(); + for (KeywordValidator validator : getValidators()) { + NodePath evaluationPathWithKeyword = validator.getEvaluationPath(); try { // Call all the pre-walk listeners. If at least one of the pre walk listeners // returns SKIP, then skip the walk. - if (this.validationContext.getConfig().getKeywordWalkListenerRunner().runPreWalkListeners(executionContext, + if (executionContext.getWalkConfig().getKeywordWalkListenerRunner().runPreWalkListeners(executionContext, evaluationPathWithKeyword.getName(-1), node, rootNode, instanceLocation, this, validator)) { validator.walk(executionContext, node, rootNode, instanceLocation, shouldValidateSchema); } } finally { // Call all the post-walk listeners. - this.validationContext.getConfig().getKeywordWalkListenerRunner().runPostWalkListeners(executionContext, + executionContext.getWalkConfig().getKeywordWalkListenerRunner().runPostWalkListeners(executionContext, evaluationPathWithKeyword.getName(-1), node, rootNode, instanceLocation, this, validator, executionContext.getErrors().subList(currentErrors, executionContext.getErrors().size())); @@ -1399,7 +1616,7 @@ public TypeValidator getTypeValidator() { return this.typeValidator; } - public List getValidators() { + public List getValidators() { if (this.validators == null) { this.validators = Collections.unmodifiableList(read(getSchemaNode())); } @@ -1407,18 +1624,18 @@ public List getValidators() { } /** - * Initializes the validators' {@link com.networknt.schema.JsonSchema} instances. - * For avoiding issues with concurrency, in 1.0.49 the {@link com.networknt.schema.JsonSchema} instances affiliated with + * Initializes the validators' {@link com.networknt.schema.Schema} instances. + * For avoiding issues with concurrency, in 1.0.49 the {@link com.networknt.schema.Schema} instances affiliated with * validators were modified to no more preload the schema and lazy loading is used instead. *

This comes with the issue that this way you cannot rely on validating important schema features, in particular - * $ref resolution at instantiation from {@link com.networknt.schema.JsonSchemaFactory}.

- *

By calling initializeValidators you can enforce preloading of the {@link com.networknt.schema.JsonSchema} + * $ref resolution at instantiation from {@link com.networknt.schema.SchemaRegistry}.

+ *

By calling initializeValidators you can enforce preloading of the {@link com.networknt.schema.Schema} * instances of the validators.

*/ public void initializeValidators() { if (!this.validatorsLoaded) { - for (final JsonValidator validator : getValidators()) { - validator.preloadJsonSchema(); + for (final KeywordValidator validator : getValidators()) { + validator.preloadSchema(); } /* * This is only set to true after the preload as it may throw an exception for @@ -1439,16 +1656,15 @@ public boolean isRecursiveAnchor() { * @return the execution context */ public ExecutionContext createExecutionContext() { - SchemaValidatorsConfig config = validationContext.getConfig(); + SchemaRegistryConfig config = schemaContext.getSchemaRegistryConfig(); // Copy execution config defaults from validation config - ExecutionConfig executionConfig = new ExecutionConfig(); - executionConfig.setLocale(config.getLocale()); - executionConfig.setFormatAssertionsEnabled(config.getFormatAssertionsEnabled()); - executionConfig.setFailFast(config.isFailFast()); - + ExecutionConfig executionConfig = ExecutionConfig.builder() + .locale(config.getLocale()) + .formatAssertionsEnabled(config.getFormatAssertionsEnabled()) + .failFast(config.isFailFast()).build(); ExecutionContext executionContext = new ExecutionContext(executionConfig); if(config.getExecutionContextCustomizer() != null) { - config.getExecutionContextCustomizer().customize(executionContext, validationContext); + config.getExecutionContextCustomizer().customize(executionContext, schemaContext); } return executionContext; } diff --git a/src/main/java/com/networknt/schema/SchemaContext.java b/src/main/java/com/networknt/schema/SchemaContext.java new file mode 100644 index 000000000..7ff84923d --- /dev/null +++ b/src/main/java/com/networknt/schema/SchemaContext.java @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2016 Network New Technologies Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.networknt.schema; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import com.fasterxml.jackson.databind.JsonNode; +import com.networknt.schema.dialect.Dialect; +import com.networknt.schema.keyword.KeywordValidator; +import com.networknt.schema.path.NodePath; + +/** + * The schema context associated with a schema and all its validators. + */ +public class SchemaContext { + private final Dialect dialect; + private final SchemaRegistry schemaRegistry; + private final ConcurrentMap schemaReferences; + private final ConcurrentMap schemaResources; + private final ConcurrentMap dynamicAnchors; + + /** + * When set to true, support for discriminators is enabled for validations of + * oneOf, anyOf and allOf as described on GitHub. + * + * When enabled, the validation of anyOf and allOf in + * polymorphism will respect OpenAPI 3 style discriminators as described in the + * OpenAPI + * 3.0.3 spec. The presence of a discriminator configuration on the schema + * will lead to the following changes in the behavior: + *
    + *
  • for oneOf the spec is unfortunately very vague. Whether + * oneOf semantics should be affected by discriminators or not is + * not even 100% clear within the members of the OAS steering committee. + * Therefore oneOf at the moment ignores discriminators
  • + *
  • for anyOf the validation will choose one of the candidate + * schemas for validation based on the discriminator property value and will + * pass validation when this specific schema passes. This is in particular + * useful when the payload could match multiple candidates in the + * anyOf list and could lead to ambiguity. Example: type B has all + * mandatory properties of A and adds more mandatory ones. Whether the payload + * is an A or B is determined via the discriminator property name. A payload + * indicating it is an instance of B then requires passing the validation of B + * and passing the validation of A would not be sufficient anymore.
  • + *
  • for allOf use cases with discriminators defined on the + * copied-in parent type, it is possible to automatically validate against a + * subtype. Example: some schema specifies that there is a field of type A. A + * carries a discriminator field and B inherits from A. Then B is automatically + * a candidate for validation as well and will be chosen in case the + * discriminator property matches
  • + *
+ * + * @param openAPI3StyleDiscriminators whether discriminators should be used. + * Defaults to false + * @since 1.0.51 + */ + private final boolean discriminatorKeywordEnabled; + + /** + * When a field is set as nullable in the OpenAPI specification, the schema + * validator validates that it is nullable however continues with validation + * against the nullable field + *

+ * If handleNullableField is set to true && incoming field is nullable && value + * is field: null --> succeed If handleNullableField is set to false && incoming + * field is nullable && value is field: null --> it is up to the type validator + * using the SchemaValidator to handle it. + */ + private final boolean nullableKeywordEnabled; + + public SchemaContext(Dialect dialect, + SchemaRegistry schemaRegistry) { + this(dialect, schemaRegistry, new ConcurrentHashMap<>(), new ConcurrentHashMap<>(), new ConcurrentHashMap<>()); + } + + public SchemaContext(Dialect dialect, SchemaRegistry schemaRegistry, + ConcurrentMap schemaReferences, + ConcurrentMap schemaResources, ConcurrentMap dynamicAnchors) { + if (dialect == null) { + throw new IllegalArgumentException("Dialect must not be null"); + } + if (schemaRegistry == null) { + throw new IllegalArgumentException("SchemaRegistry must not be null"); + } + this.dialect = dialect; + this.schemaRegistry = schemaRegistry; + this.schemaReferences = schemaReferences; + this.schemaResources = schemaResources; + this.dynamicAnchors = dynamicAnchors; + + if (dialect.getKeywords().containsKey("discriminator")) { + this.discriminatorKeywordEnabled = true; + } else { + this.discriminatorKeywordEnabled = false; + } + + if (dialect.getKeywords().containsKey("nullable")) { + this.nullableKeywordEnabled = true; + } else { + this.nullableKeywordEnabled = false; + } + } + + public Schema newSchema(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, Schema parentSchema) { + return getSchemaRegistry().create(this, schemaLocation, evaluationPath, schemaNode, parentSchema); + } + + public KeywordValidator newValidator(SchemaLocation schemaLocation, NodePath evaluationPath, + String keyword /* keyword */, JsonNode schemaNode, Schema parentSchema) { + return this.dialect.newValidator(this, schemaLocation, evaluationPath, keyword, schemaNode, parentSchema); + } + + public String resolveSchemaId(JsonNode schemaNode) { + return this.dialect.readId(schemaNode); + } + + public SchemaRegistry getSchemaRegistry() { + return this.schemaRegistry; + } + + public SchemaRegistryConfig getSchemaRegistryConfig() { + return this.schemaRegistry.getSchemaRegistryConfig(); + } + + /** + * Gets the schema references identified by the ref uri. + * + * @return the schema references + */ + public ConcurrentMap getSchemaReferences() { + return this.schemaReferences; + } + + /** + * Gets the schema resources identified by id. + * + * @return the schema resources + */ + public ConcurrentMap getSchemaResources() { + return this.schemaResources; + } + + /** + * Gets the dynamic anchors. + * + * @return the dynamic anchors + */ + public ConcurrentMap getDynamicAnchors() { + return this.dynamicAnchors; + } + + public Dialect getDialect() { + return this.dialect; + } + + public boolean isDiscriminatorKeywordEnabled() { + return discriminatorKeywordEnabled; + } + + public boolean isNullableKeywordEnabled() { + return nullableKeywordEnabled; + } +} diff --git a/src/main/java/com/networknt/schema/JsonSchemaException.java b/src/main/java/com/networknt/schema/SchemaException.java similarity index 75% rename from src/main/java/com/networknt/schema/JsonSchemaException.java rename to src/main/java/com/networknt/schema/SchemaException.java index 1add66f77..fe94a0ef3 100644 --- a/src/main/java/com/networknt/schema/JsonSchemaException.java +++ b/src/main/java/com/networknt/schema/SchemaException.java @@ -20,22 +20,22 @@ import java.util.List; /** - * Represents an error when processing the JsonSchema. + * Represents an error when processing the Schema. */ -public class JsonSchemaException extends RuntimeException { +public class SchemaException extends RuntimeException { private static final long serialVersionUID = -7805792737596582110L; - private final ValidationMessage error; + private final Error error; - public JsonSchemaException(ValidationMessage error) { + public SchemaException(Error error) { this.error = error; } - public JsonSchemaException(String message) { + public SchemaException(String message) { super(message); this.error = null; } - public JsonSchemaException(Throwable throwable) { + public SchemaException(Throwable throwable) { super(throwable); this.error = null; } @@ -45,11 +45,11 @@ public String getMessage() { return this.error != null ? this.error.getMessage() : super.getMessage(); } - public ValidationMessage getError() { + public Error getError() { return this.error; } - public List getErrors() { + public List getErrors() { if (error == null) { return Collections.emptyList(); } diff --git a/src/main/java/com/networknt/schema/JsonSchemaIdValidator.java b/src/main/java/com/networknt/schema/SchemaIdValidator.java similarity index 82% rename from src/main/java/com/networknt/schema/JsonSchemaIdValidator.java rename to src/main/java/com/networknt/schema/SchemaIdValidator.java index 3a2ee98f7..723136ccb 100644 --- a/src/main/java/com/networknt/schema/JsonSchemaIdValidator.java +++ b/src/main/java/com/networknt/schema/SchemaIdValidator.java @@ -21,7 +21,7 @@ /** * Validator for validating the correctness of $id. */ -public interface JsonSchemaIdValidator { +public interface SchemaIdValidator { /** * Validates if the $id value is valid. * @@ -29,17 +29,17 @@ public interface JsonSchemaIdValidator { * @param rootSchema true if this is a root schema * @param schemaLocation the schema location * @param resolvedSchemaLocation the schema location after resolving with the id - * @param validationContext the validation context for instance to get the + * @param schemaContext the schema context for instance to get the * meta schema * @return true if valid */ boolean validate(String id, boolean rootSchema, SchemaLocation schemaLocation, - SchemaLocation resolvedSchemaLocation, ValidationContext validationContext); + SchemaLocation resolvedSchemaLocation, SchemaContext schemaContext); - JsonSchemaIdValidator DEFAULT = new DefaultJsonSchemaIdValidator(); + SchemaIdValidator DEFAULT = new DefaultSchemaIdValidator(); /** - * Implementation of {@link JsonSchemaIdValidator}. + * Implementation of {@link SchemaIdValidator}. *

* Note that this does not strictly follow the specification. *

@@ -48,10 +48,10 @@ boolean validate(String id, boolean rootSchema, SchemaLocation schemaLocation, *

* This also allows non-empty fragments. */ - class DefaultJsonSchemaIdValidator implements JsonSchemaIdValidator { + class DefaultSchemaIdValidator implements SchemaIdValidator { @Override public boolean validate(String id, boolean rootSchema, SchemaLocation schemaLocation, - SchemaLocation resolvedSchemaLocation, ValidationContext validationContext) { + SchemaLocation resolvedSchemaLocation, SchemaContext schemaContext) { if (hasNoContext(schemaLocation)) { // The following are non-standard if (isFragment(id) || startsWithSlash(id)) { diff --git a/src/main/java/com/networknt/schema/SchemaLocation.java b/src/main/java/com/networknt/schema/SchemaLocation.java index 18d44448d..ecbbb3099 100644 --- a/src/main/java/com/networknt/schema/SchemaLocation.java +++ b/src/main/java/com/networknt/schema/SchemaLocation.java @@ -20,6 +20,9 @@ import java.nio.charset.StandardCharsets; import java.util.Objects; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.path.PathType; + /** * The schema location is the canonical IRI of the schema object plus a JSON * Pointer fragment indicating the subschema that produced a result. In contrast @@ -27,8 +30,8 @@ * applicators such as $ref or $dynamicRef. */ public class SchemaLocation { - private static final JsonNodePath JSON_POINTER = new JsonNodePath(PathType.JSON_POINTER); - private static final JsonNodePath ANCHOR = new JsonNodePath(PathType.URI_REFERENCE); + private static final NodePath JSON_POINTER = new NodePath(PathType.JSON_POINTER); + private static final NodePath ANCHOR = new NodePath(PathType.URI_REFERENCE); /** * Represents a relative schema location to the current document. @@ -36,7 +39,7 @@ public class SchemaLocation { public static final SchemaLocation DOCUMENT = new SchemaLocation(null, JSON_POINTER); private final AbsoluteIri absoluteIri; - private final JsonNodePath fragment; + private final NodePath fragment; private volatile String value = null; // computed lazily @@ -46,7 +49,7 @@ public class SchemaLocation { * @param absoluteIri canonical absolute IRI of the schema object * @param fragment the fragment */ - public SchemaLocation(AbsoluteIri absoluteIri, JsonNodePath fragment) { + public SchemaLocation(AbsoluteIri absoluteIri, NodePath fragment) { this.absoluteIri = absoluteIri; this.fragment = fragment; } @@ -77,7 +80,7 @@ public AbsoluteIri getAbsoluteIri() { * * @return the fragment */ - public JsonNodePath getFragment() { + public NodePath getFragment() { return this.fragment; } @@ -115,7 +118,7 @@ public static SchemaLocation of(String iri) { return DOCUMENT; } AbsoluteIri absoluteIri = null; - JsonNodePath fragment = JSON_POINTER; + NodePath fragment = JSON_POINTER; int index = iri.indexOf('#'); if (index == -1) { absoluteIri = AbsoluteIri.of(iri); @@ -141,7 +144,7 @@ public SchemaLocation resolve(String absoluteIriReferenceOrFragment) { if ("#".equals(absoluteIriReferenceOrFragment)) { return new SchemaLocation(this.getAbsoluteIri(), JSON_POINTER); } - JsonNodePath fragment = JSON_POINTER; + NodePath fragment = JSON_POINTER; int index = absoluteIriReferenceOrFragment.indexOf('#'); AbsoluteIri absoluteIri = this.getAbsoluteIri(); String part0 = index == -1 ? absoluteIriReferenceOrFragment @@ -211,11 +214,11 @@ public static class Fragment { * @param fragmentString the fragment * @return the path */ - public static JsonNodePath of(String fragmentString) { + public static NodePath of(String fragmentString) { if (fragmentString.startsWith("#")) { fragmentString = fragmentString.substring(1); } - JsonNodePath fragment = JSON_POINTER; + NodePath fragment = JSON_POINTER; String[] fragmentParts = fragmentString.split("/"); boolean jsonPointer = false; @@ -330,7 +333,7 @@ public static Builder builder() { */ public static class Builder { private AbsoluteIri absoluteIri; - private JsonNodePath fragment = JSON_POINTER; + private NodePath fragment = JSON_POINTER; /** * Sets the canonical absolute IRI of the schema object. @@ -365,7 +368,7 @@ protected Builder absoluteIri(String absoluteIri) { * @param fragment the fragment * @return the builder */ - protected Builder fragment(JsonNodePath fragment) { + protected Builder fragment(NodePath fragment) { this.fragment = fragment; return this; } diff --git a/src/main/java/com/networknt/schema/JsonSchemaRef.java b/src/main/java/com/networknt/schema/SchemaRef.java similarity index 77% rename from src/main/java/com/networknt/schema/JsonSchemaRef.java rename to src/main/java/com/networknt/schema/SchemaRef.java index c4d4cf4ca..e3193d9ce 100644 --- a/src/main/java/com/networknt/schema/JsonSchemaRef.java +++ b/src/main/java/com/networknt/schema/SchemaRef.java @@ -18,17 +18,17 @@ import java.util.function.Supplier; /** - * Use this object instead a JsonSchema for references. + * Use this object instead a Schema for references. */ -public class JsonSchemaRef { +public class SchemaRef { - private final Supplier schemaSupplier; + private final Supplier schemaSupplier; - public JsonSchemaRef(Supplier schema) { + public SchemaRef(Supplier schema) { this.schemaSupplier = schema; } - public JsonSchema getSchema() { + public Schema getSchema() { return this.schemaSupplier.get(); } } diff --git a/src/main/java/com/networknt/schema/SchemaRegistry.java b/src/main/java/com/networknt/schema/SchemaRegistry.java new file mode 100644 index 000000000..dfcfb80d9 --- /dev/null +++ b/src/main/java/com/networknt/schema/SchemaRegistry.java @@ -0,0 +1,824 @@ +/* + * Copyright (c) 2016 Network New Technologies Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.networknt.schema; + +import com.fasterxml.jackson.databind.JsonNode; +import com.networknt.schema.dialect.BasicDialectRegistry; +import com.networknt.schema.dialect.DefaultDialectRegistry; +import com.networknt.schema.dialect.Dialect; +import com.networknt.schema.dialect.DialectId; +import com.networknt.schema.dialect.DialectRegistry; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.resource.ResourceLoaders; +import com.networknt.schema.resource.SchemaIdResolvers; +import com.networknt.schema.resource.SchemaLoader; +import com.networknt.schema.serialization.BasicNodeReader; +import com.networknt.schema.serialization.DefaultNodeReader; +import com.networknt.schema.serialization.NodeReader; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.function.Consumer; +import java.util.function.Function; + +/** + * Registry for loading and registering {@link Schema} instances. + *

+ * This can be created with withDefaultDialect(Version) or withDialect(Dialect). + *

+ * The registry should be cached for performance. + *

+ * A different registry should be used when loading unrelated schemas. + *

+ * SchemaRegistry instances are thread-safe provided its configuration is not + * modified. + */ +public class SchemaRegistry { + private static final Logger logger = LoggerFactory.getLogger(SchemaRegistry.class); + + public static class Builder { + private String defaultDialectId; + private DialectRegistry dialectRegistry = null; + private NodeReader nodeReader = null; + private SchemaLoader schemaLoader = null; + private boolean schemaCacheEnabled = true; + private SchemaRegistryConfig schemaRegistryConfig = null; + + /** + * Sets the json node reader to read the data. + *

+ * A location aware object reader can be created using + * NodeReader.builder().locationAware().build(). + * + * @param nodeReader the object reader + * @return the builder + */ + public Builder nodeReader(NodeReader nodeReader) { + this.nodeReader = nodeReader; + return this; + } + + /** + * Sets the json node reader to read the data. + * + *

+         * A location aware object reader can be created using
+         * schemaRegistryBuilder.nodeReader(nodeReader -> nodeReader.locationAware()).
+         * 
+ * + * A json ObjectMapper can be set using + * + *
+         * schemaRegistryBuilder.nodeReader(nodeReader -> nodeReader.jsonMapper(objectMapper))
+         * 
+ * + * @param customizer + * @return the builder + */ + public Builder nodeReader(Consumer customizer) { + DefaultNodeReader.Builder builder = NodeReader.builder(); + customizer.accept(builder); + this.nodeReader = builder.build(); + return this; + } + + public Builder defaultDialectId(String defaultDialectId) { + this.defaultDialectId = defaultDialectId; + return this; + } + + public Builder dialectRegistry(DialectRegistry dialectRegistry) { + this.dialectRegistry = dialectRegistry; + return this; + } + + public Builder schemaCacheEnabled(boolean schemaCacheEnabled) { + this.schemaCacheEnabled = schemaCacheEnabled; + return this; + } + + public Builder schemaLoader(SchemaLoader schemaLoader) { + this.schemaLoader = schemaLoader; + return this; + } + + public Builder schemaLoader(Consumer customizer) { + SchemaLoader.Builder builder = null; + if (this.schemaLoader != null) { + builder = SchemaLoader.builder(this.schemaLoader); + } else { + builder = SchemaLoader.builder(); + } + customizer.accept(builder); + this.schemaLoader = builder.build(); + return this; + } + + public Builder resourceLoaders(Consumer customizer) { + SchemaLoader.Builder builder = null; + if (this.schemaLoader != null) { + builder = SchemaLoader.builder(this.schemaLoader); + } else { + builder = SchemaLoader.builder(); + } + customizer.accept(builder.getResourceLoadersBuilder()); + this.schemaLoader = builder.build(); + return this; + } + + public Builder schemaIdResolvers(Consumer customizer) { + SchemaLoader.Builder builder = null; + if (this.schemaLoader != null) { + builder = SchemaLoader.builder(this.schemaLoader); + } else { + builder = SchemaLoader.builder(); + } + customizer.accept(builder.getSchemaIdResolversBuilder()); + this.schemaLoader = builder.build(); + return this; + } + + public Builder schemaRegistryConfig(SchemaRegistryConfig schemaRegistryConfig) { + this.schemaRegistryConfig = schemaRegistryConfig; + return this; + } + + /** + * Sets the schema data by absolute IRI. + * + * @param schemas the map of IRI to schema data + * @return the builder + */ + public Builder schemas(Map schemas) { + return this.resourceLoaders(resourceLoaders -> resourceLoaders.resources(schemas)); + } + + /** + * Sets the schema data by absolute IRI function. + * + * @param schemas the function that returns schema data given IRI + * @return the builder + */ + public Builder schemas(Function schemas) { + return this.resourceLoaders(resourceLoaders -> resourceLoaders.resources(schemas)); + } + + /** + * Sets the schema data by using two mapping functions. + *

+ * Firstly to map the IRI to an object. If the object is null no mapping is + * performed. + *

+ * Next to map the object to the schema data. + * + * @param the type of the object + * @param mapIriToObject the mapping of IRI to object + * @param mapObjectToData the mappingof object to schema data + * @return the builder + */ + public Builder schemas(Function mapIriToObject, Function mapObjectToData) { + return this.resourceLoaders(resourceLoaders -> resourceLoaders.resources(mapIriToObject, mapObjectToData)); + } + + public SchemaRegistry build() { + return new SchemaRegistry(nodeReader, defaultDialectId, schemaLoader, schemaCacheEnabled, + dialectRegistry, schemaRegistryConfig); + } + } + + private final NodeReader nodeReader; + private final String defaultDialectId; + private final SchemaLoader schemaLoader; + private final ConcurrentMap schemaCache = new ConcurrentHashMap<>(); + private final boolean schemaCacheEnabled; + private final DialectRegistry dialectRegistry; + private final SchemaRegistryConfig schemaRegistryConfig; + + private SchemaRegistry(NodeReader nodeReader, String defaultDialectId, SchemaLoader schemaLoader, + boolean schemaCacheEnabled, DialectRegistry dialectRegistry, SchemaRegistryConfig schemaRegistryConfig) { + if (defaultDialectId == null || defaultDialectId.trim().isEmpty()) { + throw new IllegalArgumentException("defaultDialectId must not be null or empty"); + } + this.nodeReader = nodeReader != null ? nodeReader : BasicNodeReader.getInstance(); + this.defaultDialectId = defaultDialectId; + this.schemaLoader = schemaLoader != null ? schemaLoader : SchemaLoader.getDefault(); + this.schemaCacheEnabled = schemaCacheEnabled; + this.dialectRegistry = dialectRegistry != null ? dialectRegistry : new DefaultDialectRegistry(); + this.schemaRegistryConfig = schemaRegistryConfig != null ? schemaRegistryConfig + : SchemaRegistryConfig.getInstance(); + } + + /** + * Builder without keywords or formats. + *

+ * Typically {@link #builder(SchemaRegistry)} or + * {@link #withDefaultDialect(SpecificationVersion)} or + * {@link #withDialect(Dialect)} would be used instead. + * + * @return a builder instance without any keywords or formats - usually not what + * one needs. + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Creates a new schema registry with a default schema dialect. The schema + * dialect will only be used if the input does not specify a $schema. + *

+ * This uses a dialect registry that contains all the supported standard + * specification dialects, Draft 4, Draft 6, Draft 7, Draft 2019-09 and Draft + * 2020-12. + * + * @param specificationVersion the default dialect id corresponding to the + * specification version used when the schema does + * not specify the $schema keyword + * @return the factory + */ + public static SchemaRegistry withDefaultDialect(SpecificationVersion specificationVersion) { + return withDefaultDialect(specificationVersion, null); + } + + /** + * Creates a new schema registry with a default schema dialect. The schema + * dialect will only be used if the input does not specify a $schema. + *

+ * This uses a dialect registry that contains all the supported standard + * specification dialects, Draft 4, Draft 6, Draft 7, Draft 2019-09 and Draft + * 2020-12. + * + * @param specificationVersion the default dialect id corresponding to the + * specification version used when the schema does + * not specify the $schema keyword + * @param customizer to customize the registry + * @return the factory + */ + public static SchemaRegistry withDefaultDialect(SpecificationVersion specificationVersion, + Consumer customizer) { + Dialect dialect = Specification.getDialect(specificationVersion); + return withDefaultDialectId(dialect.getId(), customizer); + } + + /** + * Creates a new schema registry with a default schema dialect. The schema + * dialect will only be used if the input does not specify a $schema. + *

+ * This uses a dialect registry that contains all the supported standard + * specification dialects, Draft 4, Draft 6, Draft 7, Draft 2019-09 and Draft + * 2020-12. + * + * @param dialectId the default dialect id used when the schema does not + * specify the $schema keyword + * @param customizer to customize the registry + * @return the factory + */ + public static SchemaRegistry withDefaultDialectId(String dialectId, Consumer customizer) { + SchemaRegistry.Builder builder = builder().defaultDialectId(dialectId); + if (customizer != null) { + customizer.accept(builder); + } + return builder.build(); + } + + + /** + * Creates a new schema registry with a default schema dialect. The schema + * dialect will only be used if the input does not specify a $schema. + *

+ * This uses a dialect registry that contains all the supported standard + * specification dialects, Draft 4, Draft 6, Draft 7, Draft 2019-09 and Draft + * 2020-12. + * + * @param dialect the default dialect used when the schema does not specify the + * $schema keyword + * @return the factory + */ + public static SchemaRegistry withDefaultDialect(Dialect dialect) { + return withDefaultDialect(dialect, null); + } + + /** + * Creates a new schema registry with a default schema dialect. The schema + * dialect will only be used if the input does not specify a $schema. + *

+ * This uses a dialect registry that contains all the supported standard + * specification dialects, Draft 4, Draft 6, Draft 7, Draft 2019-09 and Draft + * 2020-12. + * + * @param dialect the default dialect used when the schema does not specify + * the $schema keyword + * @param customizer to customize the registry + * @return the factory + */ + public static SchemaRegistry withDefaultDialect(Dialect dialect, Consumer customizer) { + SchemaRegistry.Builder builder = builder().defaultDialectId(dialect.getId()) + .dialectRegistry(new DefaultDialectRegistry(dialect)); + if (customizer != null) { + customizer.accept(builder); + } + return builder.build(); + } + + /** + * Gets a new schema registry that supports a specific dialect only. + *

+ * Schemas that do not specify dialect using $schema will use the dialect. + *

+ * This uses a dialect registry that only contains this dialect and will throw + * an exception for unknown dialects. + * + * @param dialect the dialect + * @return the schema registry + */ + public static SchemaRegistry withDialect(Dialect dialect) { + return withDialect(dialect, null); + } + + /** + * Gets a new schema registry that supports a list of specific dialects only. + *

+ * Schemas that do not specify dialect using $schema will use the first dialect + * on the list. + *

+ * This uses a dialect registry that only contains the list of dialects and will + * throw an exception for unknown dialects. + * + * @param dialect the dialect + * @param customizer to customize the registry + * @return the schema registry + */ + public static SchemaRegistry withDialect(Dialect dialect, Consumer customizer) { + SchemaRegistry.Builder builder = builder().defaultDialectId(dialect.getId()) + .dialectRegistry(new BasicDialectRegistry(dialect)); + if (customizer != null) { + customizer.accept(builder); + } + return builder.build(); + } + + /** + * Gets a new schema registry that supports a list of specific dialects only. + *

+ * Schemas that do not specify dialect using $schema will use the first dialect + * on the list. + *

+ * This uses a dialect registry that only contains the list of dialects and will + * throw an exception for unknown dialects. + * + * @param dialects the dialects with the first being the default dialect + * @return the schema registry + */ + public static SchemaRegistry withDialects(List dialects) { + return withDialects(dialects, null); + } + + /** + * Gets a new schema registry that supports a specific dialect only. + *

+ * Schemas that do not specify dialect using $schema will use the dialect. + *

+ * This uses a dialect registry that only contains this dialect and will throw + * an exception for unknown dialects. + * + * @param dialects the dialects with the first being the default dialect + * @param customizer to customize the registry + * @return the schema registry + */ + public static SchemaRegistry withDialects(List dialects, Consumer customizer) { + SchemaRegistry.Builder builder = builder().defaultDialectId(dialects.get(0).getId()) + .dialectRegistry(new BasicDialectRegistry(dialects)); + if (customizer != null) { + customizer.accept(builder); + } + return builder.build(); + } + + + /** + * Builder from an existing {@link SchemaRegistry}. + *

+ * + * SchemaRegistry.builder(SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2019_09)); + * + * + * @param blueprint the existing factory + * @return the builder + */ + public static Builder builder(SchemaRegistry blueprint) { + Builder builder = builder().schemaLoader(blueprint.schemaLoader) + .defaultDialectId(blueprint.defaultDialectId) + .nodeReader(blueprint.nodeReader) + .dialectRegistry(blueprint.dialectRegistry) + .schemaRegistryConfig(blueprint.schemaRegistryConfig); + return builder; + } + + /** + * Gets the schema loader. + * + * @return the schema loader + */ + public SchemaLoader getSchemaLoader() { + return this.schemaLoader; + } + + /** + * Creates a schema from initial input. + * + * @param schemaUri the schema location + * @param schemaNode the schema data node + * @return the schema + */ + protected Schema newSchema(SchemaLocation schemaUri, JsonNode schemaNode) { + final SchemaContext schemaContext = createSchemaContext(schemaNode); + Schema jsonSchema = doCreate(schemaContext, getSchemaLocation(schemaUri), + new NodePath(schemaContext.getSchemaRegistryConfig().getPathType()), schemaNode, null, false); + preload(jsonSchema); + return jsonSchema; + } + + /** + * Preloads the json schema if the configuration option is set. + * + * @param schema the schema to preload + * @param config containing the configuration option + */ + private void preload(Schema schema) { + if (this.getSchemaRegistryConfig().isPreloadSchema()) { + try { + /* + * Attempt to preload and resolve $refs for performance. + */ + schema.initializeValidators(); + } catch (Exception e) { + /* + * Do nothing here to allow the schema to be cached even if the remote $ref + * cannot be resolved at this time. If the developer wants to ensure that all + * remote $refs are currently resolvable they need to call initializeValidators + * themselves. + */ + } + } + } + + public Schema create(SchemaContext schemaContext, SchemaLocation schemaLocation, NodePath evaluationPath, + JsonNode schemaNode, Schema parentSchema) { + return doCreate(schemaContext, schemaLocation, evaluationPath, schemaNode, parentSchema, false); + } + + private Schema doCreate(SchemaContext schemaContext, SchemaLocation schemaLocation, NodePath evaluationPath, + JsonNode schemaNode, Schema parentSchema, boolean suppressSubSchemaRetrieval) { + return Schema.from(withDialect(schemaContext, schemaNode), schemaLocation, evaluationPath, schemaNode, + parentSchema, suppressSubSchemaRetrieval); + } + + /** + * Determines the schema context to use for the schema given the parent schema + * context. + *

+ * This is typically the same schema context unless the schema has a different + * $schema from the parent. + *

+ * If the schema does not define a $schema, the parent should be used. + * + * @param schemaContext the parent schema context + * @param schemaNode the schema node + * @return the schema context to use + */ + private SchemaContext withDialect(SchemaContext schemaContext, JsonNode schemaNode) { + Dialect dialect = getDialect(schemaNode, schemaContext.getSchemaRegistryConfig()); + if (dialect != null && !dialect.getId().equals(schemaContext.getDialect().getId())) { + return new SchemaContext(dialect, schemaContext.getSchemaRegistry(), schemaContext.getSchemaReferences(), + schemaContext.getSchemaResources(), schemaContext.getDynamicAnchors()); + } + return schemaContext; + } + + /** + * Gets the base IRI from the schema retrieval IRI if present otherwise return + * one with a null base IRI. + *

+ * Note that the resolving of the $id or id in the schema node will take place + * in the Schema constructor. + * + * @param schemaLocation the schema retrieval uri + * @return the schema location + */ + protected SchemaLocation getSchemaLocation(SchemaLocation schemaLocation) { + return schemaLocation != null ? schemaLocation : SchemaLocation.DOCUMENT; + } + + protected SchemaContext createSchemaContext(final JsonNode schemaNode) { + final Dialect dialect = getDialectOrDefault(schemaNode); + return new SchemaContext(dialect, this); + } + + private Dialect getDialect(final JsonNode schemaNode, SchemaRegistryConfig config) { + final JsonNode iriNode = schemaNode.get("$schema"); + if (iriNode != null && iriNode.isTextual()) { + return getDialect(iriNode.textValue()); + } + return null; + } + + private Dialect getDialectOrDefault(final JsonNode schemaNode) { + final JsonNode iriNode = schemaNode.get("$schema"); + if (iriNode != null && !iriNode.isNull() && !iriNode.isTextual()) { + throw new SchemaException("Unknown dialect: " + iriNode); + } + final String iri = iriNode == null || iriNode.isNull() ? defaultDialectId : iriNode.textValue(); + return getDialect(iri); + } + + /** + * Gets the dialect that is available to the registry. + * + * @param dialectId the IRI of the meta-schema + * @return the meta-schema + */ + public Dialect getDialect(String dialectId) { + String key = normalizeDialectId(dialectId); + return dialectRegistry.getDialect(key, this); + } + + JsonNode readTree(String content, InputFormat inputFormat) throws IOException { + return this.nodeReader.readTree(content, inputFormat); + } + + JsonNode readTree(InputStream content, InputFormat inputFormat) throws IOException { + return this.nodeReader.readTree(content, inputFormat); + } + + /** + * Gets the schema. + *

+ * Using this is not recommended as there is potentially no base IRI for + * resolving references to the absolute IRI. + * + * @param schema the schema data as a string + * @return the schema + */ + public Schema getSchema(final String schema) { + return getSchema(schema, InputFormat.JSON); + } + + /** + * Gets the schema. + *

+ * Using this is not recommended as there is potentially no base IRI for + * resolving references to the absolute IRI. + * + * @param schema the schema data as a string + * @param inputFormat input format + * @return the schema + */ + public Schema getSchema(final String schema, InputFormat inputFormat) { + try { + final JsonNode schemaNode = readTree(schema, inputFormat); + return newSchema(null, schemaNode); + } catch (IOException ioe) { + logger.error("Failed to load json schema!", ioe); + throw new SchemaException(ioe); + } + } + + /** + * Gets the schema. + *

+ * Using this is not recommended as there is potentially no base IRI for + * resolving references to the absolute IRI. + * + * @param schemaStream the input stream with the schema data + * @return the schema + */ + public Schema getSchema(final InputStream schemaStream) { + return getSchema(schemaStream, InputFormat.JSON); + } + + /** + * Gets the schema. + *

+ * Using this is not recommended as there is potentially no base IRI for + * resolving references to the absolute IRI. + * + * @param schemaStream the input stream with the schema data + * @param inputFormat input format + * @return the schema + */ + public Schema getSchema(final InputStream schemaStream, InputFormat inputFormat) { + try { + final JsonNode schemaNode = readTree(schemaStream, inputFormat); + return newSchema(null, schemaNode); + } catch (IOException ioe) { + logger.error("Failed to load json schema!", ioe); + throw new SchemaException(ioe); + } + } + + /** + * Gets the schema. + * + * @param schemaUri the absolute IRI of the schema which can map to the + * retrieval IRI. + * @return the schema + */ + public Schema getSchema(final SchemaLocation schemaUri) { + Schema schema = loadSchema(schemaUri); + preload(schema); + return schema; + } + + /** + * Loads the schema. + * + * @param schemaUri the absolute IRI of the schema which can map to the + * retrieval IRI. + * @return the schema + */ + public Schema loadSchema(final SchemaLocation schemaUri) { + if (schemaCacheEnabled) { + // ConcurrentHashMap computeIfAbsent does not allow calls that result in a + // recursive update to the map. + // The getMapperSchema potentially recurses to call back to getSchema again + Schema cachedUriSchema = schemaCache.get(schemaUri); + if (cachedUriSchema == null) { + synchronized (this) { // acquire lock on shared registry object to prevent deadlock + cachedUriSchema = schemaCache.get(schemaUri); + if (cachedUriSchema == null) { + cachedUriSchema = getMappedSchema(schemaUri); + if (cachedUriSchema != null) { + schemaCache.put(schemaUri, cachedUriSchema); + } + } + } + } + return cachedUriSchema; + } + return getMappedSchema(schemaUri); + } + + protected Schema getMappedSchema(final SchemaLocation schemaUri) { + try (InputStream inputStream = this.schemaLoader.getSchemaResource(schemaUri.getAbsoluteIri()) + .getInputStream()) { + if (inputStream == null) { + throw new IOException("Cannot load schema at " + schemaUri); + } + final JsonNode schemaNode; + if (isYaml(schemaUri)) { + schemaNode = readTree(inputStream, InputFormat.YAML); + } else { + schemaNode = readTree(inputStream, InputFormat.JSON); + } + + final Dialect dialect = getDialectOrDefault(schemaNode); + NodePath evaluationPath = new NodePath(getSchemaRegistryConfig().getPathType()); + if (schemaUri.getFragment() == null || schemaUri.getFragment().getNameCount() == 0) { + // Schema without fragment + SchemaContext schemaContext = new SchemaContext(dialect, this); + return doCreate(schemaContext, schemaUri, evaluationPath, schemaNode, null, + true /* retrieved via id, resolving will not change anything */); + } else { + // Schema with fragment pointing to sub schema + final SchemaContext schemaContext = createSchemaContext(schemaNode); + SchemaLocation documentLocation = new SchemaLocation(schemaUri.getAbsoluteIri()); + Schema document = doCreate(schemaContext, documentLocation, evaluationPath, schemaNode, null, false); + return document.getRefSchema(schemaUri.getFragment()); + } + } catch (IOException e) { + logger.error("Failed to load json schema from {}", schemaUri.getAbsoluteIri(), e); + SchemaException exception = new SchemaException( + "Failed to load json schema from " + schemaUri.getAbsoluteIri()); + exception.initCause(e); + throw exception; + } + } + + /** + * Gets the schema. + * + * @param schemaUri the absolute IRI of the schema which can map to the + * retrieval IRI. + * @return the schema + */ + public Schema getSchema(final URI schemaUri) { + return getSchema(SchemaLocation.of(schemaUri.toString())); + } + + /** + * Gets the schema. + * + * @param schemaUri the absolute IRI of the schema which can map to the + * retrieval IRI. + * @param jsonNode the node + * @return the schema + */ + public Schema getSchema(final URI schemaUri, final JsonNode jsonNode) { + return newSchema(SchemaLocation.of(schemaUri.toString()), jsonNode); + } + + /** + * Gets the schema. + * + * @param schemaUri the base absolute IRI + * @param jsonNode the node + * @return the schema + */ + public Schema getSchema(final SchemaLocation schemaUri, final JsonNode jsonNode) { + return newSchema(schemaUri, jsonNode); + } + + /** + * Gets the schema. + *

+ * Using this is not recommended as there is potentially no base IRI for + * resolving references to the absolute IRI. + *

+ * Prefer {@link #getSchema(SchemaLocation, JsonNode)} instead to ensure the + * base IRI if no id is present. + * + * @param jsonNode the node + * @return the schema + */ + public Schema getSchema(final JsonNode jsonNode) { + return newSchema(null, jsonNode); + } + + /** + * Gets the schema registry config. + * + * @return the schema registry config + */ + public SchemaRegistryConfig getSchemaRegistryConfig() { + return this.schemaRegistryConfig; + } + + private boolean isYaml(final SchemaLocation schemaUri) { + final String schemeSpecificPart = schemaUri.getAbsoluteIri().toString(); + final int idx = schemeSpecificPart.lastIndexOf('.'); + + if (idx == -1) { + // no extension; assume json + return false; + } + + final String extension = schemeSpecificPart.substring(idx); + return (".yml".equals(extension) || ".yaml".equals(extension)); + } + + /** + * Normalizes the standard JSON schema dialects. + *

+ * This should not normalize any other unrecognized dialects. + * + * @param id the $schema identifier + * @return the normalized uri + */ + static protected String normalizeDialectId(String id) { + boolean found = false; + for (SpecificationVersion flag : SpecificationVersion.values()) { + if (flag.getDialectId().equals(id)) { + found = true; + break; + } + } + if (!found) { + if (id.contains("://json-schema.org/draft")) { + // unnormalized $schema + if (id.contains("/draft-07/")) { + id = DialectId.DRAFT_7; + } else if (id.contains("/draft/2019-09/")) { + id = DialectId.DRAFT_2019_09; + } else if (id.contains("/draft/2020-12/")) { + id = DialectId.DRAFT_2020_12; + } else if (id.contains("/draft-04/")) { + id = DialectId.DRAFT_4; + } else if (id.contains("/draft-06/")) { + id = DialectId.DRAFT_6; + } + } + } + return id; + } +} diff --git a/src/main/java/com/networknt/schema/SchemaRegistryConfig.java b/src/main/java/com/networknt/schema/SchemaRegistryConfig.java new file mode 100644 index 000000000..053f03a62 --- /dev/null +++ b/src/main/java/com/networknt/schema/SchemaRegistryConfig.java @@ -0,0 +1,585 @@ +/* + * Copyright (c) 2016 Network New Technologies Inc. + * + * Licensed under the Apache LicenseBuilder Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.networknt.schema; + +import com.networknt.schema.i18n.DefaultMessageSource; +import com.networknt.schema.i18n.MessageSource; +import com.networknt.schema.path.PathType; +import com.networknt.schema.regex.ECMAScriptRegularExpressionFactory; +import com.networknt.schema.regex.JDKRegularExpressionFactory; +import com.networknt.schema.regex.RegularExpressionFactory; + +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; + +/** + * Configuration for SchemaRegistry that applies to all the schemas its + * validators that is managed by the SchemaRegistry. + */ +public class SchemaRegistryConfig { + private static class Holder { + private static final SchemaRegistryConfig INSTANCE = SchemaRegistryConfig.builder().build(); + } + + /** + * Gets the default config instance. + * + * @return the config + */ + public static SchemaRegistryConfig getInstance() { + return Holder.INSTANCE; + } + + public static final int DEFAULT_PRELOAD_SCHEMA_REF_MAX_NESTING_DEPTH = 40; + + /** + * The execution context customizer that runs by default for all schemas. + */ + private final ExecutionContextCustomizer executionContextCustomizer; + + /** + * Controls if schemas loaded from refs will be cached and reused for subsequent runs. + */ + private final boolean cacheRefs; + + /** + * When set to true, "messages" provided in schema are used for forming validation errors + * else default messages are used + */ + private final String errorMessageKeyword; + + /** + * When set to true, validator process is stop immediately when a very first + * validation error is discovered. + */ + private final boolean failFast; + + /** + * Since Draft 2019-09 format assertions are not enabled by default. + */ + private final Boolean formatAssertionsEnabled; + + /** + * When set to true, use Java-specific semantics rather than native JavaScript + * semantics + */ + private final boolean javaSemantics; + + /** + * The Locale to consider when loading validation messages from the default resource bundle. + */ + private final Locale locale; + + /** + * When set to true, can interpret round doubles as integers + */ + private final boolean losslessNarrowing; + + /** + * The message source to use for generating localised messages. + */ + private final MessageSource messageSource; + + /** + * The approach used to generate paths in reported messages, logs and errors. Default is the legacy "JSONPath-like" approach. + */ + private final PathType pathType; + + /** + * Controls if the schema will automatically be preloaded. + */ + private final boolean preloadSchema; + + /** + * Controls the max depth of the evaluation path to preload when preloading refs. + */ + private final int preloadSchemaRefMaxNestingDepth; + + /** + * Used to create {@link com.networknt.schema.regex.RegularExpression}. + */ + private final RegularExpressionFactory regularExpressionFactory; + + /** + * Used to validate the acceptable $id values. + */ + private final SchemaIdValidator schemaIdValidator; + + /** + * Contains a mapping of how strict a keyword's validators should be. + * Defaults to {@literal true}. + *

+ * Each validator has its own understanding of what constitutes strict + * and permissive. + */ + private final Map strictness; + + /** + * when validate type, if TYPE_LOOSE = true, will try to convert string to + * different types to match the type defined in schema. + */ + private boolean typeLoose; + + protected SchemaRegistryConfig(boolean cacheRefs, + String errorMessageKeyword, ExecutionContextCustomizer executionContextCustomizer, boolean failFast, + Boolean formatAssertionsEnabled, + boolean javaSemantics, + Locale locale, boolean losslessNarrowing, + MessageSource messageSource, PathType pathType, + boolean preloadSchema, int preloadSchemaRefMaxNestingDepth, + RegularExpressionFactory regularExpressionFactory, SchemaIdValidator schemaIdValidator, + Map strictness, boolean typeLoose) { + super(); + this.cacheRefs = cacheRefs; + this.errorMessageKeyword = errorMessageKeyword; + this.executionContextCustomizer = executionContextCustomizer; + this.failFast = failFast; + this.formatAssertionsEnabled = formatAssertionsEnabled; + this.javaSemantics = javaSemantics; + this.locale = locale; + this.losslessNarrowing = losslessNarrowing; + this.messageSource = messageSource; + this.pathType = pathType; + this.preloadSchema = preloadSchema; + this.preloadSchemaRefMaxNestingDepth = preloadSchemaRefMaxNestingDepth; + this.regularExpressionFactory = regularExpressionFactory; + this.schemaIdValidator = schemaIdValidator; + this.strictness = strictness; + this.typeLoose = typeLoose; + } + + public ExecutionContextCustomizer getExecutionContextCustomizer() { + return this.executionContextCustomizer; + } + + /** + * Gets the format assertion enabled flag. + *

+ * This defaults to null meaning that it will follow the defaults of the + * specification. + *

+ * Since draft 2019-09 this will default to false unless enabled by using the + * $vocabulary keyword. + * + * @return the format assertions enabled flag + */ + public Boolean getFormatAssertionsEnabled() { + return formatAssertionsEnabled; + } + + /** + * Get the locale to consider when generating localised messages (default is the + * JVM default). + *

+ * This locale is on a schema basis and will be used as the default locale for + * {@link com.networknt.schema.ExecutionConfig}. + * + * @return The locale. + */ + public Locale getLocale() { + if (this.locale == null) { + // This should not be cached as it can be changed using Locale#setDefault(Locale) + return Locale.getDefault(); + } + return this.locale; + } + + /** + * Get the message source to use for generating localised messages. + * + * @return the message source + */ + public MessageSource getMessageSource() { + if (this.messageSource == null) { + return DefaultMessageSource.getInstance(); + } + return this.messageSource; + } + + /** + * Get the approach used to generate paths in messages, logs and errors. + * + * @return The path generation approach. + */ + public PathType getPathType() { + return this.pathType; + } + + /** + * Gets the max depth of the evaluation path to preload when preloading refs. + * + * @return the max depth to preload + */ + public int getPreloadSchemaRefMaxNestingDepth() { + return preloadSchemaRefMaxNestingDepth; + } + + /** + * Gets the regular expression factory. + *

+ * This defaults to the JDKRegularExpressionFactory and the implementations + * require inclusion of optional org.jruby.joni:joni or org.graalvm.js:js dependencies. + * + * @return the factory + */ + public RegularExpressionFactory getRegularExpressionFactory() { + return regularExpressionFactory; + } + + /** + * Gets the schema id validator to validate $id. + * + * @return the validator + */ + public SchemaIdValidator getSchemaIdValidator() { + return schemaIdValidator; + } + + /** + * Gets if schemas loaded from refs will be cached and reused for subsequent + * runs. + * + * @return true if schemas loaded from refs should be cached + */ + public boolean isCacheRefs() { + return cacheRefs; + } + + public String getErrorMessageKeyword() { + return this.errorMessageKeyword; + } + + public boolean isFailFast() { + return this.failFast; + } + + public boolean isJavaSemantics() { + return this.javaSemantics; + } + + public boolean isLosslessNarrowing() { + return this.losslessNarrowing; + } + + /** + * Gets if the schema should be preloaded. + * + * @return true if it should be preloaded + */ + public boolean isPreloadSchema() { + return preloadSchema; + } + + /** + * Answers whether a keyword's validators may relax their analysis. The + * default is to perform strict checking. One must explicitly allow a + * validator to be more permissive. + *

+ * Each validator has its own understanding of what is permissive and + * strict. Consult the keyword's documentation for details. + * + * @param keyword the keyword to adjust (not null) + * @return Whether to perform a strict validation. + */ + public boolean isStrict(String keyword) { + return isStrict(keyword, Boolean.TRUE); + } + + /** + * Determines if the validator should perform strict checking. + * + * @param keyword the keyword + * @param defaultValue the default value + * @return whether to perform a strict validation + */ + public boolean isStrict(String keyword, Boolean defaultValue) { + return this.strictness.getOrDefault(Objects.requireNonNull(keyword, "keyword cannot be null"), defaultValue); + } + + /** + * Returns whether types are interpreted in a loose manner. + *

+ * If set to true, a single value can be interpreted as a size 1 array. Strings + * may also be interpreted as number, integer or boolean. + * + * @return true if type are interpreted in a loose manner + */ + public boolean isTypeLoose() { + return this.typeLoose; + } + + /** + * Creates a builder. + * + * @return the builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Copies values from a configuration to a new builder. + * + * @param config the configuration + * @return the builder + */ + public static Builder builder(SchemaRegistryConfig config) { + Builder builder = new Builder(); + builder.cacheRefs = config.cacheRefs; + builder.errorMessageKeyword = config.errorMessageKeyword; + builder.executionContextCustomizer = config.executionContextCustomizer; + builder.failFast = config.failFast; + builder.formatAssertionsEnabled = config.formatAssertionsEnabled; + builder.javaSemantics = config.javaSemantics; + builder.locale = config.locale; + builder.losslessNarrowing = config.losslessNarrowing; + builder.messageSource = config.messageSource; + builder.pathType = config.pathType; + builder.preloadSchema = config.preloadSchema; + builder.preloadSchemaRefMaxNestingDepth = config.preloadSchemaRefMaxNestingDepth; + builder.regularExpressionFactory = config.regularExpressionFactory; + builder.schemaIdValidator = config.schemaIdValidator; + builder.strictness = config.strictness; + builder.typeLoose = config.typeLoose; + return builder; + } + + /** + * Builder for {@link SchemaRegistryConfig}. + */ + public static class Builder extends BuilderSupport { + @Override + protected Builder self() { + return this; + } + } + + /** + * Builder for {@link SchemaRegistryConfig}. + */ + public static abstract class BuilderSupport { + protected boolean cacheRefs = true; + protected String errorMessageKeyword = null; + protected ExecutionContextCustomizer executionContextCustomizer = null; + protected boolean failFast = false; + protected Boolean formatAssertionsEnabled = null; + protected boolean javaSemantics = false; + protected Locale locale = null; // This must be null to use Locale.getDefault() as the default can be changed + protected boolean losslessNarrowing = false; + protected MessageSource messageSource = null; + protected PathType pathType = PathType.JSON_POINTER; + protected boolean preloadSchema = true; + protected int preloadSchemaRefMaxNestingDepth = DEFAULT_PRELOAD_SCHEMA_REF_MAX_NESTING_DEPTH; + protected RegularExpressionFactory regularExpressionFactory = JDKRegularExpressionFactory.getInstance(); + protected SchemaIdValidator schemaIdValidator = SchemaIdValidator.DEFAULT; + protected Map strictness = new HashMap<>(0); + protected boolean typeLoose = false; + + protected abstract T self(); + + /** + * Sets if schemas loaded from refs will be cached and reused for subsequent runs. + *

+ * Defaults to true. + * + * @param cacheRefs true to cache + * @return the builder + */ + public T cacheRefs(boolean cacheRefs) { + this.cacheRefs = cacheRefs; + return self(); + } + /** + * Sets the error message keyword for setting custom messages in the schema. + *

+ * Defaults to null meaning custom messages are not enabled. + * + * @param errorMessageKeyword to use for custom messages in the schema + * @return the builder + */ + public T errorMessageKeyword(String errorMessageKeyword) { + this.errorMessageKeyword = errorMessageKeyword; + return self(); + } + /** + * Sets the execution context customizer that is run before each run. + * + * @param executionContextCustomizer the customizer + * @return the builder + */ + public T executionContextCustomizer(ExecutionContextCustomizer executionContextCustomizer) { + this.executionContextCustomizer = executionContextCustomizer; + return self(); + } + + /** + * Sets if the validation should immediately return once a validation error has + * occurred. This can improve performance if inputs are invalid but cannot + * return all error messages to the caller. + *

+ * Defaults to false. + * + * @param failFast true to enable + * @return the builder + */ + public T failFast(boolean failFast) { + this.failFast = failFast; + return self(); + } + + /** + * Sets if format assertions are enabled. If format assertions are not enabled + * the format keyword will behave like an annotation and not attempt to validate + * if the inputs are valid. + *

+ * Defaults to not enabling format assertions for Draft 2019-09 and above and + * enabling format assertions for Draft 7 and below. + * + * @param formatAssertionsEnabled true to enable + * @return the builder + */ + public T formatAssertionsEnabled(Boolean formatAssertionsEnabled) { + this.formatAssertionsEnabled = formatAssertionsEnabled; + return self(); + } + + public T javaSemantics(boolean javaSemantics) { + this.javaSemantics = javaSemantics; + return self(); + } + + /** + * Set the locale to consider when generating localized messages. + *

+ * Note that this locale is set on a schema registry basis. To configure the + * schema on a per execution basis use + * {@link com.networknt.schema.ExecutionConfig.Builder#locale(Locale)}. + *

+ * Defaults to use {@link Locale#getDefault()}. + * + * @param locale The locale. + * @return the builder + */ + public T locale(Locale locale) { + this.locale = locale; + return self(); + } + + public T losslessNarrowing(boolean losslessNarrowing) { + this.losslessNarrowing = losslessNarrowing; + return self(); + } + /** + * Sets the message source to use for generating localised messages. + * + * @param messageSource the message source + * @return the builder + */ + public T messageSource(MessageSource messageSource) { + this.messageSource = messageSource; + return self(); + } + /** + * Sets the path type to use when reporting the instance location of errors. + *

+ * Defaults to {@link PathType#JSON_POINTER}. + * + * @param pathType the path type + * @return the path type + */ + public T pathType(PathType pathType) { + this.pathType = pathType; + return self(); + } + /** + * Sets if the schema should be preloaded. + *

+ * Defaults to true. + * + * @param preloadSchema true to preload + * @return the builder + */ + public T preloadSchema(boolean preloadSchema) { + this.preloadSchema = preloadSchema; + return self(); + } + /** + * Sets the max depth of the evaluation path to preload when preloading refs. + *

+ * Defaults to 40. + * + * @param preloadSchemaRefMaxNestingDepth to preload + * @return the builder + */ + public T preloadSchemaRefMaxNestingDepth(int preloadSchemaRefMaxNestingDepth) { + this.preloadSchemaRefMaxNestingDepth = preloadSchemaRefMaxNestingDepth; + return self(); + } + /** + * Sets the regular expression factory. + *

+ * Defaults to the {@link JDKRegularExpressionFactory} + *

+ * The {@link ECMAScriptRegularExpressionFactory} requires the inclusion of + * optional org.jruby.joni:joni or org.graalvm.js:js dependencies. + * + * @see JDKRegularExpressionFactory + * @see ECMAScriptRegularExpressionFactory + * @param regularExpressionFactory the factory + * @return the builder + */ + public T regularExpressionFactory(RegularExpressionFactory regularExpressionFactory) { + this.regularExpressionFactory = regularExpressionFactory; + return self(); + } + /** + * Sets the schema id validator to use. + *

+ * Defaults to {@link SchemaIdValidator#DEFAULT}. + * + * @param schemaIdValidator the builder + * @return the builder + */ + public T schemaIdValidator(SchemaIdValidator schemaIdValidator) { + this.schemaIdValidator = schemaIdValidator; + return self(); + } + public T strict(Map strict) { + this.strictness = strict; + return self(); + } + public T strict(String keyword, boolean strict) { + this.strictness.put(Objects.requireNonNull(keyword, "keyword cannot be null"), strict); + return self(); + } + public T typeLoose(boolean typeLoose) { + this.typeLoose = typeLoose; + return self(); + } + public SchemaRegistryConfig build() { + return new SchemaRegistryConfig(cacheRefs, errorMessageKeyword, + executionContextCustomizer, failFast, formatAssertionsEnabled, + javaSemantics, locale, losslessNarrowing, messageSource, + pathType, preloadSchema, preloadSchemaRefMaxNestingDepth, + regularExpressionFactory, schemaIdValidator, strictness, typeLoose + ); + } + + } +} diff --git a/src/main/java/com/networknt/schema/SchemaValidatorsConfig.java b/src/main/java/com/networknt/schema/SchemaValidatorsConfig.java deleted file mode 100644 index a08f7abed..000000000 --- a/src/main/java/com/networknt/schema/SchemaValidatorsConfig.java +++ /dev/null @@ -1,1410 +0,0 @@ -/* - * Copyright (c) 2016 Network New Technologies Inc. - * - * Licensed under the Apache LicenseBuilder Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.networknt.schema; - -import com.fasterxml.jackson.databind.JsonNode; -import com.networknt.schema.i18n.DefaultMessageSource; -import com.networknt.schema.i18n.MessageSource; -import com.networknt.schema.regex.ECMAScriptRegularExpressionFactory; -import com.networknt.schema.regex.JDKRegularExpressionFactory; -import com.networknt.schema.regex.RegularExpressionFactory; -import com.networknt.schema.walk.DefaultItemWalkListenerRunner; -import com.networknt.schema.walk.DefaultKeywordWalkListenerRunner; -import com.networknt.schema.walk.DefaultPropertyWalkListenerRunner; -import com.networknt.schema.walk.JsonSchemaWalkListener; -import com.networknt.schema.walk.WalkListenerRunner; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Objects; -import java.util.function.Consumer; - -/** - * Configuration for validators. - */ -public class SchemaValidatorsConfig { - // This is just a constant for listening to all Keywords. - public static final String ALL_KEYWORD_WALK_LISTENER_KEY = "com.networknt.AllKeywordWalkListener"; - - public static final int DEFAULT_PRELOAD_JSON_SCHEMA_REF_MAX_NESTING_DEPTH = 40; - - /** - * The strategy the walker uses to sets nodes that are missing or NullNode to - * the default value, if any, and mutate the input json. - */ - private ApplyDefaultsStrategy applyDefaultsStrategy = ApplyDefaultsStrategy.EMPTY_APPLY_DEFAULTS_STRATEGY; - - /** - * Controls if schemas loaded from refs will be cached and reused for subsequent runs. - */ - private boolean cacheRefs = true; - - /** - * When set to true, "messages" provided in schema are used for forming validation errors - * else default messages are used - */ - private String errorMessageKeyword = "message"; - - private ExecutionContextCustomizer executionContextCustomizer; - - /** - * When set to true, validator process is stop immediately when a very first - * validation error is discovered. - */ - private boolean failFast; - - /** - * Since Draft 2019-09 format assertions are not enabled by default. - */ - private Boolean formatAssertionsEnabled = null; - - /** - * When a field is set as nullable in the OpenAPI specification, the schema - * validator validates that it is nullable however continues with validation - * against the nullable field - *

- * If handleNullableField is set to true && incoming field is nullable && value - * is field: null --> succeed If handleNullableField is set to false && incoming - * field is nullable && value is field: null --> it is up to the type validator - * using the SchemaValidator to handle it. - */ - private boolean nullableKeywordEnabled = true; - - private final WalkListenerRunner itemWalkListenerRunner; - - private final List itemWalkListeners; - - /** - * When set to true, use Java-specific semantics rather than native JavaScript - * semantics - */ - private boolean javaSemantics; - - private final WalkListenerRunner keywordWalkListenerRunner; - - private final Map> keywordWalkListenersMap; - - /** - * The Locale to consider when loading validation messages from the default resource bundle. - */ - private Locale locale; - - /** - * When set to true, can interpret round doubles as integers - */ - private boolean losslessNarrowing; - - /** - * The message source to use for generating localised messages. - */ - private MessageSource messageSource; - - /** - * When set to true, support for discriminators is enabled for validations of - * oneOf, anyOf and allOf as described on GitHub. - */ - private boolean discriminatorKeywordEnabled = false; - - /** - * The approach used to generate paths in reported messages, logs and errors. Default is the legacy "JSONPath-like" approach. - */ - private PathType pathType = PathType.DEFAULT; - - /** - * Controls if the schema will automatically be preloaded. - */ - private boolean preloadJsonSchema = true; - - /** - * Controls the max depth of the evaluation path to preload when preloading refs. - */ - private int preloadJsonSchemaRefMaxNestingDepth = DEFAULT_PRELOAD_JSON_SCHEMA_REF_MAX_NESTING_DEPTH; - - private final WalkListenerRunner propertyWalkListenerRunner; - - private final List propertyWalkListeners; - - /** - * When set to true assumes that schema is used to validate incoming data from an API. - */ - private Boolean readOnly = null; - - /** - * Used to create {@link com.networknt.schema.regex.RegularExpression}. - */ - private RegularExpressionFactory regularExpressionFactory = JDKRegularExpressionFactory.getInstance(); - - /** - * Used to validate the acceptable $id values. - */ - private JsonSchemaIdValidator schemaIdValidator = JsonSchemaIdValidator.DEFAULT; - - /** - * Contains a mapping of how strict a keyword's validators should be. - * Defaults to {@literal true}. - *

- * Each validator has its own understanding of what constitutes strict - * and permissive. - */ - private final Map strictness; - - /** - * when validate type, if TYPE_LOOSE = true, will try to convert string to - * different types to match the type defined in schema. - */ - private boolean typeLoose; - - /** - * When set to true assumes that schema is used to validate outgoing data from an API. - */ - private Boolean writeOnly = null; - - /** - * Constructor to create an instance. - *

- * This is deprecated in favor of using the builder - * {@link SchemaValidatorsConfig#builder()} to create an instance. Migration - * note: The builder has different defaults from the constructor. - *

-     * SchemaValidatorsConfig config = SchemaValidatorsConfig.builder()
-     *     .pathType(PathType.LEGACY)
-     *     .errorMessageKeyword("message")
-     *     .nullableKeywordEnabled(true)
-     *     .build();
-     * 
- *
    - *
  • customMessageSupported (errorMessageKeyword): change from message to null - *
  • pathType: changed from PathType.LEGACY to PathType.JSON_POINTER. - *
  • handleNullableField (nullableKeywordEnabled): changed from true to false - *
- */ - @Deprecated - public SchemaValidatorsConfig() { - this.strictness = new HashMap<>(0); - - this.keywordWalkListenersMap = new HashMap<>(); - this.propertyWalkListeners = new ArrayList<>(); - this.itemWalkListeners = new ArrayList<>(); - - this.itemWalkListenerRunner = new DefaultItemWalkListenerRunner(getArrayItemWalkListeners()); - this.keywordWalkListenerRunner = new DefaultKeywordWalkListenerRunner(getKeywordWalkListenersMap()); - this.propertyWalkListenerRunner = new DefaultPropertyWalkListenerRunner(getPropertyWalkListeners()); - } - - SchemaValidatorsConfig(ApplyDefaultsStrategy applyDefaultsStrategy, boolean cacheRefs, - String errorMessageKeyword, ExecutionContextCustomizer executionContextCustomizer, boolean failFast, - Boolean formatAssertionsEnabled, boolean nullableKeywordEnabled, - List itemWalkListeners, boolean javaSemantics, - Map> keywordWalkListenersMap, Locale locale, boolean losslessNarrowing, - MessageSource messageSource, boolean discriminatorKeywordEnabled, PathType pathType, - boolean preloadJsonSchema, int preloadJsonSchemaRefMaxNestingDepth, - List propertyWalkListeners, Boolean readOnly, - RegularExpressionFactory regularExpressionFactory, JsonSchemaIdValidator schemaIdValidator, - Map strictness, boolean typeLoose, Boolean writeOnly) { - super(); - this.applyDefaultsStrategy = applyDefaultsStrategy; - this.cacheRefs = cacheRefs; - this.errorMessageKeyword = errorMessageKeyword; - this.executionContextCustomizer = executionContextCustomizer; - this.failFast = failFast; - this.formatAssertionsEnabled = formatAssertionsEnabled; - this.nullableKeywordEnabled = nullableKeywordEnabled; - this.itemWalkListeners = itemWalkListeners; - this.javaSemantics = javaSemantics; - this.keywordWalkListenersMap = keywordWalkListenersMap; - this.locale = locale; - this.losslessNarrowing = losslessNarrowing; - this.messageSource = messageSource; - this.discriminatorKeywordEnabled = discriminatorKeywordEnabled; - this.pathType = pathType; - this.preloadJsonSchema = preloadJsonSchema; - this.preloadJsonSchemaRefMaxNestingDepth = preloadJsonSchemaRefMaxNestingDepth; - this.propertyWalkListeners = propertyWalkListeners; - this.readOnly = readOnly; - this.regularExpressionFactory = regularExpressionFactory; - this.schemaIdValidator = schemaIdValidator; - this.strictness = strictness; - this.typeLoose = typeLoose; - this.writeOnly = writeOnly; - - this.itemWalkListenerRunner = new DefaultItemWalkListenerRunner(getArrayItemWalkListeners()); - this.keywordWalkListenerRunner = new DefaultKeywordWalkListenerRunner(getKeywordWalkListenersMap()); - this.propertyWalkListenerRunner = new DefaultPropertyWalkListenerRunner(getPropertyWalkListeners()); - } - - public void addItemWalkListener(JsonSchemaWalkListener itemWalkListener) { - this.itemWalkListeners.add(itemWalkListener); - } - - public void addItemWalkListeners(List itemWalkListeners) { - this.itemWalkListeners.addAll(itemWalkListeners); - } - - public void addKeywordWalkListener(JsonSchemaWalkListener keywordWalkListener) { - if (this.keywordWalkListenersMap.get(ALL_KEYWORD_WALK_LISTENER_KEY) == null) { - List keywordWalkListeners = new ArrayList<>(); - this.keywordWalkListenersMap.put(ALL_KEYWORD_WALK_LISTENER_KEY, keywordWalkListeners); - } - this.keywordWalkListenersMap.get(ALL_KEYWORD_WALK_LISTENER_KEY).add(keywordWalkListener); - } - - public void addKeywordWalkListener(String keyword, JsonSchemaWalkListener keywordWalkListener) { - if (this.keywordWalkListenersMap.get(keyword) == null) { - List keywordWalkListeners = new ArrayList<>(); - this.keywordWalkListenersMap.put(keyword, keywordWalkListeners); - } - this.keywordWalkListenersMap.get(keyword).add(keywordWalkListener); - } - - public void addKeywordWalkListeners(List keywordWalkListeners) { - if (this.keywordWalkListenersMap.get(ALL_KEYWORD_WALK_LISTENER_KEY) == null) { - List ikeywordWalkListeners = new ArrayList<>(); - this.keywordWalkListenersMap.put(ALL_KEYWORD_WALK_LISTENER_KEY, ikeywordWalkListeners); - } - this.keywordWalkListenersMap.get(ALL_KEYWORD_WALK_LISTENER_KEY).addAll(keywordWalkListeners); - } - - public void addKeywordWalkListeners(String keyword, List keywordWalkListeners) { - if (this.keywordWalkListenersMap.get(keyword) == null) { - List ikeywordWalkListeners = new ArrayList<>(); - this.keywordWalkListenersMap.put(keyword, ikeywordWalkListeners); - } - this.keywordWalkListenersMap.get(keyword).addAll(keywordWalkListeners); - } - - public void addPropertyWalkListener(JsonSchemaWalkListener propertyWalkListener) { - this.propertyWalkListeners.add(propertyWalkListener); - } - - public void addPropertyWalkListeners(List propertyWalkListeners) { - this.propertyWalkListeners.addAll(propertyWalkListeners); - } - - public ApplyDefaultsStrategy getApplyDefaultsStrategy() { - return this.applyDefaultsStrategy; - } - - public List getArrayItemWalkListeners() { - return this.itemWalkListeners; - } - - public ExecutionContextCustomizer getExecutionContextCustomizer() { - return this.executionContextCustomizer; - } - - /** - * Gets the format assertion enabled flag. - *

- * This defaults to null meaning that it will follow the defaults of the - * specification. - *

- * Since draft 2019-09 this will default to false unless enabled by using the - * $vocabulary keyword. - * - * @return the format assertions enabled flag - */ - public Boolean getFormatAssertionsEnabled() { - return formatAssertionsEnabled; - } - - WalkListenerRunner getItemWalkListenerRunner() { - return this.itemWalkListenerRunner; - } - - WalkListenerRunner getKeywordWalkListenerRunner() { - return this.keywordWalkListenerRunner; - } - - public Map> getKeywordWalkListenersMap() { - return this.keywordWalkListenersMap; - } - - /** - * Get the locale to consider when generating localised messages (default is the - * JVM default). - *

- * This locale is on a schema basis and will be used as the default locale for - * {@link com.networknt.schema.ExecutionConfig}. - * - * @return The locale. - */ - public Locale getLocale() { - if (this.locale == null) { - // This should not be cached as it can be changed using Locale#setDefault(Locale) - return Locale.getDefault(); - } - return this.locale; - } - - /** - * Get the message source to use for generating localised messages. - * - * @return the message source - */ - public MessageSource getMessageSource() { - if (this.messageSource == null) { - return DefaultMessageSource.getInstance(); - } - return this.messageSource; - } - - /** - * Get the approach used to generate paths in messages, logs and errors. - * - * @return The path generation approach. - */ - public PathType getPathType() { - return this.pathType; - } - - /** - * Gets the max depth of the evaluation path to preload when preloading refs. - * - * @return the max depth to preload - */ - public int getPreloadJsonSchemaRefMaxNestingDepth() { - return preloadJsonSchemaRefMaxNestingDepth; - } - - WalkListenerRunner getPropertyWalkListenerRunner() { - return this.propertyWalkListenerRunner; - } - - public List getPropertyWalkListeners() { - return this.propertyWalkListeners; - } - - /** - * Gets the regular expression factory. - *

- * This defaults to the JDKRegularExpressionFactory and the implementations - * require inclusion of optional org.jruby.joni:joni or org.graalvm.js:js dependencies. - * - * @return the factory - */ - public RegularExpressionFactory getRegularExpressionFactory() { - return regularExpressionFactory; - } - - /** - * Gets the schema id validator to validate $id. - * - * @return the validator - */ - public JsonSchemaIdValidator getSchemaIdValidator() { - return schemaIdValidator; - } - - /** - * Gets if schemas loaded from refs will be cached and reused for subsequent - * runs. - * - * @return true if schemas loaded from refs should be cached - */ - public boolean isCacheRefs() { - return cacheRefs; - } - - @Deprecated - public boolean isCustomMessageSupported() { - return this.errorMessageKeyword != null; - } - - public String getErrorMessageKeyword() { - return this.errorMessageKeyword; - } - - /** - * Gets whether to use a ECMA-262 compliant regular expression validator. - *

- * This defaults to the false and setting true require inclusion of optional - * org.jruby.joni:joni or org.graalvm.js:js dependencies. - * - * @return true if ECMA-262 compliant - */ - public boolean isEcma262Validator() { - return !(this.regularExpressionFactory instanceof JDKRegularExpressionFactory); - } - - public boolean isFailFast() { - return this.failFast; - } - - /** - * Deprecated use {{@link #isNullableKeywordEnabled()} instead. - * - * @return true if the nullable keyword is enabled - */ - @Deprecated - public boolean isHandleNullableField() { - return isNullableKeywordEnabled(); - } - - /** - * Gets if the nullable keyword is enabled. - * - * @return true if the nullable keyword is enabled - */ - public boolean isNullableKeywordEnabled() { - return this.nullableKeywordEnabled; - } - - public boolean isJavaSemantics() { - return this.javaSemantics; - } - - public boolean isLosslessNarrowing() { - return this.losslessNarrowing; - } - - /** - * Indicates whether OpenAPI 3 style discriminators should be supported - *

- * Deprecated use {{@link #isDiscriminatorKeywordEnabled()} instead. - * - * @return true in case discriminators are enabled - * @since 1.0.51 - */ - @Deprecated - public boolean isOpenAPI3StyleDiscriminators() { - return isDiscriminatorKeywordEnabled(); - } - - /** - * Gets if the discriminator keyword is enabled. - * - * @return true if the discriminator keyword is enabled - */ - public boolean isDiscriminatorKeywordEnabled() { - return this.discriminatorKeywordEnabled; - } - - /** - * Gets if the schema should be preloaded. - * - * @return true if it should be preloaded - */ - public boolean isPreloadJsonSchema() { - return preloadJsonSchema; - } - - public boolean isReadOnly() { - return null != this.readOnly && this.readOnly; - } - - Boolean getReadOnly() { - return this.readOnly; - } - - /** - * Answers whether a keyword's validators may relax their analysis. The - * default is to perform strict checking. One must explicitly allow a - * validator to be more permissive. - *

- * Each validator has its own understanding of what is permissive and - * strict. Consult the keyword's documentation for details. - * - * @param keyword the keyword to adjust (not null) - * @return Whether to perform a strict validation. - */ - public boolean isStrict(String keyword) { - return isStrict(keyword, Boolean.TRUE); - } - - /** - * Determines if the validator should perform strict checking. - * - * @param keyword the keyword - * @param defaultValue the default value - * @return whether to perform a strict validation - */ - public boolean isStrict(String keyword, Boolean defaultValue) { - return this.strictness.getOrDefault(Objects.requireNonNull(keyword, "keyword cannot be null"), defaultValue); - } - - /** - * - * @return true if type loose is used. - */ - public boolean isTypeLoose() { - return this.typeLoose; - } - - public boolean isWriteOnly() { - return null != this.writeOnly && this.writeOnly; - } - - Boolean getWriteOnly() { - return this.writeOnly; - } - - public void setApplyDefaultsStrategy(ApplyDefaultsStrategy applyDefaultsStrategy) { - this.applyDefaultsStrategy = applyDefaultsStrategy != null ? applyDefaultsStrategy - : ApplyDefaultsStrategy.EMPTY_APPLY_DEFAULTS_STRATEGY; - } - - /** - * Sets if schemas loaded from refs will be cached and reused for subsequent - * runs. - *

- * Note that setting this to false will affect performance as refs will need to - * be repeatedly resolved for each evaluation run. It may be needed to be set to - * false if there are multiple nested applicators like anyOf, oneOf and allOf as - * that will consume a lot of memory to cache all the permutations. - * - * @param cacheRefs true to cache - */ - public void setCacheRefs(boolean cacheRefs) { - this.cacheRefs = cacheRefs; - } - - /** - * Sets whether custom error messages in the schema are used. - *

- * This is deprecated in favor of setting the error message keyword to use. - * - * @param customMessageSupported true to use message as the error message keyword - */ - @Deprecated - public void setCustomMessageSupported(boolean customMessageSupported) { - this.errorMessageKeyword = customMessageSupported ? "message" : null; - } - - /** - * Sets whether to use a ECMA-262 compliant regular expression validator. - *

- * This defaults to the false and setting true require inclusion of optional - * org.jruby.joni:joni or org.graalvm.js:js dependencies. - * - * @param ecma262Validator true if ECMA-262 compliant - */ - public void setEcma262Validator(boolean ecma262Validator) { - this.regularExpressionFactory = ecma262Validator ? ECMAScriptRegularExpressionFactory.getInstance() - : JDKRegularExpressionFactory.getInstance(); - } - - public void setExecutionContextCustomizer(ExecutionContextCustomizer executionContextCustomizer) { - this.executionContextCustomizer = executionContextCustomizer; - } - - /** - * When enabled, - * {@link JsonValidator#validate(ExecutionContext, JsonNode, JsonNode, JsonNodePath)} - * doesn't return any {@link java.util.Set}<{@link ValidationMessage}>, - * instead a {@link JsonSchemaException} is thrown as soon as a validation - * errors is discovered. - * - * @param failFast boolean - */ - public void setFailFast(final boolean failFast) { - this.failFast = failFast; - } - - /** - * Sets the format assertion enabled flag. - *

- * This is deprecated. Either set this using the builder - * SchemaValidatorsConfig.builder().formatAssertionsEnabled(true).build() or - * this should be set via - * executionContext.getExecutionConfig().setFormatAssertionsEnabled(true). - * - * @param formatAssertionsEnabled the format assertions enabled flag - */ - @Deprecated - public void setFormatAssertionsEnabled(Boolean formatAssertionsEnabled) { - this.formatAssertionsEnabled = formatAssertionsEnabled; - } - - public void setHandleNullableField(boolean handleNullableField) { - this.nullableKeywordEnabled = handleNullableField; - } - - public void setJavaSemantics(boolean javaSemantics) { - this.javaSemantics = javaSemantics; - } - - /** - * Set the locale to consider when generating localised messages. - *

- * Note that this locale is set on a schema basis. To configure the schema on a - * per execution basis use - * {@link com.networknt.schema.ExecutionConfig#setLocale(Locale)}. - *

- * This is deprecated. Either set this using the builder - * SchemaValidatorsConfig.builder().locale(locale).build() or this should be set - * via executionContext.getExecutionConfig().setLocale(locale). - * - * @param locale The locale. - */ - @Deprecated - public void setLocale(Locale locale) { - this.locale = locale; - } - - public void setLosslessNarrowing(boolean losslessNarrowing) { - this.losslessNarrowing = losslessNarrowing; - } - - /** - * Set the message source to use for generating localised messages. - * - * @param messageSource the message source - */ - public void setMessageSource(MessageSource messageSource) { - this.messageSource = messageSource; - } - - /** - * When enabled, the validation of anyOf and allOf in - * polymorphism will respect OpenAPI 3 style discriminators as described in the - * OpenAPI - * 3.0.3 spec. The presence of a discriminator configuration on the schema - * will lead to the following changes in the behavior: - *

    - *
  • for oneOf the spec is unfortunately very vague. Whether - * oneOf semantics should be affected by discriminators or not is - * not even 100% clear within the members of the OAS steering committee. - * Therefore oneOf at the moment ignores discriminators
  • - *
  • for anyOf the validation will choose one of the candidate - * schemas for validation based on the discriminator property value and will - * pass validation when this specific schema passes. This is in particular - * useful when the payload could match multiple candidates in the - * anyOf list and could lead to ambiguity. Example: type B has all - * mandatory properties of A and adds more mandatory ones. Whether the payload - * is an A or B is determined via the discriminator property name. A payload - * indicating it is an instance of B then requires passing the validation of B - * and passing the validation of A would not be sufficient anymore.
  • - *
  • for allOf use cases with discriminators defined on the - * copied-in parent type, it is possible to automatically validate against a - * subtype. Example: some schema specifies that there is a field of type A. A - * carries a discriminator field and B inherits from A. Then B is automatically - * a candidate for validation as well and will be chosen in case the - * discriminator property matches
  • - *
- * - * @param openAPI3StyleDiscriminators whether discriminators should be used. - * Defaults to false - * @since 1.0.51 - */ - public void setOpenAPI3StyleDiscriminators(boolean openAPI3StyleDiscriminators) { - this.discriminatorKeywordEnabled = openAPI3StyleDiscriminators; - } - - /** - * Set the approach used to generate paths in messages, logs and errors (default is PathType.LEGACY). - * - * @param pathType The path generation approach. - */ - public void setPathType(PathType pathType) { - this.pathType = pathType; - } - - /** - * Sets if the schema should be preloaded. - * - * @param preloadJsonSchema true to preload - */ - public void setPreloadJsonSchema(boolean preloadJsonSchema) { - this.preloadJsonSchema = preloadJsonSchema; - } - - /** - * Sets the max depth of the evaluation path to preload when preloading refs. - * - * @param preloadJsonSchemaRefMaxNestingDepth the max depth to preload - */ - public void setPreloadJsonSchemaRefMaxNestingDepth(int preloadJsonSchemaRefMaxNestingDepth) { - this.preloadJsonSchemaRefMaxNestingDepth = preloadJsonSchemaRefMaxNestingDepth; - } - - public void setReadOnly(boolean readOnly) { - this.readOnly = readOnly; - } - - /** - * Sets the regular expression factory. - *

- * This defaults to the JDKRegularExpressionFactory and the implementations - * require inclusion of optional org.jruby.joni:joni or org.graalvm.js:js dependencies. - * - * @see JDKRegularExpressionFactory - * @see ECMAScriptRegularExpressionFactory - * @param regularExpressionFactory the factory - */ - public void setRegularExpressionFactory(RegularExpressionFactory regularExpressionFactory) { - this.regularExpressionFactory = regularExpressionFactory; - } - - /** - * Sets the schema id validator to validate $id. - * - * @param schemaIdValidator the validator - */ - public void setSchemaIdValidator(JsonSchemaIdValidator schemaIdValidator) { - this.schemaIdValidator = schemaIdValidator; - } - - /** - * Alters the strictness of validations for a specific keyword. When set to - * {@literal true}, instructs the keyword's validators to perform strict - * validation. Otherwise, a validator may perform a more permissive check. - * - * @param keyword The keyword to adjust (not null) - * @param strict Whether to perform strict validations - */ - public void setStrict(String keyword, boolean strict) { - this.strictness.put(Objects.requireNonNull(keyword, "keyword cannot be null"), strict); - } - - public void setTypeLoose(boolean typeLoose) { - this.typeLoose = typeLoose; - } - - public void setWriteOnly(boolean writeOnly) { - this.writeOnly = writeOnly; - } - - public static Builder builder() { - return new Builder(); - } - - public static Builder builder(SchemaValidatorsConfig config) { - Builder builder = new Builder(); - builder.applyDefaultsStrategy = config.applyDefaultsStrategy; - builder.cacheRefs = config.cacheRefs; - builder.errorMessageKeyword = config.errorMessageKeyword; - builder.executionContextCustomizer = config.executionContextCustomizer; - builder.failFast = config.failFast; - builder.formatAssertionsEnabled = config.formatAssertionsEnabled; - builder.nullableKeywordEnabled = config.nullableKeywordEnabled; - builder.itemWalkListeners = config.itemWalkListeners; - builder.javaSemantics = config.javaSemantics; - builder.keywordWalkListeners = config.keywordWalkListenersMap; - builder.locale = config.locale; - builder.losslessNarrowing = config.losslessNarrowing; - builder.messageSource = config.messageSource; - builder.discriminatorKeywordEnabled = config.discriminatorKeywordEnabled; - builder.pathType = config.pathType; - builder.preloadJsonSchema = config.preloadJsonSchema; - builder.preloadJsonSchemaRefMaxNestingDepth = config.preloadJsonSchemaRefMaxNestingDepth; - builder.propertyWalkListeners = config.propertyWalkListeners; - builder.readOnly = config.readOnly; - builder.regularExpressionFactory = config.regularExpressionFactory; - builder.schemaIdValidator = config.schemaIdValidator; - builder.strictness = config.strictness; - builder.typeLoose = config.typeLoose; - builder.writeOnly = config.writeOnly; - return builder; - } - - /** - * Builder for {@link SchemaValidatorsConfig}. - */ - public static class Builder { - private ApplyDefaultsStrategy applyDefaultsStrategy = ApplyDefaultsStrategy.EMPTY_APPLY_DEFAULTS_STRATEGY; - private boolean cacheRefs = true; - private String errorMessageKeyword = null; - private ExecutionContextCustomizer executionContextCustomizer = null; - private boolean failFast = false; - private Boolean formatAssertionsEnabled = null; - private boolean nullableKeywordEnabled = false; - private List itemWalkListeners = new ArrayList<>(); - private boolean javaSemantics = false; - private Map> keywordWalkListeners = new HashMap<>(); - private Locale locale = null; // This must be null to use Locale.getDefault() as the default can be changed - private boolean losslessNarrowing = false; - private MessageSource messageSource = null; - private boolean discriminatorKeywordEnabled = false; - private PathType pathType = PathType.JSON_POINTER; - private boolean preloadJsonSchema = true; - private int preloadJsonSchemaRefMaxNestingDepth = DEFAULT_PRELOAD_JSON_SCHEMA_REF_MAX_NESTING_DEPTH; - private List propertyWalkListeners = new ArrayList<>(); - private Boolean readOnly = null; - private RegularExpressionFactory regularExpressionFactory = JDKRegularExpressionFactory.getInstance(); - private JsonSchemaIdValidator schemaIdValidator = JsonSchemaIdValidator.DEFAULT; - private Map strictness = new HashMap<>(0); - private boolean typeLoose = false; - private Boolean writeOnly = null; - - /** - * Sets the strategy the walker uses to sets nodes to the default value. - *

- * Defaults to {@link ApplyDefaultsStrategy#EMPTY_APPLY_DEFAULTS_STRATEGY}. - * - * @param applyDefaultsStrategy the strategy - * @return the builder - */ - public Builder applyDefaultsStrategy(ApplyDefaultsStrategy applyDefaultsStrategy) { - this.applyDefaultsStrategy = applyDefaultsStrategy != null ? applyDefaultsStrategy - : ApplyDefaultsStrategy.EMPTY_APPLY_DEFAULTS_STRATEGY; - return this; - } - /** - * Sets if schemas loaded from refs will be cached and reused for subsequent runs. - *

- * Defaults to true. - * - * @param cacheRefs true to cache - * @return the builder - */ - public Builder cacheRefs(boolean cacheRefs) { - this.cacheRefs = cacheRefs; - return this; - } - /** - * Sets the error message keyword for setting custom messages in the schema. - *

- * Defaults to null meaning custom messages are not enabled. - * - * @param errorMessageKeyword to use for custom messages in the schema - * @return the builder - */ - public Builder errorMessageKeyword(String errorMessageKeyword) { - this.errorMessageKeyword = errorMessageKeyword; - return this; - } - /** - * Sets the execution context customizer that is run before each run. - * - * @param executionContextCustomizer the customizer - * @return the builder - */ - public Builder executionContextCustomizer(ExecutionContextCustomizer executionContextCustomizer) { - this.executionContextCustomizer = executionContextCustomizer; - return this; - } - - /** - * Sets if the validation should immediately return once a validation error has - * occurred. This can improve performance if inputs are invalid but cannot - * return all error messages to the caller. - *

- * Defaults to false. - * - * @param failFast true to enable - * @return the builder - */ - public Builder failFast(boolean failFast) { - this.failFast = failFast; - return this; - } - - /** - * Sets if format assertions are enabled. If format assertions are not enabled - * the format keyword will behave like an annotation and not attempt to validate - * if the inputs are valid. - *

- * Defaults to not enabling format assertions for Draft 2019-09 and above and - * enabling format assertions for Draft 7 and below. - * - * @param formatAssertionsEnabled true to enable - * @return the builder - */ - public Builder formatAssertionsEnabled(Boolean formatAssertionsEnabled) { - this.formatAssertionsEnabled = formatAssertionsEnabled; - return this; - } - - /** - * Sets if the nullable keyword is enabled. - * - * @param nullableKeywordEnabled true to enable - * @return the builder - */ - public Builder nullableKeywordEnabled(boolean nullableKeywordEnabled) { - this.nullableKeywordEnabled = nullableKeywordEnabled; - return this; - } - public Builder itemWalkListeners(List itemWalkListeners) { - this.itemWalkListeners = itemWalkListeners; - return this; - } - public Builder javaSemantics(boolean javaSemantics) { - this.javaSemantics = javaSemantics; - return this; - } - public Builder keywordWalkListeners(Map> keywordWalkListeners) { - this.keywordWalkListeners = keywordWalkListeners; - return this; - } - /** - * Set the locale to consider when generating localised messages. - *

- * Note that this locale is set on a schema basis. To configure the schema on a - * per execution basis use - * {@link com.networknt.schema.ExecutionConfig#setLocale(Locale)}. - *

- * Defaults to use {@link Locale#getDefault()}. - * - * @param locale The locale. - * @return the builder - */ - public Builder locale(Locale locale) { - this.locale = locale; - return this; - } - public Builder losslessNarrowing(boolean losslessNarrowing) { - this.losslessNarrowing = losslessNarrowing; - return this; - } - /** - * Sets the message source to use for generating localised messages. - * - * @param messageSource the message source - * @return the builder - */ - public Builder messageSource(MessageSource messageSource) { - this.messageSource = messageSource; - return this; - } - /** - * Sets if the discriminator keyword is enabled. - *

- * Defaults to false. - * - * @param discriminatorKeywordEnabled true to enable - * @return the builder - */ - public Builder discriminatorKeywordEnabled(boolean discriminatorKeywordEnabled) { - this.discriminatorKeywordEnabled = discriminatorKeywordEnabled; - return this; - } - /** - * Sets the path type to use when reporting the instance location of errors. - *

- * Defaults to {@link PathType#JSON_POINTER}. - * - * @param pathType the path type - * @return the path type - */ - public Builder pathType(PathType pathType) { - this.pathType = pathType; - return this; - } - /** - * Sets if the schema should be preloaded. - *

- * Defaults to true. - * - * @param preloadJsonSchema true to preload - * @return the builder - */ - public Builder preloadJsonSchema(boolean preloadJsonSchema) { - this.preloadJsonSchema = preloadJsonSchema; - return this; - } - /** - * Sets the max depth of the evaluation path to preload when preloading refs. - *

- * Defaults to 40. - * - * @param preloadJsonSchemaRefMaxNestingDepth to preload - * @return the builder - */ - public Builder preloadJsonSchemaRefMaxNestingDepth(int preloadJsonSchemaRefMaxNestingDepth) { - this.preloadJsonSchemaRefMaxNestingDepth = preloadJsonSchemaRefMaxNestingDepth; - return this; - } - public Builder propertyWalkListeners(List propertyWalkListeners) { - this.propertyWalkListeners = propertyWalkListeners; - return this; - } - public Builder readOnly(Boolean readOnly) { - this.readOnly = readOnly; - return this; - } - /** - * Sets the regular expression factory. - *

- * Defaults to the {@link JDKRegularExpressionFactory} - *

- * The {@link ECMAScriptRegularExpressionFactory} requires the inclusion of - * optional org.jruby.joni:joni or org.graalvm.js:js dependencies. - * - * @see JDKRegularExpressionFactory - * @see ECMAScriptRegularExpressionFactory - * @param regularExpressionFactory the factory - * @return the builder - */ - public Builder regularExpressionFactory(RegularExpressionFactory regularExpressionFactory) { - this.regularExpressionFactory = regularExpressionFactory; - return this; - } - /** - * Sets the schema id validator to use. - *

- * Defaults to {@link JsonSchemaIdValidator#DEFAULT}. - * - * @param schemaIdValidator the builder - * @return the builder - */ - public Builder schemaIdValidator(JsonSchemaIdValidator schemaIdValidator) { - this.schemaIdValidator = schemaIdValidator; - return this; - } - public Builder strict(Map strict) { - this.strictness = strict; - return this; - } - public Builder typeLoose(boolean typeLoose) { - this.typeLoose = typeLoose; - return this; - } - public Builder writeOnly(Boolean writeOnly) { - this.writeOnly = writeOnly; - return this; - } - public SchemaValidatorsConfig build() { - return new ImmutableSchemaValidatorsConfig(applyDefaultsStrategy, cacheRefs, errorMessageKeyword, - executionContextCustomizer, failFast, formatAssertionsEnabled, nullableKeywordEnabled, - itemWalkListeners, javaSemantics, keywordWalkListeners, locale, losslessNarrowing, messageSource, - discriminatorKeywordEnabled, pathType, preloadJsonSchema, preloadJsonSchemaRefMaxNestingDepth, - propertyWalkListeners, readOnly, regularExpressionFactory, schemaIdValidator, strictness, typeLoose, - writeOnly); - } - public Builder strict(String keyword, boolean strict) { - this.strictness.put(Objects.requireNonNull(keyword, "keyword cannot be null"), strict); - return this; - } - public Builder keywordWalkListener(String keyword, JsonSchemaWalkListener keywordWalkListener) { - this.keywordWalkListeners.computeIfAbsent(keyword, key -> new ArrayList<>()).add(keywordWalkListener); - return this; - } - public Builder keywordWalkListener(JsonSchemaWalkListener keywordWalkListener) { - return keywordWalkListener(ALL_KEYWORD_WALK_LISTENER_KEY, keywordWalkListener); - } - public Builder keywordWalkListeners(Consumer>> keywordWalkListeners) { - keywordWalkListeners.accept(this.keywordWalkListeners); - return this; - } - public Builder propertyWalkListener(JsonSchemaWalkListener propertyWalkListener) { - this.propertyWalkListeners.add(propertyWalkListener); - return this; - } - public Builder propertyWalkListeners(Consumer> propertyWalkListeners) { - propertyWalkListeners.accept(this.propertyWalkListeners); - return this; - } - public Builder itemWalkListener(JsonSchemaWalkListener itemWalkListener) { - this.itemWalkListeners.add(itemWalkListener); - return this; - } - public Builder itemWalkListeners(Consumer> itemWalkListeners) { - itemWalkListeners.accept(this.itemWalkListeners); - return this; - } - } - - /** - * {@link SchemaValidatorsConfig} that throws on mutators or deprecated methods. - *

- * The {@link SchemaValidatorsConfig} will be made immutable in a future breaking release. - */ - public static class ImmutableSchemaValidatorsConfig extends SchemaValidatorsConfig { - public ImmutableSchemaValidatorsConfig(ApplyDefaultsStrategy applyDefaultsStrategy, boolean cacheRefs, - String errorMessageKeyword, ExecutionContextCustomizer executionContextCustomizer, boolean failFast, - Boolean formatAssertionsEnabled, boolean handleNullableField, - List itemWalkListeners, boolean javaSemantics, - Map> keywordWalkListenersMap, Locale locale, - boolean losslessNarrowing, MessageSource messageSource, boolean openAPI3StyleDiscriminators, - PathType pathType, boolean preloadJsonSchema, int preloadJsonSchemaRefMaxNestingDepth, - List propertyWalkListeners, Boolean readOnly, - RegularExpressionFactory regularExpressionFactory, JsonSchemaIdValidator schemaIdValidator, - Map strictness, boolean typeLoose, Boolean writeOnly) { - super(applyDefaultsStrategy, cacheRefs, errorMessageKeyword, executionContextCustomizer, failFast, - formatAssertionsEnabled, handleNullableField, itemWalkListeners, javaSemantics, keywordWalkListenersMap, locale, - losslessNarrowing, messageSource, openAPI3StyleDiscriminators, pathType, preloadJsonSchema, - preloadJsonSchemaRefMaxNestingDepth, propertyWalkListeners, readOnly, regularExpressionFactory, - schemaIdValidator, strictness, typeLoose, writeOnly); - } - - @Override - public void addItemWalkListener(JsonSchemaWalkListener itemWalkListener) { - throw new UnsupportedOperationException(); - } - - @Override - public void addItemWalkListeners(List itemWalkListeners) { - throw new UnsupportedOperationException(); - } - - @Override - public void addKeywordWalkListener(JsonSchemaWalkListener keywordWalkListener) { - throw new UnsupportedOperationException(); - } - - @Override - public void addKeywordWalkListener(String keyword, JsonSchemaWalkListener keywordWalkListener) { - throw new UnsupportedOperationException(); - } - - @Override - public void addKeywordWalkListeners(List keywordWalkListeners) { - throw new UnsupportedOperationException(); - } - - @Override - public void addKeywordWalkListeners(String keyword, List keywordWalkListeners) { - throw new UnsupportedOperationException(); - } - - @Override - public void addPropertyWalkListener(JsonSchemaWalkListener propertyWalkListener) { - throw new UnsupportedOperationException(); - } - - @Override - public void addPropertyWalkListeners(List propertyWalkListeners) { - throw new UnsupportedOperationException(); - } - - @Override - public void setApplyDefaultsStrategy(ApplyDefaultsStrategy applyDefaultsStrategy) { - throw new UnsupportedOperationException(); - } - - @Override - public void setCacheRefs(boolean cacheRefs) { - throw new UnsupportedOperationException(); - } - - @Override - public void setCustomMessageSupported(boolean customMessageSupported) { - throw new UnsupportedOperationException(); - } - - @Override - public void setEcma262Validator(boolean ecma262Validator) { - throw new UnsupportedOperationException(); - } - - @Override - public void setExecutionContextCustomizer(ExecutionContextCustomizer executionContextCustomizer) { - throw new UnsupportedOperationException(); - } - - @Override - public void setFailFast(boolean failFast) { - throw new UnsupportedOperationException(); - } - - @Override - public void setFormatAssertionsEnabled(Boolean formatAssertionsEnabled) { - throw new UnsupportedOperationException(); - } - - @Override - public void setHandleNullableField(boolean handleNullableField) { - throw new UnsupportedOperationException(); - } - - @Override - public void setJavaSemantics(boolean javaSemantics) { - throw new UnsupportedOperationException(); - } - - @Override - public void setLocale(Locale locale) { - throw new UnsupportedOperationException(); - } - - @Override - public void setLosslessNarrowing(boolean losslessNarrowing) { - throw new UnsupportedOperationException(); - } - - @Override - public void setMessageSource(MessageSource messageSource) { - throw new UnsupportedOperationException(); - } - - @Override - public void setOpenAPI3StyleDiscriminators(boolean openAPI3StyleDiscriminators) { - throw new UnsupportedOperationException(); - } - - @Override - public void setPathType(PathType pathType) { - throw new UnsupportedOperationException(); - } - - @Override - public void setPreloadJsonSchema(boolean preloadJsonSchema) { - throw new UnsupportedOperationException(); - } - - @Override - public void setPreloadJsonSchemaRefMaxNestingDepth(int preloadJsonSchemaRefMaxNestingDepth) { - throw new UnsupportedOperationException(); - } - - @Override - public void setReadOnly(boolean readOnly) { - throw new UnsupportedOperationException(); - } - - @Override - public void setRegularExpressionFactory(RegularExpressionFactory regularExpressionFactory) { - throw new UnsupportedOperationException(); - } - - @Override - public void setSchemaIdValidator(JsonSchemaIdValidator schemaIdValidator) { - throw new UnsupportedOperationException(); - } - - @Override - public void setStrict(String keyword, boolean strict) { - throw new UnsupportedOperationException(); - } - - @Override - public void setTypeLoose(boolean typeLoose) { - throw new UnsupportedOperationException(); - } - - @Override - public void setWriteOnly(boolean writeOnly) { - throw new UnsupportedOperationException(); - } - - @Override - public void setLoadCollectors(boolean loadCollectors) { - throw new UnsupportedOperationException(); - } - - @Override - public SchemaValidatorsConfig disableUnevaluatedAnalysis() { - throw new UnsupportedOperationException(); - } - - @Override - public SchemaValidatorsConfig disableUnevaluatedItems() { - throw new UnsupportedOperationException(); - } - - @Override - public SchemaValidatorsConfig disableUnevaluatedProperties() { - throw new UnsupportedOperationException(); - } - - @Override - public SchemaValidatorsConfig enableUnevaluatedAnalysis() { - throw new UnsupportedOperationException(); - } - - @Override - public SchemaValidatorsConfig enableUnevaluatedItems() { - throw new UnsupportedOperationException(); - } - - @Override - public SchemaValidatorsConfig enableUnevaluatedProperties() { - throw new UnsupportedOperationException(); - } - } - - /* Below are deprecated for removal */ - @Deprecated - private boolean loadCollectors = true; - - /** - * Use {@code isReadOnly} or {@code isWriteOnly} - * @return true if schema is used to write data - */ - @Deprecated - public boolean isWriteMode() { - return null == this.writeOnly || this.writeOnly; - } - - /** - * Sets if collectors are to be loaded. - *

- * This is deprecated in favor of the caller calling {@link CollectorContext#loadCollectors()} manually. - * - * @param loadCollectors to load collectors - */ - @Deprecated - public void setLoadCollectors(boolean loadCollectors) { - this.loadCollectors = loadCollectors; - } - - /** - * Gets if collectors are to be loaded. - * - * @return if collectors are to be loader - */ - @Deprecated - public boolean doLoadCollectors() { - return this.loadCollectors; - } - - @Deprecated - public SchemaValidatorsConfig disableUnevaluatedAnalysis() { - return this; - } - - @Deprecated - public SchemaValidatorsConfig disableUnevaluatedItems() { - return this; - } - - @Deprecated - public SchemaValidatorsConfig disableUnevaluatedProperties() { - return this; - } - - @Deprecated - public SchemaValidatorsConfig enableUnevaluatedAnalysis() { - return this; - } - - @Deprecated - public SchemaValidatorsConfig enableUnevaluatedItems() { - return this; - } - - @Deprecated - public SchemaValidatorsConfig enableUnevaluatedProperties() { - return this; - } - - @Deprecated - public boolean isUnevaluatedItemsAnalysisDisabled() { - return false; - } - - @Deprecated - public boolean isUnevaluatedItemsAnalysisEnabled() { - return !isUnevaluatedItemsAnalysisDisabled(); - } - - @Deprecated - public boolean isUnevaluatedPropertiesAnalysisDisabled() { - return false; - } - - @Deprecated - public boolean isUnevaluatedPropertiesAnalysisEnabled() { - return !isUnevaluatedPropertiesAnalysisDisabled(); - } -} diff --git a/src/main/java/com/networknt/schema/SpecVersion.java b/src/main/java/com/networknt/schema/SpecVersion.java deleted file mode 100644 index 3f02cd91a..000000000 --- a/src/main/java/com/networknt/schema/SpecVersion.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2020 Network New Technologies Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.networknt.schema; - -import java.util.Optional; - -public class SpecVersion { - - public enum VersionFlag { - - V4(1 << 0, SchemaId.V4), - V6(1 << 1, SchemaId.V6), - V7(1 << 2, SchemaId.V7), - V201909(1 << 3, SchemaId.V201909), - V202012(1 << 4, SchemaId.V202012); - - - private final long versionFlagValue; - private final String id; - - VersionFlag(long versionFlagValue, String id) { - this.versionFlagValue = versionFlagValue; - this.id = id; - } - - public String getId() { - return this.id; - } - - public long getVersionFlagValue() { - return this.versionFlagValue; - } - - public static Optional fromId(String id) { - for (VersionFlag v: VersionFlag.values()) { - if (v.id.equals(id)) return Optional.of(v); - } - return Optional.empty(); - } - } - -} diff --git a/src/main/java/com/networknt/schema/Specification.java b/src/main/java/com/networknt/schema/Specification.java new file mode 100644 index 000000000..67cd6a61d --- /dev/null +++ b/src/main/java/com/networknt/schema/Specification.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2020 Network New Technologies Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.networknt.schema; + +import com.networknt.schema.dialect.Dialect; +import com.networknt.schema.dialect.DialectId; +import com.networknt.schema.dialect.Dialects; + +/** + * The version of the JSON Schema specification that defines the standard + * dialects. + */ +public class Specification { + + /** + * Gets the standard dialect given the specification version. + *

+ * This should only be used if the standard dialect is required, otherwise the + * dialect should be retrieved from the dialect registry. + * + * @param version the schema specification version + * @return the dialect or null if not found + */ + public static Dialect getDialect(SpecificationVersion version) { + if (null == version) { + return null; + } + switch (version) { + case DRAFT_2020_12: + return Dialects.getDraft202012(); + case DRAFT_2019_09: + return Dialects.getDraft201909(); + case DRAFT_7: + return Dialects.getDraft7(); + case DRAFT_6: + return Dialects.getDraft6(); + case DRAFT_4: + return Dialects.getDraft4(); + default: + return null; + } + } + + /** + * Gets the standard dialect given the dialect id. + *

+ * This should only be used if the standard dialect is required, otherwise the + * dialect should be retrieved from the dialect registry. + * + * @param dialectId the schema specification version + * @return the dialect or null if not found + */ + public static Dialect getDialect(String dialectId) { + if (null == dialectId) { + return null; + } + switch (dialectId) { + case DialectId.DRAFT_2020_12: + return Dialects.getDraft202012(); + case DialectId.DRAFT_2019_09: + return Dialects.getDraft201909(); + case DialectId.DRAFT_7: + return Dialects.getDraft7(); + case DialectId.DRAFT_6: + return Dialects.getDraft6(); + case DialectId.DRAFT_4: + return Dialects.getDraft4(); + default: + return null; + } + } +} diff --git a/src/main/java/com/networknt/schema/SpecificationVersion.java b/src/main/java/com/networknt/schema/SpecificationVersion.java new file mode 100644 index 000000000..33bd3752e --- /dev/null +++ b/src/main/java/com/networknt/schema/SpecificationVersion.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2020 Network New Technologies Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.networknt.schema; + +import java.util.Optional; + +import com.networknt.schema.dialect.DialectId; + +/** + * The version of the JSON Schema specification that defines the standard + * dialects. + */ +public enum SpecificationVersion { + /** + * Draft 4. + */ + DRAFT_4(4, DialectId.DRAFT_4), + /** + * Draft 6. + */ + DRAFT_6(6, DialectId.DRAFT_6), + /** + * Draft 7. + */ + DRAFT_7(7, DialectId.DRAFT_7), + /** + * Draft 2019-09. + */ + DRAFT_2019_09(8, DialectId.DRAFT_2019_09), + /** + * Draft 2020-12. + */ + DRAFT_2020_12(9, DialectId.DRAFT_2020_12); + + private final int order; + private final String dialectId; + + SpecificationVersion(int order, String dialectId) { + this.order = order; + this.dialectId = dialectId; + } + + /** + * Gets the dialect id used for the $schema keyword. The dialect id is an IRI + * that identifies the meta schema used to validate the dialect. + * + * @return the dialect id + */ + public String getDialectId() { + return this.dialectId; + } + + /** + * Gets the unique release order of the specification version used that + * indicates when the specification was released. Lower numbers indicate the + * specification was released earlier. + * + * @return the order when the specification was released + */ + public int getOrder() { + return this.order; + } + + /** + * Gets the specification version that matches the dialect id indicated by + * $schema keyword. The dialect id is an IRI that identifies the meta schema + * used to validate the dialect. + * + * @param dialectId the dialect id specified by $schema keyword + * @return the specification version if it matches the dialect id + */ + public static Optional fromDialectId(String dialectId) { + for (SpecificationVersion version : SpecificationVersion.values()) { + if (version.dialectId.equals(dialectId)) { + return Optional.of(version); + } + } + return Optional.empty(); + } +} diff --git a/src/main/java/com/networknt/schema/SpecificationVersionRange.java b/src/main/java/com/networknt/schema/SpecificationVersionRange.java new file mode 100644 index 000000000..846872f51 --- /dev/null +++ b/src/main/java/com/networknt/schema/SpecificationVersionRange.java @@ -0,0 +1,32 @@ +package com.networknt.schema; + +import java.util.Arrays; +import java.util.EnumSet; + +/** + * SpecificationVersionRange. + */ +public enum SpecificationVersionRange { + NONE(new SpecificationVersion[] { }), + ALL_VERSIONS(new SpecificationVersion[] { SpecificationVersion.DRAFT_4, SpecificationVersion.DRAFT_6, SpecificationVersion.DRAFT_7, SpecificationVersion.DRAFT_2019_09, SpecificationVersion.DRAFT_2020_12 }), + MIN_DRAFT_6(new SpecificationVersion[] { SpecificationVersion.DRAFT_6, SpecificationVersion.DRAFT_7, SpecificationVersion.DRAFT_2019_09, SpecificationVersion.DRAFT_2020_12 }), + DRAFT_6_TO_DRAFT_7(new SpecificationVersion[] { SpecificationVersion.DRAFT_6, SpecificationVersion.DRAFT_7 }), + MIN_DRAFT_7(new SpecificationVersion[] { SpecificationVersion.DRAFT_7, SpecificationVersion.DRAFT_2019_09, SpecificationVersion.DRAFT_2020_12 }), + MAX_DRAFT_7(new SpecificationVersion[] { SpecificationVersion.DRAFT_4, SpecificationVersion.DRAFT_6, SpecificationVersion.DRAFT_7 }), + MAX_DRAFT_2019_09(new SpecificationVersion[] { SpecificationVersion.DRAFT_4, SpecificationVersion.DRAFT_6, SpecificationVersion.DRAFT_7, SpecificationVersion.DRAFT_2019_09 }), + MIN_DRAFT_2019_09(new SpecificationVersion[] { SpecificationVersion.DRAFT_2019_09, SpecificationVersion.DRAFT_2020_12 }), + MIN_DRAFT_2020_12(new SpecificationVersion[] { SpecificationVersion.DRAFT_2020_12 }), + DRAFT_2019_09(new SpecificationVersion[] { SpecificationVersion.DRAFT_2019_09 }), + DRAFT_7(new SpecificationVersion[] { SpecificationVersion.DRAFT_7 }); + + private final EnumSet versions; + + SpecificationVersionRange(SpecificationVersion[] versionFlags) { + this.versions = EnumSet.noneOf(SpecificationVersion.class); + this.versions.addAll(Arrays.asList(versionFlags)); + } + + public EnumSet getVersions() { + return this.versions; + } +} \ No newline at end of file diff --git a/src/main/java/com/networknt/schema/ValidationContext.java b/src/main/java/com/networknt/schema/ValidationContext.java deleted file mode 100644 index d35b29b94..000000000 --- a/src/main/java/com/networknt/schema/ValidationContext.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (c) 2016 Network New Technologies Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.networknt.schema; - -import java.util.Optional; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -import com.fasterxml.jackson.databind.JsonNode; -import com.networknt.schema.SpecVersion.VersionFlag; - -public class ValidationContext { - private final JsonMetaSchema metaSchema; - private final JsonSchemaFactory jsonSchemaFactory; - private final SchemaValidatorsConfig config; - private final ConcurrentMap schemaReferences; - private final ConcurrentMap schemaResources; - private final ConcurrentMap dynamicAnchors; - - public ValidationContext(JsonMetaSchema metaSchema, - JsonSchemaFactory jsonSchemaFactory, SchemaValidatorsConfig config) { - this(metaSchema, jsonSchemaFactory, config, new ConcurrentHashMap<>(), new ConcurrentHashMap<>(), new ConcurrentHashMap<>()); - } - - public ValidationContext(JsonMetaSchema metaSchema, JsonSchemaFactory jsonSchemaFactory, - SchemaValidatorsConfig config, ConcurrentMap schemaReferences, - ConcurrentMap schemaResources, ConcurrentMap dynamicAnchors) { - if (metaSchema == null) { - throw new IllegalArgumentException("JsonMetaSchema must not be null"); - } - if (jsonSchemaFactory == null) { - throw new IllegalArgumentException("JsonSchemaFactory must not be null"); - } - this.metaSchema = metaSchema; - this.jsonSchemaFactory = jsonSchemaFactory; - // The deprecated SchemaValidatorsConfig constructor needs to remain until removed - this.config = config == null ? new SchemaValidatorsConfig() : config; - this.schemaReferences = schemaReferences; - this.schemaResources = schemaResources; - this.dynamicAnchors = dynamicAnchors; - } - - public JsonSchema newSchema(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, JsonSchema parentSchema) { - return getJsonSchemaFactory().create(this, schemaLocation, evaluationPath, schemaNode, parentSchema); - } - - public JsonValidator newValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, - String keyword /* keyword */, JsonNode schemaNode, JsonSchema parentSchema) { - return this.metaSchema.newValidator(this, schemaLocation, evaluationPath, keyword, schemaNode, parentSchema); - } - - public String resolveSchemaId(JsonNode schemaNode) { - return this.metaSchema.readId(schemaNode); - } - - public JsonSchemaFactory getJsonSchemaFactory() { - return this.jsonSchemaFactory; - } - - public SchemaValidatorsConfig getConfig() { - return this.config; - } - - /** - * Gets the schema references identified by the ref uri. - * - * @return the schema references - */ - public ConcurrentMap getSchemaReferences() { - return this.schemaReferences; - } - - /** - * Gets the schema resources identified by id. - * - * @return the schema resources - */ - public ConcurrentMap getSchemaResources() { - return this.schemaResources; - } - - /** - * Gets the dynamic anchors. - * - * @return the dynamic anchors - */ - public ConcurrentMap getDynamicAnchors() { - return this.dynamicAnchors; - } - - public JsonMetaSchema getMetaSchema() { - return this.metaSchema; - } - - public Optional activeDialect() { - return Optional.of(this.metaSchema.getSpecification()); - } -} diff --git a/src/main/java/com/networknt/schema/JsonSchemaValidator.java b/src/main/java/com/networknt/schema/Validator.java similarity index 60% rename from src/main/java/com/networknt/schema/JsonSchemaValidator.java rename to src/main/java/com/networknt/schema/Validator.java index cb551a1b4..84d295dc5 100644 --- a/src/main/java/com/networknt/schema/JsonSchemaValidator.java +++ b/src/main/java/com/networknt/schema/Validator.java @@ -17,36 +17,40 @@ package com.networknt.schema; import com.fasterxml.jackson.databind.JsonNode; -import com.networknt.schema.walk.JsonSchemaWalker; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.walk.Walker; /** - * Standard json validator interface, implemented by all validators and JsonSchema. + * A processor that checks an instance node belonging to an instance document + * against a schema. */ -public interface JsonSchemaValidator extends JsonSchemaWalker { +public interface Validator extends Walker { /** - * Validate the given JsonNode, the given node is the child node of the root node at given - * data path. - * @param executionContext ExecutionContext - * @param node JsonNode - * @param rootNode JsonNode - * @param instanceLocation JsonNodePath + * Validate the instance node which belongs to the instance document at the + * instance location. + * + * @param executionContext the execution context + * @param instanceNode the instance node being processed + * @param instance the instance document that the instance node belongs + * to + * @param instanceLocation the location of the instance node being processed */ - void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, - JsonNodePath instanceLocation); + void validate(ExecutionContext executionContext, JsonNode instanceNode, JsonNode instance, + NodePath instanceLocation); /** * This is default implementation of walk method. Its job is to call the * validate method if shouldValidateSchema is enabled. */ @Override - default void walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, - JsonNodePath instanceLocation, boolean shouldValidateSchema) { - if (node == null) { + default void walk(ExecutionContext executionContext, JsonNode instanceNode, JsonNode instance, + NodePath instanceLocation, boolean shouldValidateSchema) { + if (instanceNode == null) { // Note that null is not the same as NullNode return; } if (shouldValidateSchema) { - validate(executionContext, node, rootNode, instanceLocation); + validate(executionContext, instanceNode, instance, instanceLocation); } } @@ -67,5 +71,5 @@ default void walk(ExecutionContext executionContext, JsonNode node, JsonNode roo * * @return the evaluation path */ - JsonNodePath getEvaluationPath(); + NodePath getEvaluationPath(); } diff --git a/src/main/java/com/networknt/schema/ValidatorTypeCode.java b/src/main/java/com/networknt/schema/ValidatorTypeCode.java deleted file mode 100644 index 458efc762..000000000 --- a/src/main/java/com/networknt/schema/ValidatorTypeCode.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright (c) 2016 Network New Technologies Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.networknt.schema; - -import com.fasterxml.jackson.databind.JsonNode; -import com.networknt.schema.SpecVersion.VersionFlag; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -@FunctionalInterface -interface ValidatorFactory { - JsonValidator newInstance(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, - JsonSchema parentSchema, ValidationContext validationContext); -} - -enum VersionCode { - None(new SpecVersion.VersionFlag[] { }), - AllVersions(new SpecVersion.VersionFlag[] { SpecVersion.VersionFlag.V4, SpecVersion.VersionFlag.V6, SpecVersion.VersionFlag.V7, SpecVersion.VersionFlag.V201909, SpecVersion.VersionFlag.V202012 }), - MinV6(new SpecVersion.VersionFlag[] { SpecVersion.VersionFlag.V6, SpecVersion.VersionFlag.V7, SpecVersion.VersionFlag.V201909, SpecVersion.VersionFlag.V202012 }), - MinV6MaxV7(new SpecVersion.VersionFlag[] { SpecVersion.VersionFlag.V6, SpecVersion.VersionFlag.V7 }), - MinV7(new SpecVersion.VersionFlag[] { SpecVersion.VersionFlag.V7, SpecVersion.VersionFlag.V201909, SpecVersion.VersionFlag.V202012 }), - MaxV7(new SpecVersion.VersionFlag[] { SpecVersion.VersionFlag.V4, SpecVersion.VersionFlag.V6, SpecVersion.VersionFlag.V7 }), - MaxV201909(new SpecVersion.VersionFlag[] { SpecVersion.VersionFlag.V4, SpecVersion.VersionFlag.V6, SpecVersion.VersionFlag.V7, SpecVersion.VersionFlag.V201909 }), - MinV201909(new SpecVersion.VersionFlag[] { SpecVersion.VersionFlag.V201909, SpecVersion.VersionFlag.V202012 }), - MinV202012(new SpecVersion.VersionFlag[] { SpecVersion.VersionFlag.V202012 }), - V201909(new SpecVersion.VersionFlag[] { SpecVersion.VersionFlag.V201909 }), - V7(new SpecVersion.VersionFlag[] { SpecVersion.VersionFlag.V7 }); - - private final EnumSet versions; - - VersionCode(SpecVersion.VersionFlag[] versionFlags) { - this.versions = EnumSet.noneOf(VersionFlag.class); - this.versions.addAll(Arrays.asList(versionFlags)); - } - - EnumSet getVersions() { - return this.versions; - } -} - -public enum ValidatorTypeCode implements Keyword, ErrorMessageType { - ADDITIONAL_PROPERTIES("additionalProperties", "1001", AdditionalPropertiesValidator::new, VersionCode.MaxV7), - ALL_OF("allOf", "1002", AllOfValidator::new, VersionCode.MaxV7), - ANY_OF("anyOf", "1003", AnyOfValidator::new, VersionCode.MaxV7), - CONST("const", "1042", ConstValidator::new, VersionCode.MinV6MaxV7), - CONTAINS("contains", "1043", ContainsValidator::new, VersionCode.MinV6MaxV7), - CONTENT_ENCODING("contentEncoding", "1052", ContentEncodingValidator::new, VersionCode.V7), - CONTENT_MEDIA_TYPE("contentMediaType", "1053", ContentMediaTypeValidator::new, VersionCode.V7), - DEPENDENCIES("dependencies", "1007", DependenciesValidator::new, VersionCode.AllVersions), - DEPENDENT_REQUIRED("dependentRequired", "1045", DependentRequired::new, VersionCode.None), - DEPENDENT_SCHEMAS("dependentSchemas", "1046", DependentSchemas::new, VersionCode.None), - DISCRIMINATOR("discriminator", "2001", DiscriminatorValidator::new, VersionCode.None), - DYNAMIC_REF("$dynamicRef", "1051", DynamicRefValidator::new, VersionCode.None), - ENUM("enum", "1008", EnumValidator::new, VersionCode.MaxV7), - EXCLUSIVE_MAXIMUM("exclusiveMaximum", "1038", ExclusiveMaximumValidator::new, VersionCode.MinV6MaxV7), - EXCLUSIVE_MINIMUM("exclusiveMinimum", "1039", ExclusiveMinimumValidator::new, VersionCode.MinV6MaxV7), - FALSE("false", "1041", FalseValidator::new, VersionCode.MinV6), - FORMAT("format", "1009", null, VersionCode.MaxV7) { - @Override public JsonValidator newValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { - throw new UnsupportedOperationException("Use FormatKeyword instead"); - } - }, - ID("id", "1036", null, VersionCode.AllVersions), - IF_THEN_ELSE("if", "1037", IfValidator::new, VersionCode.V7), - ITEMS_202012("items", "1010", ItemsValidator202012::new, VersionCode.None), - ITEMS("items", "1010", ItemsValidator::new, VersionCode.MaxV7), - MAX_CONTAINS("maxContains", "1006", MinMaxContainsValidator::new, VersionCode.None), - MAX_ITEMS("maxItems", "1012", MaxItemsValidator::new, VersionCode.MaxV7), - MAX_LENGTH("maxLength", "1013", MaxLengthValidator::new, VersionCode.MaxV7), - MAX_PROPERTIES("maxProperties", "1014", MaxPropertiesValidator::new, VersionCode.MaxV7), - MAXIMUM("maximum", "1011", MaximumValidator::new, VersionCode.MaxV7), - MIN_CONTAINS("minContains", "1049", MinMaxContainsValidator::new, VersionCode.None), - MIN_ITEMS("minItems", "1016", MinItemsValidator::new, VersionCode.MaxV7), - MIN_LENGTH("minLength", "1017", MinLengthValidator::new, VersionCode.MaxV7), - MIN_PROPERTIES("minProperties", "1018", MinPropertiesValidator::new, VersionCode.MaxV7), - MINIMUM("minimum", "1015", MinimumValidator::new, VersionCode.MaxV7), - MULTIPLE_OF("multipleOf", "1019", MultipleOfValidator::new, VersionCode.MaxV7), - NOT_ALLOWED("notAllowed", "1033", NotAllowedValidator::new, VersionCode.AllVersions), - NOT("not", "1020", NotValidator::new, VersionCode.MaxV7), - ONE_OF("oneOf", "1022", OneOfValidator::new, VersionCode.MaxV7), - PATTERN_PROPERTIES("patternProperties", "1024", PatternPropertiesValidator::new, VersionCode.MaxV7), - PATTERN("pattern", "1023", PatternValidator::new, VersionCode.MaxV7), - PREFIX_ITEMS("prefixItems", "1048", PrefixItemsValidator::new, VersionCode.None), - PROPERTIES("properties", "1025", PropertiesValidator::new, VersionCode.MaxV7), - PROPERTYNAMES("propertyNames", "1044", PropertyNamesValidator::new, VersionCode.MinV6MaxV7), - READ_ONLY("readOnly", "1032", ReadOnlyValidator::new, VersionCode.V7), - RECURSIVE_REF("$recursiveRef", "1050", RecursiveRefValidator::new, VersionCode.None), - REF("$ref", "1026", RefValidator::new, VersionCode.MaxV7), - REQUIRED("required", "1028", RequiredValidator::new, VersionCode.MaxV7), - TRUE("true", "1040", TrueValidator::new, VersionCode.MinV6), - TYPE("type", "1029", TypeValidator::new, VersionCode.MaxV7), - UNEVALUATED_ITEMS("unevaluatedItems", "1021", UnevaluatedItemsValidator::new, VersionCode.None), - UNEVALUATED_PROPERTIES("unevaluatedProperties","1047",UnevaluatedPropertiesValidator::new,VersionCode.None), - UNION_TYPE("unionType", "1030", UnionTypeValidator::new, VersionCode.None), - UNIQUE_ITEMS("uniqueItems", "1031", UniqueItemsValidator::new, VersionCode.MaxV7), - WRITE_ONLY("writeOnly", "1027", WriteOnlyValidator::new, VersionCode.V7), - ; - - private static final Map CONSTANTS = new HashMap<>(); - - static { - for (ValidatorTypeCode c : values()) { - CONSTANTS.put(c.value, c); - } - } - - private final String value; - private final String errorCode; - private final ValidatorFactory validatorFactory; - private final VersionCode versionCode; - - ValidatorTypeCode(String value, String errorCode, ValidatorFactory validatorFactory, VersionCode versionCode) { - this.value = value; - this.errorCode = errorCode; - this.validatorFactory = validatorFactory; - this.versionCode = versionCode; - } - - public static List getKeywords(SpecVersion.VersionFlag versionFlag) { - final List result = new ArrayList<>(); - for (ValidatorTypeCode keyword : values()) { - if (keyword.getVersionCode().getVersions().contains(versionFlag)) { - result.add(keyword); - } - } - return result; - } - - public static ValidatorTypeCode fromValue(String value) { - ValidatorTypeCode constant = CONSTANTS.get(value); - if (constant == null) { - throw new IllegalArgumentException(value); - } - return constant; - } - - @Override - public JsonValidator newValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, - JsonSchema parentSchema, ValidationContext validationContext) { - if (this.validatorFactory == null) { - throw new UnsupportedOperationException("No suitable validator for " + getValue()); - } - return validatorFactory.newInstance(schemaLocation, evaluationPath, schemaNode, parentSchema, - validationContext); - } - - @Override - public String toString() { - return this.value; - } - - @Override - public String getValue() { - return this.value; - } - - @Override - public String getErrorCode() { - return this.errorCode; - } - - public VersionCode getVersionCode() { - return this.versionCode; - } - - @Override - public String getErrorCodeValue() { - return getValue(); - } -} diff --git a/src/main/java/com/networknt/schema/Vocabularies.java b/src/main/java/com/networknt/schema/Vocabularies.java deleted file mode 100644 index 821a92f36..000000000 --- a/src/main/java/com/networknt/schema/Vocabularies.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.networknt.schema; - -import java.util.HashMap; -import java.util.Map; - -/** - * Vocabularies. - */ -public class Vocabularies { - private static final Map VALUES; - - static { - Map mapping = new HashMap<>(); - mapping.put(Vocabulary.V201909_CORE.getIri(), Vocabulary.V201909_CORE); - mapping.put(Vocabulary.V201909_APPLICATOR.getIri(), Vocabulary.V201909_APPLICATOR); - mapping.put(Vocabulary.V201909_VALIDATION.getIri(), Vocabulary.V201909_VALIDATION); - mapping.put(Vocabulary.V201909_META_DATA.getIri(), Vocabulary.V201909_META_DATA); - mapping.put(Vocabulary.V201909_FORMAT.getIri(), Vocabulary.V201909_FORMAT); - mapping.put(Vocabulary.V201909_CONTENT.getIri(), Vocabulary.V201909_CONTENT); - - mapping.put(Vocabulary.V202012_CORE.getIri(), Vocabulary.V202012_CORE); - mapping.put(Vocabulary.V202012_APPLICATOR.getIri(), Vocabulary.V202012_APPLICATOR); - mapping.put(Vocabulary.V202012_UNEVALUATED.getIri(), Vocabulary.V202012_UNEVALUATED); - mapping.put(Vocabulary.V202012_VALIDATION.getIri(), Vocabulary.V202012_VALIDATION); - mapping.put(Vocabulary.V202012_META_DATA.getIri(), Vocabulary.V202012_META_DATA); - mapping.put(Vocabulary.V202012_FORMAT_ANNOTATION.getIri(), Vocabulary.V202012_FORMAT_ANNOTATION); - mapping.put(Vocabulary.V202012_FORMAT_ASSERTION.getIri(), Vocabulary.V202012_FORMAT_ASSERTION); - mapping.put(Vocabulary.V202012_CONTENT.getIri(), Vocabulary.V202012_CONTENT); - - mapping.put(Vocabulary.OPENAPI_3_1_BASE.getIri(), Vocabulary.OPENAPI_3_1_BASE); - - VALUES = mapping; - } - - /** - * Gets the vocabulary given its uri. - * - * @param uri the vocabulary - * @return the vocabulary - */ - public static Vocabulary getVocabulary(String uri) { - return VALUES.get(uri); - } -} diff --git a/src/main/java/com/networknt/schema/Vocabulary.java b/src/main/java/com/networknt/schema/Vocabulary.java deleted file mode 100644 index aa2c360de..000000000 --- a/src/main/java/com/networknt/schema/Vocabulary.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (c) 2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.networknt.schema; - -import java.util.Arrays; -import java.util.LinkedHashSet; -import java.util.Objects; -import java.util.Set; - -/** - * Represents a vocabulary in meta-schema. - *

- * This contains the IRI and the keywords in the vocabulary. - */ -public class Vocabulary { - - // 2019-09 - public static final Vocabulary V201909_CORE = new Vocabulary("https://json-schema.org/draft/2019-09/vocab/core", - new NonValidationKeyword("$id"), new NonValidationKeyword("$schema"), new NonValidationKeyword("$anchor"), - ValidatorTypeCode.REF, ValidatorTypeCode.RECURSIVE_REF, new NonValidationKeyword("$recursiveAnchor"), - new NonValidationKeyword("$vocabulary"), new NonValidationKeyword("$comment"), - new NonValidationKeyword("$defs")); - public static final Vocabulary V201909_APPLICATOR = new Vocabulary( - "https://json-schema.org/draft/2019-09/vocab/applicator", new NonValidationKeyword("additionalItems"), - ValidatorTypeCode.UNEVALUATED_ITEMS, ValidatorTypeCode.ITEMS, ValidatorTypeCode.CONTAINS, - ValidatorTypeCode.ADDITIONAL_PROPERTIES, ValidatorTypeCode.UNEVALUATED_PROPERTIES, - ValidatorTypeCode.PROPERTIES, ValidatorTypeCode.PATTERN_PROPERTIES, ValidatorTypeCode.DEPENDENT_SCHEMAS, - ValidatorTypeCode.PROPERTYNAMES, ValidatorTypeCode.IF_THEN_ELSE, new NonValidationKeyword("then"), - new NonValidationKeyword("else"), ValidatorTypeCode.ALL_OF, ValidatorTypeCode.ANY_OF, - ValidatorTypeCode.ONE_OF, ValidatorTypeCode.NOT); - public static final Vocabulary V201909_VALIDATION = new Vocabulary( - "https://json-schema.org/draft/2019-09/vocab/validation", ValidatorTypeCode.MULTIPLE_OF, - ValidatorTypeCode.MAXIMUM, ValidatorTypeCode.EXCLUSIVE_MAXIMUM, ValidatorTypeCode.MINIMUM, - ValidatorTypeCode.EXCLUSIVE_MINIMUM, ValidatorTypeCode.MAX_LENGTH, ValidatorTypeCode.MIN_LENGTH, - ValidatorTypeCode.PATTERN, ValidatorTypeCode.MAX_ITEMS, ValidatorTypeCode.MIN_ITEMS, - ValidatorTypeCode.UNIQUE_ITEMS, ValidatorTypeCode.MAX_CONTAINS, ValidatorTypeCode.MIN_CONTAINS, - ValidatorTypeCode.MAX_PROPERTIES, ValidatorTypeCode.MIN_PROPERTIES, ValidatorTypeCode.REQUIRED, - ValidatorTypeCode.DEPENDENT_REQUIRED, ValidatorTypeCode.CONST, ValidatorTypeCode.ENUM, - ValidatorTypeCode.TYPE); - public static final Vocabulary V201909_META_DATA = new Vocabulary( - "https://json-schema.org/draft/2019-09/vocab/meta-data", new AnnotationKeyword("title"), - new AnnotationKeyword("description"), new AnnotationKeyword("default"), new AnnotationKeyword("deprecated"), - ValidatorTypeCode.READ_ONLY, ValidatorTypeCode.WRITE_ONLY, new AnnotationKeyword("examples")); - public static final Vocabulary V201909_FORMAT = new Vocabulary("https://json-schema.org/draft/2019-09/vocab/format", - ValidatorTypeCode.FORMAT); - public static final Vocabulary V201909_CONTENT = new Vocabulary( - "https://json-schema.org/draft/2019-09/vocab/content", new AnnotationKeyword("contentMediaType"), - new AnnotationKeyword("contentEncoding"), new AnnotationKeyword("contentSchema")); - - // 2020-12 - public static final Vocabulary V202012_CORE = new Vocabulary("https://json-schema.org/draft/2020-12/vocab/core", - new NonValidationKeyword("$id"), new NonValidationKeyword("$schema"), ValidatorTypeCode.REF, - new NonValidationKeyword("$anchor"), ValidatorTypeCode.DYNAMIC_REF, - new NonValidationKeyword("$dynamicAnchor"), new NonValidationKeyword("$vocabulary"), - new NonValidationKeyword("$comment"), new NonValidationKeyword("$defs")); - public static final Vocabulary V202012_APPLICATOR = new Vocabulary( - "https://json-schema.org/draft/2020-12/vocab/applicator", ValidatorTypeCode.PREFIX_ITEMS, - ValidatorTypeCode.ITEMS_202012, ValidatorTypeCode.CONTAINS, ValidatorTypeCode.ADDITIONAL_PROPERTIES, - ValidatorTypeCode.PROPERTIES, ValidatorTypeCode.PATTERN_PROPERTIES, ValidatorTypeCode.DEPENDENT_SCHEMAS, - ValidatorTypeCode.PROPERTYNAMES, ValidatorTypeCode.IF_THEN_ELSE, new NonValidationKeyword("then"), - new NonValidationKeyword("else"), ValidatorTypeCode.ALL_OF, ValidatorTypeCode.ANY_OF, - ValidatorTypeCode.ONE_OF, ValidatorTypeCode.NOT); - public static final Vocabulary V202012_UNEVALUATED = new Vocabulary( - "https://json-schema.org/draft/2020-12/vocab/unevaluated", ValidatorTypeCode.UNEVALUATED_ITEMS, - ValidatorTypeCode.UNEVALUATED_PROPERTIES); - public static final Vocabulary V202012_VALIDATION = new Vocabulary( - "https://json-schema.org/draft/2020-12/vocab/validation", ValidatorTypeCode.TYPE, ValidatorTypeCode.CONST, - ValidatorTypeCode.ENUM, ValidatorTypeCode.MULTIPLE_OF, ValidatorTypeCode.MAXIMUM, - ValidatorTypeCode.EXCLUSIVE_MAXIMUM, ValidatorTypeCode.MINIMUM, ValidatorTypeCode.EXCLUSIVE_MINIMUM, - ValidatorTypeCode.MAX_LENGTH, ValidatorTypeCode.MIN_LENGTH, ValidatorTypeCode.PATTERN, - ValidatorTypeCode.MAX_ITEMS, ValidatorTypeCode.MIN_ITEMS, ValidatorTypeCode.UNIQUE_ITEMS, - ValidatorTypeCode.MAX_CONTAINS, ValidatorTypeCode.MIN_CONTAINS, ValidatorTypeCode.MAX_PROPERTIES, - ValidatorTypeCode.MIN_PROPERTIES, ValidatorTypeCode.REQUIRED, ValidatorTypeCode.DEPENDENT_REQUIRED); - public static final Vocabulary V202012_META_DATA = new Vocabulary( - "https://json-schema.org/draft/2020-12/vocab/meta-data", new AnnotationKeyword("title"), - new AnnotationKeyword("description"), new AnnotationKeyword("default"), new AnnotationKeyword("deprecated"), - ValidatorTypeCode.READ_ONLY, ValidatorTypeCode.WRITE_ONLY, new AnnotationKeyword("examples")); - public static final Vocabulary V202012_FORMAT_ANNOTATION = new Vocabulary( - "https://json-schema.org/draft/2020-12/vocab/format-annotation", ValidatorTypeCode.FORMAT); - public static final Vocabulary V202012_FORMAT_ASSERTION = new Vocabulary( - "https://json-schema.org/draft/2020-12/vocab/format-assertion", ValidatorTypeCode.FORMAT); - public static final Vocabulary V202012_CONTENT = new Vocabulary( - "https://json-schema.org/draft/2020-12/vocab/content", new AnnotationKeyword("contentEncoding"), - new AnnotationKeyword("contentMediaType"), new AnnotationKeyword("contentSchema")); - - // OpenAPI 3.1 - public static final Vocabulary OPENAPI_3_1_BASE = new Vocabulary("https://spec.openapis.org/oas/3.1/vocab/base", - new AnnotationKeyword("example"), ValidatorTypeCode.DISCRIMINATOR, new AnnotationKeyword("externalDocs"), - new AnnotationKeyword("xml")); - - private final String iri; - private final Set keywords; - - /** - * Constructor. - * - * @param iri the iri - * @param keywords the keywords - */ - public Vocabulary(String iri, Keyword... keywords) { - this.iri = iri; - this.keywords = new LinkedHashSet<>(); - this.keywords.addAll(Arrays.asList(keywords)); - } - - /** - * The iri of the vocabulary. - * - * @return the iri - */ - public String getIri() { - return iri; - } - - /** - * The keywords in the vocabulary. - * - * @return the keywords - */ - public Set getKeywords() { - return keywords; - } - - @Override - public int hashCode() { - return Objects.hash(iri, keywords); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - Vocabulary other = (Vocabulary) obj; - return Objects.equals(iri, other.iri) && Objects.equals(keywords, other.keywords); - } - - @Override - public String toString() { - return "Vocabulary [iri=" + iri + ", keywords=" + keywords + "]"; - } - -} diff --git a/src/main/java/com/networknt/schema/WriteOnlyValidator.java b/src/main/java/com/networknt/schema/WriteOnlyValidator.java deleted file mode 100644 index e28eccaaa..000000000 --- a/src/main/java/com/networknt/schema/WriteOnlyValidator.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.networknt.schema; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.fasterxml.jackson.databind.JsonNode; - -/** - * {@link JsonValidator} for writeOnly. - */ -public class WriteOnlyValidator extends BaseJsonValidator { - private static final Logger logger = LoggerFactory.getLogger(WriteOnlyValidator.class); - - private final boolean writeOnly; - - public WriteOnlyValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.WRITE_ONLY, validationContext); - - this.writeOnly = validationContext.getConfig().isWriteOnly(); - logger.debug("Loaded WriteOnlyValidator for property {} as {}", parentSchema, "write mode"); - } - - @Override - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) { - debug(logger, executionContext, node, rootNode, instanceLocation); - if (this.writeOnly) { - executionContext.addError(message().instanceNode(node).instanceLocation(instanceLocation) - .locale(executionContext.getExecutionConfig().getLocale()) - .failFast(executionContext.isFailFast()).build()); - } - } - -} diff --git a/src/main/java/com/networknt/schema/annotation/JsonNodeAnnotation.java b/src/main/java/com/networknt/schema/annotation/Annotation.java similarity index 76% rename from src/main/java/com/networknt/schema/annotation/JsonNodeAnnotation.java rename to src/main/java/com/networknt/schema/annotation/Annotation.java index 086bc35ee..a3638498d 100644 --- a/src/main/java/com/networknt/schema/annotation/JsonNodeAnnotation.java +++ b/src/main/java/com/networknt/schema/annotation/Annotation.java @@ -17,22 +17,22 @@ import java.util.Objects; -import com.networknt.schema.JsonNodePath; -import com.networknt.schema.Keyword; import com.networknt.schema.SchemaLocation; +import com.networknt.schema.keyword.Keyword; +import com.networknt.schema.path.NodePath; /** * The annotation. */ -public class JsonNodeAnnotation { +public class Annotation { private final String keyword; - private final JsonNodePath instanceLocation; + private final NodePath instanceLocation; private final SchemaLocation schemaLocation; - private final JsonNodePath evaluationPath; + private final NodePath evaluationPath; private final Object value; - public JsonNodeAnnotation(String keyword, JsonNodePath instanceLocation, SchemaLocation schemaLocation, - JsonNodePath evaluationPath, Object value) { + public Annotation(String keyword, NodePath instanceLocation, SchemaLocation schemaLocation, + NodePath evaluationPath, Object value) { super(); this.keyword = keyword; this.instanceLocation = instanceLocation; @@ -55,7 +55,7 @@ public String getKeyword() { * * @return the instance location */ - public JsonNodePath getInstanceLocation() { + public NodePath getInstanceLocation() { return instanceLocation; } @@ -75,7 +75,7 @@ public SchemaLocation getSchemaLocation() { * * @return the evaluation path */ - public JsonNodePath getEvaluationPath() { + public NodePath getEvaluationPath() { return evaluationPath; } @@ -92,7 +92,7 @@ public T getValue() { @Override public String toString() { - return "JsonNodeAnnotation [evaluationPath=" + evaluationPath + ", schemaLocation=" + schemaLocation + return "Annotation [evaluationPath=" + evaluationPath + ", schemaLocation=" + schemaLocation + ", instanceLocation=" + instanceLocation + ", keyword=" + keyword + ", value=" + value + "]"; } @@ -109,7 +109,7 @@ public boolean equals(Object obj) { return false; if (getClass() != obj.getClass()) return false; - JsonNodeAnnotation other = (JsonNodeAnnotation) obj; + Annotation other = (Annotation) obj; return Objects.equals(evaluationPath, other.evaluationPath) && Objects.equals(instanceLocation, other.instanceLocation) && Objects.equals(keyword, other.keyword) && Objects.equals(schemaLocation, other.schemaLocation) && Objects.equals(value, other.value); @@ -121,9 +121,9 @@ public static Builder builder() { public static class Builder { private String keyword; - private JsonNodePath instanceLocation; + private NodePath instanceLocation; private SchemaLocation schemaLocation; - private JsonNodePath evaluationPath; + private NodePath evaluationPath; private Object value; public Builder keyword(Keyword keyword) { @@ -136,7 +136,7 @@ public Builder keyword(String keyword) { return this; } - public Builder instanceLocation(JsonNodePath instanceLocation) { + public Builder instanceLocation(NodePath instanceLocation) { this.instanceLocation = instanceLocation; return this; } @@ -146,7 +146,7 @@ public Builder schemaLocation(SchemaLocation schemaLocation) { return this; } - public Builder evaluationPath(JsonNodePath evaluationPath) { + public Builder evaluationPath(NodePath evaluationPath) { this.evaluationPath = evaluationPath; return this; } @@ -156,8 +156,8 @@ public Builder value(Object value) { return this; } - public JsonNodeAnnotation build() { - return new JsonNodeAnnotation(keyword, instanceLocation, schemaLocation, evaluationPath, value); + public Annotation build() { + return new Annotation(keyword, instanceLocation, schemaLocation, evaluationPath, value); } } diff --git a/src/main/java/com/networknt/schema/annotation/JsonNodeAnnotationPredicate.java b/src/main/java/com/networknt/schema/annotation/AnnotationPredicate.java similarity index 76% rename from src/main/java/com/networknt/schema/annotation/JsonNodeAnnotationPredicate.java rename to src/main/java/com/networknt/schema/annotation/AnnotationPredicate.java index 5f356af12..c9268e17c 100644 --- a/src/main/java/com/networknt/schema/annotation/JsonNodeAnnotationPredicate.java +++ b/src/main/java/com/networknt/schema/annotation/AnnotationPredicate.java @@ -17,15 +17,15 @@ import java.util.function.Predicate; -import com.networknt.schema.JsonNodePath; import com.networknt.schema.SchemaLocation; +import com.networknt.schema.path.NodePath; /** * A predicate for filtering annotations. */ -public class JsonNodeAnnotationPredicate implements Predicate { - final Predicate instanceLocationPredicate; - final Predicate evaluationPathPredicate; +public class AnnotationPredicate implements Predicate { + final Predicate instanceLocationPredicate; + final Predicate evaluationPathPredicate; final Predicate schemaLocationPredicate; final Predicate keywordPredicate; final Predicate valuePredicate; @@ -39,8 +39,8 @@ public class JsonNodeAnnotationPredicate implements Predicate instanceLocationPredicate, - Predicate evaluationPathPredicate, Predicate schemaLocationPredicate, + protected AnnotationPredicate(Predicate instanceLocationPredicate, + Predicate evaluationPathPredicate, Predicate schemaLocationPredicate, Predicate keywordPredicate, Predicate valuePredicate) { super(); this.instanceLocationPredicate = instanceLocationPredicate; @@ -51,7 +51,7 @@ protected JsonNodeAnnotationPredicate(Predicate instanceLocationPr } @Override - public boolean test(JsonNodeAnnotation t) { + public boolean test(Annotation t) { return ((valuePredicate == null || valuePredicate.test(t.getValue())) && (keywordPredicate == null || keywordPredicate.test(t.getKeyword())) && (instanceLocationPredicate == null || instanceLocationPredicate.test(t.getInstanceLocation())) @@ -64,7 +64,7 @@ public boolean test(JsonNodeAnnotation t) { * * @return the predicate */ - public Predicate getInstanceLocationPredicate() { + public Predicate getInstanceLocationPredicate() { return instanceLocationPredicate; } @@ -73,7 +73,7 @@ public Predicate getInstanceLocationPredicate() { * * @return the predicate */ - public Predicate getEvaluationPathPredicate() { + public Predicate getEvaluationPathPredicate() { return evaluationPathPredicate; } @@ -114,21 +114,21 @@ public static Builder builder() { } /** - * Builder for building a {@link JsonNodeAnnotationPredicate}. + * Builder for building a {@link AnnotationPredicate}. */ public static class Builder { - Predicate instanceLocationPredicate; - Predicate evaluationPathPredicate; + Predicate instanceLocationPredicate; + Predicate evaluationPathPredicate; Predicate schemaLocationPredicate; Predicate keywordPredicate; Predicate valuePredicate; - public Builder instanceLocation(Predicate instanceLocationPredicate) { + public Builder instanceLocation(Predicate instanceLocationPredicate) { this.instanceLocationPredicate = instanceLocationPredicate; return this; } - public Builder evaluationPath(Predicate evaluationPathPredicate) { + public Builder evaluationPath(Predicate evaluationPathPredicate) { this.evaluationPathPredicate = evaluationPathPredicate; return this; } @@ -148,8 +148,8 @@ public Builder value(Predicate valuePredicate) { return this; } - public JsonNodeAnnotationPredicate build() { - return new JsonNodeAnnotationPredicate(instanceLocationPredicate, evaluationPathPredicate, + public AnnotationPredicate build() { + return new AnnotationPredicate(instanceLocationPredicate, evaluationPathPredicate, schemaLocationPredicate, keywordPredicate, valuePredicate); } } diff --git a/src/main/java/com/networknt/schema/annotation/JsonNodeAnnotations.java b/src/main/java/com/networknt/schema/annotation/Annotations.java similarity index 81% rename from src/main/java/com/networknt/schema/annotation/JsonNodeAnnotations.java rename to src/main/java/com/networknt/schema/annotation/Annotations.java index 4e4f58278..581f73b8f 100644 --- a/src/main/java/com/networknt/schema/annotation/JsonNodeAnnotations.java +++ b/src/main/java/com/networknt/schema/annotation/Annotations.java @@ -21,7 +21,7 @@ import java.util.Map; import com.fasterxml.jackson.core.JsonProcessingException; -import com.networknt.schema.JsonNodePath; +import com.networknt.schema.path.NodePath; import com.networknt.schema.serialization.JsonMapperFactory; /** @@ -31,14 +31,14 @@ * "https://github.com/json-schema-org/json-schema-spec/issues/530">Details * of annotation collection */ -public class JsonNodeAnnotations { +public class Annotations { /** * Stores the annotations. *

* instancePath to annotation */ - private final Map> values = new LinkedHashMap<>(); + private final Map> values = new LinkedHashMap<>(); /** * Gets the annotations. @@ -47,7 +47,7 @@ public class JsonNodeAnnotations { * * @return the annotations */ - public Map> asMap() { + public Map> asMap() { return this.values; } @@ -56,7 +56,7 @@ public Map> asMap() { * * @param annotation the annotation */ - public void put(JsonNodeAnnotation annotation) { + public void put(Annotation annotation) { this.values.computeIfAbsent(annotation.getInstanceLocation(), (k) -> new ArrayList<>()).add(annotation); } @@ -76,10 +76,10 @@ public static class Formatter { * @param annotations the annotations * @return the formatted JSON */ - public static String format(Map> annotations) { + public static String format(Map> annotations) { Map>> results = new LinkedHashMap<>(); - for (List list : annotations.values()) { - for (JsonNodeAnnotation annotation : list) { + for (List list : annotations.values()) { + for (Annotation annotation : list) { String keyword = annotation.getKeyword(); String instancePath = annotation.getInstanceLocation().toString(); String evaluationPath = annotation.getEvaluationPath().toString(); diff --git a/src/main/java/com/networknt/schema/dialect/AbstractDialectRegistry.java b/src/main/java/com/networknt/schema/dialect/AbstractDialectRegistry.java new file mode 100644 index 000000000..7bddaacfa --- /dev/null +++ b/src/main/java/com/networknt/schema/dialect/AbstractDialectRegistry.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.networknt.schema.dialect; + +import java.util.Map; +import java.util.Map.Entry; + +import com.fasterxml.jackson.databind.JsonNode; +import com.networknt.schema.Error; +import com.networknt.schema.InvalidSchemaException; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.SchemaRegistry; +import com.networknt.schema.SpecificationVersion; + +/** + * Abstract {@link DialectRegistry}. + */ +public abstract class AbstractDialectRegistry implements DialectRegistry { + protected Dialect loadDialect(String iri, SchemaRegistry schemaFactory) { + try { + Dialect result = loadDialectBuilder(iri, schemaFactory).build(); + return result; + } catch (InvalidSchemaException e) { + throw e; + } catch (Exception e) { + Error error = Error.builder().message("Failed to load dialect ''{0}''").arguments(iri).build(); + throw new InvalidSchemaException(error, e); + } + } + + protected Dialect.Builder loadDialectBuilder(String iri, SchemaRegistry schemaFactory) { + Schema schema = schemaFactory.getSchema(SchemaLocation.of(iri)); + Dialect.Builder builder = Dialect.builder(iri, schema.getSchemaContext().getDialect()); + SpecificationVersion specification = schema.getSchemaContext().getDialect().getSpecificationVersion(); + if (specification != null) { + if (specification.getOrder() >= SpecificationVersion.DRAFT_2019_09.getOrder()) { + // Process vocabularies + JsonNode vocabulary = schema.getSchemaNode().get("$vocabulary"); + if (vocabulary != null) { + builder.vocabularies(Map::clear); + for (Entry vocabs : vocabulary.properties()) { + builder.vocabulary(vocabs.getKey(), vocabs.getValue().booleanValue()); + } + } + } + } + return builder; + } +} diff --git a/src/main/java/com/networknt/schema/dialect/BasicDialectRegistry.java b/src/main/java/com/networknt/schema/dialect/BasicDialectRegistry.java new file mode 100644 index 000000000..137b78a15 --- /dev/null +++ b/src/main/java/com/networknt/schema/dialect/BasicDialectRegistry.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.networknt.schema.dialect; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; + +import com.networknt.schema.Error; +import com.networknt.schema.InvalidSchemaException; +import com.networknt.schema.SchemaRegistry; + +/** + * Basic {@link DialectRegistry}. + */ +public class BasicDialectRegistry extends AbstractDialectRegistry { + protected final Function dialects; + + protected BasicDialectRegistry() { + this.dialects = null; + } + + public BasicDialectRegistry(Function dialects) { + this.dialects = dialects; + } + + public BasicDialectRegistry(Dialect dialect) { + this.dialects = dialectId -> dialect.getId().equals(dialectId) ? dialect : null; + } + + public BasicDialectRegistry(Collection dialects) { + Map result = new HashMap<>(); + for (Dialect dialect : dialects) { + result.put(dialect.getId(), dialect); + } + this.dialects = result::get; + } + + @Override + public Dialect getDialect(String dialectId, SchemaRegistry schemaRegistry) { + Dialect dialect = dialects.apply(dialectId); + if (dialect != null) { + return dialect; + } + throw new InvalidSchemaException(Error.builder() + .message("Unknown dialect ''{0}''. Only dialects that are explicitly configured can be used.") + .arguments(dialectId).build()); + } +} diff --git a/src/main/java/com/networknt/schema/dialect/DefaultDialectRegistry.java b/src/main/java/com/networknt/schema/dialect/DefaultDialectRegistry.java new file mode 100644 index 000000000..d66d0f39e --- /dev/null +++ b/src/main/java/com/networknt/schema/dialect/DefaultDialectRegistry.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.networknt.schema.dialect; + +import java.util.Collection; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.function.Function; + +import com.networknt.schema.SchemaRegistry; +import com.networknt.schema.Specification; + +/** + * Default {@link DialectRegistry}. + */ +public class DefaultDialectRegistry extends BasicDialectRegistry { + private final ConcurrentMap loadedDialects = new ConcurrentHashMap<>(); + + public DefaultDialectRegistry() { + super(); + } + + public DefaultDialectRegistry(Function dialects) { + super(dialects); + } + + public DefaultDialectRegistry(Dialect dialect) { + super(dialect); + } + + public DefaultDialectRegistry(Collection dialects) { + super(dialects); + } + + @Override + public Dialect getDialect(String dialectId, SchemaRegistry schemaFactory) { + if (this.dialects != null) { + Dialect dialect = dialects.apply(dialectId); + if (dialect != null) { + return dialect; + } + } + // Is it a well-known dialect? + Dialect dialect = Specification.getDialect(dialectId); + if (dialect != null) { + return dialect; + } + return loadedDialects.computeIfAbsent(dialectId, id -> loadDialect(id, schemaFactory)); + } + + private static class Holder { + private static final DefaultDialectRegistry INSTANCE = new DefaultDialectRegistry(); + } + + public static DefaultDialectRegistry getInstance() { + return Holder.INSTANCE; + } +} diff --git a/src/main/java/com/networknt/schema/JsonMetaSchema.java b/src/main/java/com/networknt/schema/dialect/Dialect.java similarity index 66% rename from src/main/java/com/networknt/schema/JsonMetaSchema.java rename to src/main/java/com/networknt/schema/dialect/Dialect.java index e2a90056e..ebe04b2bc 100644 --- a/src/main/java/com/networknt/schema/JsonMetaSchema.java +++ b/src/main/java/com/networknt/schema/dialect/Dialect.java @@ -14,11 +14,29 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.dialect; import com.fasterxml.jackson.databind.JsonNode; -import com.networknt.schema.SpecVersion.VersionFlag; -import com.networknt.schema.utils.StringUtils; +import com.networknt.schema.Error; +import com.networknt.schema.InvalidSchemaException; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaException; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.SchemaContext; +import com.networknt.schema.SpecificationVersion; +import com.networknt.schema.format.Format; +import com.networknt.schema.keyword.FormatKeyword; +import com.networknt.schema.keyword.Keyword; +import com.networknt.schema.keyword.KeywordFactory; +import com.networknt.schema.keyword.KeywordValidator; +import com.networknt.schema.keyword.UnknownKeywordFactory; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.keyword.KeywordType; +import com.networknt.schema.utils.Strings; +import com.networknt.schema.vocabulary.Vocabularies; +import com.networknt.schema.vocabulary.Vocabulary; +import com.networknt.schema.vocabulary.VocabularyRegistry; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -31,10 +49,13 @@ import java.util.function.Consumer; /** - * Represents a meta-schema which is uniquely identified by its IRI. + * A dialect represents the set of keywords and semantics that can be used to + * evaluate a schema. The dialect can be uniquely identified by its IRI which + * points to the meta-schema used to validate schemas written for that dialect. + * The dialect for a particular schema is indicated using the $schema keyword. */ -public class JsonMetaSchema { - private static final Logger logger = LoggerFactory.getLogger(JsonMetaSchema.class); +public class Dialect { + private static final Logger logger = LoggerFactory.getLogger(Dialect.class); /** * Factory for creating a format keyword. @@ -50,21 +71,21 @@ public interface FormatKeywordFactory { } /** - * Builder for {@link JsonMetaSchema}. + * Builder for {@link Dialect}. */ public static class Builder { - private String iri; + private String id; private String idKeyword = "$id"; - private VersionFlag specification = null; + private SpecificationVersion specificationVersion = null; private final Map keywords = new HashMap<>(); private final Map formats = new HashMap<>(); private final Map vocabularies = new HashMap<>(); private FormatKeywordFactory formatKeywordFactory = null; - private VocabularyFactory vocabularyFactory = null; + private VocabularyRegistry vocabularyRegistry = null; private KeywordFactory unknownKeywordFactory = null; - public Builder(String iri) { - this.iri = iri; + public Builder(String id) { + this.id = id; } private Map createKeywordsMap(Map kwords, Map formats) { @@ -73,8 +94,8 @@ private Map createKeywordsMap(Map kwords, Map< for (Map.Entry type : kwords.entrySet()) { String keywordName = type.getKey(); Keyword keyword = type.getValue(); - if (ValidatorTypeCode.FORMAT.getValue().equals(keywordName)) { - if (!(keyword instanceof FormatKeyword) && !ValidatorTypeCode.FORMAT.equals(keyword)) { + if (KeywordType.FORMAT.getValue().equals(keywordName)) { + if (!(keyword instanceof FormatKeyword) && !KeywordType.FORMAT.equals(keyword)) { throw new IllegalArgumentException("Overriding the keyword 'format' is not supported. Use the formatKeywordFactory and extend the FormatKeyword."); } // Indicate that the format keyword needs to be created @@ -103,13 +124,13 @@ public Builder formatKeywordFactory(FormatKeywordFactory formatKeywordFactory) { } /** - * Sets the vocabulary factory for handling custom vocabularies. + * Sets the vocabulary registry for handling custom vocabularies. * - * @param vocabularyFactory the factory + * @param vocabularyRegistry the registry * @return the builder */ - public Builder vocabularyFactory(VocabularyFactory vocabularyFactory) { - this.vocabularyFactory = vocabularyFactory; + public Builder vocabularyRegistry(VocabularyRegistry vocabularyRegistry) { + this.vocabularyRegistry = vocabularyRegistry; return this; } @@ -242,13 +263,13 @@ public Builder vocabularies(Consumer> customizer) { } /** - * Sets the specification. + * Sets the specification version. * - * @param specification the specification + * @param specification the specification version * @return the builder */ - public Builder specification(VersionFlag specification) { - this.specification = specification; + public Builder specificationVersion(SpecificationVersion specification) { + this.specificationVersion = specification; return this; } @@ -263,152 +284,108 @@ public Builder idKeyword(String idKeyword) { return this; } - public JsonMetaSchema build() { + public Dialect build() { // create builtin keywords with (custom) formats. Map keywords = this.keywords; - if (this.specification != null) { - if (this.specification.getVersionFlagValue() >= SpecVersion.VersionFlag.V201909.getVersionFlagValue()) { + if (this.specificationVersion != null) { + if (this.specificationVersion.getOrder() >= SpecificationVersion.DRAFT_2019_09.getOrder()) { keywords = new HashMap<>(this.keywords); for(Entry entry : this.vocabularies.entrySet()) { Vocabulary vocabulary = null; String id = entry.getKey(); - if (this.vocabularyFactory != null) { - vocabulary = this.vocabularyFactory.getVocabulary(id); + if (this.vocabularyRegistry != null) { + vocabulary = this.vocabularyRegistry.getVocabulary(id); } if (vocabulary == null) { vocabulary = Vocabularies.getVocabulary(id); } if (vocabulary != null) { for (Keyword keyword : vocabulary.getKeywords()) { - keywords.put(keyword.getValue(), keyword); + // Only add keyword from vocabulary if not already + // ie. allow overriding the keyword by explicitly adding it + keywords.putIfAbsent(keyword.getValue(), keyword); } } else if (Boolean.TRUE.equals(entry.getValue())) { - ValidationMessage validationMessage = ValidationMessage.builder() - .message("Meta-schema ''{1}'' has unknown required vocabulary ''{2}''") - .arguments(this.iri, id).build(); - throw new InvalidSchemaException(validationMessage); + Error error = Error.builder() + .message("Meta-schema ''{0}'' has unknown required vocabulary ''{1}''") + .arguments(this.id, id).build(); + throw new InvalidSchemaException(error); } } } } Map result = createKeywordsMap(keywords, this.formats); - return new JsonMetaSchema(this.iri, this.idKeyword, result, this.vocabularies, this.specification, this); - } - - @Deprecated - public Builder addKeyword(Keyword keyword) { - return keyword(keyword); - } - - @Deprecated - public Builder addKeywords(Collection keywords) { - return keywords(keywords); - } - - @Deprecated - public Builder addFormat(Format format) { - return format(format); - } - - @Deprecated - public Builder addFormats(Collection formats) { - return formats(formats); + return new Dialect(this.id, this.idKeyword, result, this.vocabularies, this.specificationVersion, this); } } - private final String iri; + private final String id; private final String idKeyword; private final Map keywords; private final Map vocabularies; - private final VersionFlag specification; + private final SpecificationVersion specificationVersion; private final Builder builder; - JsonMetaSchema(String iri, String idKeyword, Map keywords, Map vocabularies, VersionFlag specification, Builder builder) { - if (StringUtils.isBlank(iri)) { - throw new IllegalArgumentException("iri must not be null or blank"); + Dialect(String dialectId, String idKeyword, Map keywords, Map vocabularies, SpecificationVersion specification, Builder builder) { + if (Strings.isBlank(dialectId)) { + throw new IllegalArgumentException("dialect id must not be null or blank"); } - if (StringUtils.isBlank(idKeyword)) { + if (Strings.isBlank(idKeyword)) { throw new IllegalArgumentException("idKeyword must not be null or blank"); } if (keywords == null) { throw new IllegalArgumentException("keywords must not be null "); } - this.iri = iri; + this.id = dialectId; this.idKeyword = idKeyword; this.keywords = keywords; - this.specification = specification; + this.specificationVersion = specification; this.vocabularies = vocabularies; this.builder = builder; } - public static JsonMetaSchema getV4() { - return new Version4().getInstance(); - } - - public static JsonMetaSchema getV6() { - return new Version6().getInstance(); - } - - public static JsonMetaSchema getV7() { - return new Version7().getInstance(); - } - - public static JsonMetaSchema getV201909() { - return new Version201909().getInstance(); - } - - public static JsonMetaSchema getV202012() { - return new Version202012().getInstance(); - } - /** * Create a builder without keywords or formats. - *

- * Use {@link #getV4()} for the Draft 4 Metaschema, or if you need a builder based on Draft4, use - * - * - * JsonMetaSchema.builder("http://your-metaschema-iri", JsonMetaSchema.getV4()).build(); - * * - * @param iri the IRI of the metaschema that will be defined via this builder. + * @param id the IRI of the dialect that will be defined via this builder. * @return a builder instance without any keywords or formats - usually not what one needs. */ - public static Builder builder(String iri) { - return new Builder(iri); + public static Builder builder(String id) { + return new Builder(id); } /** * Create a builder. * - * @param iri the IRI of your new JsonMetaSchema that will be defined via + * @param id the IRI of your new Dialect that will be defined via * this builder. - * @param blueprint the JsonMetaSchema to base your custom JsonMetaSchema on. + * @param blueprint the Dialect to base your custom Dialect on. * @return a builder instance preconfigured to be the same as blueprint, but * with a different uri. */ - public static Builder builder(String iri, JsonMetaSchema blueprint) { + public static Builder builder(String id, Dialect blueprint) { Builder builder = builder(blueprint); - builder.iri = iri; + builder.id = id; return builder; } /** * Create a builder. * - * @param blueprint the JsonMetaSchema to base your custom JsonMetaSchema on. + * @param blueprint the Dialect to base your custom Dialect on. * @return a builder instance preconfigured to be the same as blueprint */ - public static Builder builder(JsonMetaSchema blueprint) { + public static Builder builder(Dialect blueprint) { Map vocabularies = new HashMap<>(blueprint.getVocabularies()); - return builder(blueprint.getIri()) + return builder(blueprint.getId()) .idKeyword(blueprint.idKeyword) .keywords(blueprint.builder.keywords.values()) .formats(blueprint.builder.formats.values()) - .specification(blueprint.getSpecification()) + .specificationVersion(blueprint.getSpecificationVersion()) .vocabularies(vocabularies) - .vocabularyFactory(blueprint.builder.vocabularyFactory) + .vocabularyRegistry(blueprint.builder.vocabularyRegistry) .formatKeywordFactory(blueprint.builder.formatKeywordFactory) .unknownKeywordFactory(blueprint.builder.unknownKeywordFactory) ; @@ -443,8 +420,8 @@ private static String readText(JsonNode node, String field) { return fieldNode == null ? null : fieldNode.textValue(); } - public String getIri() { - return this.iri; + public String getId() { + return this.id; } public Map getKeywords() { @@ -455,14 +432,14 @@ public Map getVocabularies() { return this.vocabularies; } - public VersionFlag getSpecification() { - return this.specification; + public SpecificationVersion getSpecificationVersion() { + return this.specificationVersion; } /** * Creates a new validator of the keyword. * - * @param validationContext the validation context + * @param schemaContext the schema context * @param schemaLocation the schema location * @param evaluationPath the evaluation path * @param keyword the keyword @@ -470,53 +447,53 @@ public VersionFlag getSpecification() { * @param parentSchema the parent schema * @return the validator */ - public JsonValidator newValidator(ValidationContext validationContext, SchemaLocation schemaLocation, - JsonNodePath evaluationPath, String keyword, JsonNode schemaNode, JsonSchema parentSchema) { + public KeywordValidator newValidator(SchemaContext schemaContext, SchemaLocation schemaLocation, + NodePath evaluationPath, String keyword, JsonNode schemaNode, Schema parentSchema) { try { Keyword kw = this.keywords.get(keyword); if (kw == null) { - if (keyword.equals(validationContext.getConfig().getErrorMessageKeyword())) { + if (keyword.equals(schemaContext.getSchemaRegistryConfig().getErrorMessageKeyword())) { return null; } - if (validationContext.getConfig().isNullableKeywordEnabled() && "nullable".equals(keyword)) { + if (schemaContext.isNullableKeywordEnabled() && "nullable".equals(keyword)) { return null; } - if (ValidatorTypeCode.DISCRIMINATOR.getValue().equals(keyword) - && validationContext.getConfig().isDiscriminatorKeywordEnabled()) { - return ValidatorTypeCode.DISCRIMINATOR.newValidator(schemaLocation, evaluationPath, schemaNode, - parentSchema, validationContext); + if (KeywordType.DISCRIMINATOR.getValue().equals(keyword) + && schemaContext.isDiscriminatorKeywordEnabled()) { + return KeywordType.DISCRIMINATOR.newValidator(schemaLocation, evaluationPath, schemaNode, + parentSchema, schemaContext); } kw = this.builder.unknownKeywordFactory != null - ? this.builder.unknownKeywordFactory.getKeyword(keyword, validationContext) - : UnknownKeywordFactory.getInstance().getKeyword(keyword, validationContext); + ? this.builder.unknownKeywordFactory.getKeyword(keyword, schemaContext) + : UnknownKeywordFactory.getInstance().getKeyword(keyword, schemaContext); if (kw == null) { return null; } } - return kw.newValidator(schemaLocation, evaluationPath, schemaNode, parentSchema, validationContext); + return kw.newValidator(schemaLocation, evaluationPath, schemaNode, parentSchema, schemaContext); } catch (InvocationTargetException e) { - if (e.getTargetException() instanceof JsonSchemaException) { + if (e.getTargetException() instanceof SchemaException) { logger.error("Error:", e); - throw (JsonSchemaException) e.getTargetException(); + throw (SchemaException) e.getTargetException(); } logger.warn("Could not load validator {}", keyword); - throw new JsonSchemaException(e.getTargetException()); - } catch (JsonSchemaException e) { + throw new SchemaException(e.getTargetException()); + } catch (SchemaException e) { throw e; } catch (Exception e) { logger.warn("Could not load validator {}", keyword); - throw new JsonSchemaException(e); + throw new SchemaException(e); } } @Override public String toString() { - return this.iri; + return this.id; } @Override public int hashCode() { - return Objects.hash(iri); + return id.hashCode(); } @Override @@ -527,7 +504,7 @@ public boolean equals(Object obj) { return false; if (getClass() != obj.getClass()) return false; - JsonMetaSchema other = (JsonMetaSchema) obj; - return Objects.equals(iri, other.iri); + Dialect other = (Dialect) obj; + return Objects.equals(id, other.id); } } diff --git a/src/main/java/com/networknt/schema/SchemaId.java b/src/main/java/com/networknt/schema/dialect/DialectId.java similarity index 57% rename from src/main/java/com/networknt/schema/SchemaId.java rename to src/main/java/com/networknt/schema/dialect/DialectId.java index 51ef06305..d5e910c6e 100644 --- a/src/main/java/com/networknt/schema/SchemaId.java +++ b/src/main/java/com/networknt/schema/dialect/DialectId.java @@ -13,36 +13,38 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.dialect; /** - * Schema Identifier used in $schema. + * The dialect id is an IRI that points to the meta-schema that can be used to + * validate schemas written for that dialect. The dialect used for a particular + * schema is indicated using the $schema keyword. */ -public class SchemaId { +public class DialectId { /** * Draft 4. */ - public static final String V4 = "http://json-schema.org/draft-04/schema#"; + public static final String DRAFT_4 = "http://json-schema.org/draft-04/schema#"; /** * Draft 6. */ - public static final String V6 = "http://json-schema.org/draft-06/schema#"; + public static final String DRAFT_6 = "http://json-schema.org/draft-06/schema#"; /** * Draft 7. */ - public static final String V7 = "http://json-schema.org/draft-07/schema#"; + public static final String DRAFT_7 = "http://json-schema.org/draft-07/schema#"; /** * Draft 2019-09. */ - public static final String V201909 = "https://json-schema.org/draft/2019-09/schema"; + public static final String DRAFT_2019_09 = "https://json-schema.org/draft/2019-09/schema"; /** * Draft 2020-12. */ - public static final String V202012 = "https://json-schema.org/draft/2020-12/schema"; + public static final String DRAFT_2020_12 = "https://json-schema.org/draft/2020-12/schema"; /** * OpenAPI 3.0. diff --git a/src/main/java/com/networknt/schema/dialect/DialectRegistry.java b/src/main/java/com/networknt/schema/dialect/DialectRegistry.java new file mode 100644 index 000000000..4c1d7d883 --- /dev/null +++ b/src/main/java/com/networknt/schema/dialect/DialectRegistry.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.networknt.schema.dialect; + +import com.networknt.schema.SchemaRegistry; + +/** + * Registry for {@link Dialect} that can be retrieved using the dialect id which + * is the IRI that indicates the meta-schema that can be used to validate the + * schema conforms to the dialect. + */ +@FunctionalInterface +public interface DialectRegistry { + /** + * Gets the dialect given the dialect id which is the IRI that indicates the + * meta-schema that can be used to validate the schema conforms to the dialect. + * + * @param dialectId the dialect id of the dialect which IRI that indicates + * the meta-schema that can be used to validate the schema + * conforms to the dialect + * @param schemaRegistry the schema registry to fetch and load unknown dialect's + * meta-schema + * @return the dialect + */ + Dialect getDialect(String dialectId, SchemaRegistry schemaRegistry); +} diff --git a/src/main/java/com/networknt/schema/dialect/Dialects.java b/src/main/java/com/networknt/schema/dialect/Dialects.java new file mode 100644 index 000000000..9095565e7 --- /dev/null +++ b/src/main/java/com/networknt/schema/dialect/Dialects.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.networknt.schema.dialect; + +/** + * The dialects. + */ +public class Dialects { + /** + * Draft 4. + * + * @return the Draft 4 dialect + */ + public static Dialect getDraft4() { + return Draft4.getInstance(); + } + + /** + * Draft 6. + * + * @return the Draft 6 dialect + */ + public static Dialect getDraft6() { + return Draft6.getInstance(); + } + + /** + * Draft 7. + * + * @return the Draft 7 dialect + */ + public static Dialect getDraft7() { + return Draft7.getInstance(); + } + + /** + * Draft 2019-09. + * + * @return the Draft 2019-09 dialect + */ + public static Dialect getDraft201909() { + return Draft201909.getInstance(); + } + + /** + * Draft 2020-12. + * + * @return the Draft 2020-12 dialect + */ + public static Dialect getDraft202012() { + return Draft202012.getInstance(); + } + + /** + * OpenAPI 3.0. + * + * @return the OpenAPI 3.0 dialect + */ + public static Dialect getOpenApi30() { + return OpenApi30.getInstance(); + } + + /** + * OpenAPI 3.1. + * + * @return the OpenAPI 3.1 dialect + */ + public static Dialect getOpenApi31() { + return OpenApi31.getInstance(); + } +} diff --git a/src/main/java/com/networknt/schema/Version201909.java b/src/main/java/com/networknt/schema/dialect/Draft201909.java similarity index 63% rename from src/main/java/com/networknt/schema/Version201909.java rename to src/main/java/com/networknt/schema/dialect/Draft201909.java index 69763f2bc..67f45119e 100644 --- a/src/main/java/com/networknt/schema/Version201909.java +++ b/src/main/java/com/networknt/schema/dialect/Draft201909.java @@ -1,15 +1,20 @@ -package com.networknt.schema; +package com.networknt.schema.dialect; import java.util.Collections; import java.util.HashMap; import java.util.Map; +import com.networknt.schema.SpecificationVersion; +import com.networknt.schema.format.Formats; +import com.networknt.schema.keyword.NonValidationKeyword; +import com.networknt.schema.keyword.KeywordType; + /** * Draft 2019-09 dialect. */ -public class Version201909 implements JsonSchemaVersion { - private static final String IRI = SchemaId.V201909; - private static final String ID = "$id"; +public class Draft201909 { + private static final String ID = DialectId.DRAFT_2019_09; + private static final String ID_KEYWORD = "$id"; private static final Map VOCABULARY; static { @@ -24,13 +29,13 @@ public class Version201909 implements JsonSchemaVersion { } private static class Holder { - private static final JsonMetaSchema INSTANCE; + private static final Dialect INSTANCE; static { - INSTANCE = JsonMetaSchema.builder(IRI) - .specification(SpecVersion.VersionFlag.V201909) - .idKeyword(ID) + INSTANCE = Dialect.builder(ID) + .specificationVersion(SpecificationVersion.DRAFT_2019_09) + .idKeyword(ID_KEYWORD) .formats(Formats.DEFAULT) - .keywords(ValidatorTypeCode.getKeywords(SpecVersion.VersionFlag.V201909)) + .keywords(KeywordType.getKeywords(SpecificationVersion.DRAFT_2019_09)) // keywords that may validly exist, but have no validation aspect to them .keywords(Collections.singletonList( new NonValidationKeyword("definitions") @@ -40,8 +45,7 @@ private static class Holder { } } - @Override - public JsonMetaSchema getInstance() { + public static Dialect getInstance() { return Holder.INSTANCE; } } diff --git a/src/main/java/com/networknt/schema/Version202012.java b/src/main/java/com/networknt/schema/dialect/Draft202012.java similarity index 65% rename from src/main/java/com/networknt/schema/Version202012.java rename to src/main/java/com/networknt/schema/dialect/Draft202012.java index 32fabc35a..e7f9cbcff 100644 --- a/src/main/java/com/networknt/schema/Version202012.java +++ b/src/main/java/com/networknt/schema/dialect/Draft202012.java @@ -1,15 +1,20 @@ -package com.networknt.schema; +package com.networknt.schema.dialect; import java.util.Collections; import java.util.HashMap; import java.util.Map; +import com.networknt.schema.SpecificationVersion; +import com.networknt.schema.format.Formats; +import com.networknt.schema.keyword.NonValidationKeyword; +import com.networknt.schema.keyword.KeywordType; + /** * Draft 2020-12 dialect. */ -public class Version202012 implements JsonSchemaVersion { - private static final String IRI = SchemaId.V202012; - private static final String ID = "$id"; +public class Draft202012 { + private static final String ID = DialectId.DRAFT_2020_12; + private static final String ID_KEYWORD = "$id"; private static final Map VOCABULARY; static { @@ -25,13 +30,13 @@ public class Version202012 implements JsonSchemaVersion { } private static class Holder { - private static final JsonMetaSchema INSTANCE; + private static final Dialect INSTANCE; static { - INSTANCE = JsonMetaSchema.builder(IRI) - .specification(SpecVersion.VersionFlag.V202012) - .idKeyword(ID) + INSTANCE = Dialect.builder(ID) + .specificationVersion(SpecificationVersion.DRAFT_2020_12) + .idKeyword(ID_KEYWORD) .formats(Formats.DEFAULT) - .keywords(ValidatorTypeCode.getKeywords(SpecVersion.VersionFlag.V202012)) + .keywords(KeywordType.getKeywords(SpecificationVersion.DRAFT_2020_12)) // keywords that may validly exist, but have no validation aspect to them .keywords(Collections.singletonList( new NonValidationKeyword("definitions") @@ -41,8 +46,7 @@ private static class Holder { } } - @Override - public JsonMetaSchema getInstance() { + public static Dialect getInstance() { return Holder.INSTANCE; } } diff --git a/src/main/java/com/networknt/schema/Version4.java b/src/main/java/com/networknt/schema/dialect/Draft4.java similarity index 61% rename from src/main/java/com/networknt/schema/Version4.java rename to src/main/java/com/networknt/schema/dialect/Draft4.java index 84ad7138a..5a55098f1 100644 --- a/src/main/java/com/networknt/schema/Version4.java +++ b/src/main/java/com/networknt/schema/dialect/Draft4.java @@ -1,22 +1,28 @@ -package com.networknt.schema; +package com.networknt.schema.dialect; import java.util.Arrays; +import com.networknt.schema.SpecificationVersion; +import com.networknt.schema.format.Formats; +import com.networknt.schema.keyword.AnnotationKeyword; +import com.networknt.schema.keyword.NonValidationKeyword; +import com.networknt.schema.keyword.KeywordType; + /** * Draft 4 dialect. */ -public class Version4 implements JsonSchemaVersion { - private static final String IRI = SchemaId.V4; - private static final String ID = "id"; +public class Draft4 { + private static final String ID = DialectId.DRAFT_4; + private static final String ID_KEYWORD = "id"; private static class Holder { - private static final JsonMetaSchema INSTANCE; + private static final Dialect INSTANCE; static { - INSTANCE = JsonMetaSchema.builder(IRI) - .specification(SpecVersion.VersionFlag.V4) - .idKeyword(ID) + INSTANCE = Dialect.builder(ID) + .specificationVersion(SpecificationVersion.DRAFT_4) + .idKeyword(ID_KEYWORD) .formats(Formats.DEFAULT) - .keywords(ValidatorTypeCode.getKeywords(SpecVersion.VersionFlag.V4)) + .keywords(KeywordType.getKeywords(SpecificationVersion.DRAFT_4)) // keywords that may validly exist, but have no validation aspect to them .keywords(Arrays.asList( new NonValidationKeyword("$schema"), @@ -34,7 +40,7 @@ private static class Holder { } } - public JsonMetaSchema getInstance() { + public static Dialect getInstance() { return Holder.INSTANCE; } } diff --git a/src/main/java/com/networknt/schema/Version6.java b/src/main/java/com/networknt/schema/dialect/Draft6.java similarity index 55% rename from src/main/java/com/networknt/schema/Version6.java rename to src/main/java/com/networknt/schema/dialect/Draft6.java index 3b308227d..0c6463139 100644 --- a/src/main/java/com/networknt/schema/Version6.java +++ b/src/main/java/com/networknt/schema/dialect/Draft6.java @@ -1,23 +1,29 @@ -package com.networknt.schema; +package com.networknt.schema.dialect; import java.util.Arrays; +import com.networknt.schema.SpecificationVersion; +import com.networknt.schema.format.Formats; +import com.networknt.schema.keyword.AnnotationKeyword; +import com.networknt.schema.keyword.NonValidationKeyword; +import com.networknt.schema.keyword.KeywordType; + /** * Draft 6 dialect. */ -public class Version6 implements JsonSchemaVersion { - private static final String IRI = SchemaId.V6; +public class Draft6 { + private static final String ID = DialectId.DRAFT_6; // Draft 6 uses "$id" - private static final String ID = "$id"; + private static final String ID_KEYWORD = "$id"; private static class Holder { - private static final JsonMetaSchema INSTANCE; + private static final Dialect INSTANCE; static { - INSTANCE = JsonMetaSchema.builder(IRI) - .specification(SpecVersion.VersionFlag.V6) - .idKeyword(ID) + INSTANCE = Dialect.builder(ID) + .specificationVersion(SpecificationVersion.DRAFT_6) + .idKeyword(ID_KEYWORD) .formats(Formats.DEFAULT) - .keywords(ValidatorTypeCode.getKeywords(SpecVersion.VersionFlag.V6)) + .keywords(KeywordType.getKeywords(SpecificationVersion.DRAFT_6)) // keywords that may validly exist, but have no validation aspect to them .keywords(Arrays.asList( new NonValidationKeyword("$schema"), @@ -33,7 +39,7 @@ private static class Holder { } } - public JsonMetaSchema getInstance() { + public static Dialect getInstance() { return Holder.INSTANCE; } } diff --git a/src/main/java/com/networknt/schema/Version7.java b/src/main/java/com/networknt/schema/dialect/Draft7.java similarity index 59% rename from src/main/java/com/networknt/schema/Version7.java rename to src/main/java/com/networknt/schema/dialect/Draft7.java index de8d2d74d..edbdc3ab5 100644 --- a/src/main/java/com/networknt/schema/Version7.java +++ b/src/main/java/com/networknt/schema/dialect/Draft7.java @@ -1,22 +1,28 @@ -package com.networknt.schema; +package com.networknt.schema.dialect; import java.util.Arrays; +import com.networknt.schema.SpecificationVersion; +import com.networknt.schema.format.Formats; +import com.networknt.schema.keyword.AnnotationKeyword; +import com.networknt.schema.keyword.NonValidationKeyword; +import com.networknt.schema.keyword.KeywordType; + /** * Draft 7 dialect. */ -public class Version7 implements JsonSchemaVersion { - private static final String IRI = SchemaId.V7; - private static final String ID = "$id"; +public class Draft7 { + private static final String ID = DialectId.DRAFT_7; + private static final String ID_KEYWORD = "$id"; private static class Holder { - private static final JsonMetaSchema INSTANCE; + private static final Dialect INSTANCE; static { - INSTANCE = JsonMetaSchema.builder(IRI) - .specification(SpecVersion.VersionFlag.V7) - .idKeyword(ID) + INSTANCE = Dialect.builder(ID) + .specificationVersion(SpecificationVersion.DRAFT_7) + .idKeyword(ID_KEYWORD) .formats(Formats.DEFAULT) - .keywords(ValidatorTypeCode.getKeywords(SpecVersion.VersionFlag.V7)) + .keywords(KeywordType.getKeywords(SpecificationVersion.DRAFT_7)) // keywords that may validly exist, but have no validation aspect to them .keywords(Arrays.asList( new NonValidationKeyword("$schema"), @@ -34,8 +40,7 @@ private static class Holder { } } - @Override - public JsonMetaSchema getInstance() { + public static Dialect getInstance() { return Holder.INSTANCE; } } diff --git a/src/main/java/com/networknt/schema/dialect/OpenApi30.java b/src/main/java/com/networknt/schema/dialect/OpenApi30.java new file mode 100644 index 000000000..62ef933e2 --- /dev/null +++ b/src/main/java/com/networknt/schema/dialect/OpenApi30.java @@ -0,0 +1,71 @@ +package com.networknt.schema.dialect; + +import java.util.Arrays; + +import com.networknt.schema.SpecificationVersion; +import com.networknt.schema.format.Formats; +import com.networknt.schema.keyword.AnnotationKeyword; +import com.networknt.schema.keyword.NonValidationKeyword; +import com.networknt.schema.keyword.KeywordType; + +/** + * OpenAPI 3.0. + */ +public class OpenApi30 { + private static final String ID = DialectId.OPENAPI_3_0; + private static final String ID_KEYWORD = "id"; + + private static class Holder { + private static final Dialect INSTANCE; + static { + INSTANCE = Dialect.builder(ID) + .specificationVersion(SpecificationVersion.DRAFT_4) + .idKeyword(ID_KEYWORD) + .formats(Formats.DEFAULT) + .keywords(Arrays.asList( + new AnnotationKeyword("title"), + KeywordType.PATTERN, + KeywordType.REQUIRED, + KeywordType.ENUM, + KeywordType.MINIMUM, + KeywordType.MAXIMUM, + KeywordType.MULTIPLE_OF, + KeywordType.MIN_LENGTH, + KeywordType.MAX_LENGTH, + KeywordType.MIN_ITEMS, + KeywordType.MAX_ITEMS, + KeywordType.UNIQUE_ITEMS, + KeywordType.MIN_PROPERTIES, + KeywordType.MAX_PROPERTIES, + + KeywordType.TYPE, + KeywordType.FORMAT, + new AnnotationKeyword("description"), + KeywordType.ITEMS_LEGACY, + KeywordType.PROPERTIES, + KeywordType.ADDITIONAL_PROPERTIES, + new AnnotationKeyword("default"), + KeywordType.ALL_OF, + KeywordType.ONE_OF, + KeywordType.ANY_OF, + KeywordType.NOT, + + new AnnotationKeyword("deprecated"), + KeywordType.DISCRIMINATOR, + new AnnotationKeyword("example"), + new AnnotationKeyword("externalDocs"), + new NonValidationKeyword("nullable"), + KeywordType.READ_ONLY, + KeywordType.WRITE_ONLY, + new AnnotationKeyword("xml"), + + KeywordType.REF + )) + .build(); + } + } + + public static Dialect getInstance() { + return Holder.INSTANCE; + } +} diff --git a/src/main/java/com/networknt/schema/oas/OpenApi31.java b/src/main/java/com/networknt/schema/dialect/OpenApi31.java similarity index 64% rename from src/main/java/com/networknt/schema/oas/OpenApi31.java rename to src/main/java/com/networknt/schema/dialect/OpenApi31.java index 69f1a50a1..a51934cb6 100644 --- a/src/main/java/com/networknt/schema/oas/OpenApi31.java +++ b/src/main/java/com/networknt/schema/dialect/OpenApi31.java @@ -1,22 +1,20 @@ -package com.networknt.schema.oas; +package com.networknt.schema.dialect; import java.util.Collections; import java.util.HashMap; import java.util.Map; -import com.networknt.schema.Formats; -import com.networknt.schema.JsonMetaSchema; -import com.networknt.schema.NonValidationKeyword; -import com.networknt.schema.SchemaId; -import com.networknt.schema.SpecVersion; -import com.networknt.schema.ValidatorTypeCode; +import com.networknt.schema.SpecificationVersion; +import com.networknt.schema.format.Formats; +import com.networknt.schema.keyword.NonValidationKeyword; +import com.networknt.schema.keyword.KeywordType; /** * OpenAPI 3.1. */ public class OpenApi31 { - private static final String IRI = SchemaId.OPENAPI_3_1; - private static final String ID = "$id"; + private static final String ID = DialectId.OPENAPI_3_1; + private static final String ID_KEYWORD = "$id"; private static final Map VOCABULARY; static { @@ -33,13 +31,13 @@ public class OpenApi31 { } private static class Holder { - private static final JsonMetaSchema INSTANCE; + private static final Dialect INSTANCE; static { - INSTANCE = JsonMetaSchema.builder(IRI) - .specification(SpecVersion.VersionFlag.V202012) - .idKeyword(ID) + INSTANCE = Dialect.builder(ID) + .specificationVersion(SpecificationVersion.DRAFT_2020_12) + .idKeyword(ID_KEYWORD) .formats(Formats.DEFAULT) - .keywords(ValidatorTypeCode.getKeywords(SpecVersion.VersionFlag.V202012)) + .keywords(KeywordType.getKeywords(SpecificationVersion.DRAFT_2020_12)) // keywords that may validly exist, but have no validation aspect to them .keywords(Collections.singletonList( new NonValidationKeyword("definitions") @@ -49,7 +47,7 @@ private static class Holder { } } - public static JsonMetaSchema getInstance() { + public static Dialect getInstance() { return Holder.INSTANCE; } } diff --git a/src/main/java/com/networknt/schema/format/AbstractFormat.java b/src/main/java/com/networknt/schema/format/AbstractFormat.java deleted file mode 100644 index 73d85e909..000000000 --- a/src/main/java/com/networknt/schema/format/AbstractFormat.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2016 Network New Technologies Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.networknt.schema.format; - -import com.networknt.schema.ExecutionContext; - -/** - * Used for Formats that do not need to use the {@link ExecutionContext}. - */ -@Deprecated -public abstract class AbstractFormat extends BaseFormat { - /** - * Constructor. - * - * @param name the name - * @param errorMessageDescription the error message description - */ - public AbstractFormat(String name, String errorMessageDescription) { - super(name, errorMessageDescription); - } - - @Override - public boolean matches(ExecutionContext executionContext, String value) { - return matches(value); - } - - abstract public boolean matches(String value); -} diff --git a/src/main/java/com/networknt/schema/format/AbstractRFC3986Format.java b/src/main/java/com/networknt/schema/format/AbstractRFC3986Format.java index b08dd9ba0..a97a053ab 100644 --- a/src/main/java/com/networknt/schema/format/AbstractRFC3986Format.java +++ b/src/main/java/com/networknt/schema/format/AbstractRFC3986Format.java @@ -5,10 +5,9 @@ import java.util.regex.Pattern; import com.networknt.schema.ExecutionContext; -import com.networknt.schema.Format; /** - * {@link AbstractFormat} for RFC 3986. + * {@link Format} for RFC 3986 Uniform Resource Identifier (URI): Generic Syntax. */ public abstract class AbstractRFC3986Format implements Format { private static final Pattern VALID = Pattern.compile("([A-Za-z0-9+-\\.]*:)?//|[A-Za-z0-9+-\\.]+:"); diff --git a/src/main/java/com/networknt/schema/format/BaseFormat.java b/src/main/java/com/networknt/schema/format/BaseFormat.java deleted file mode 100644 index d8310bb4c..000000000 --- a/src/main/java/com/networknt/schema/format/BaseFormat.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2016 Network New Technologies Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.networknt.schema.format; - -import com.networknt.schema.Format; - -/** - * Base implementation of {@link Format}. - */ -@Deprecated -public abstract class BaseFormat implements Format { - private final String name; - private final String errorMessageDescription; - - public BaseFormat(String name, String errorMessageDescription) { - this.name = name; - this.errorMessageDescription = errorMessageDescription; - } - - @Override - public String getName() { - return name; - } - - @Override - public String getErrorMessageDescription() { - return errorMessageDescription; - } -} diff --git a/src/main/java/com/networknt/schema/format/BaseFormatJsonValidator.java b/src/main/java/com/networknt/schema/format/BaseFormatJsonValidator.java deleted file mode 100644 index cda3a3be7..000000000 --- a/src/main/java/com/networknt/schema/format/BaseFormatJsonValidator.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.networknt.schema.format; - -import java.util.Map; - -import com.fasterxml.jackson.databind.JsonNode; -import com.networknt.schema.BaseJsonValidator; -import com.networknt.schema.ErrorMessageType; -import com.networknt.schema.ExecutionContext; -import com.networknt.schema.JsonNodePath; -import com.networknt.schema.JsonSchema; -import com.networknt.schema.Keyword; -import com.networknt.schema.SchemaLocation; -import com.networknt.schema.ValidationContext; -import com.networknt.schema.SpecVersion.VersionFlag; - -public abstract class BaseFormatJsonValidator extends BaseJsonValidator { - protected final boolean assertionsEnabled; - - public BaseFormatJsonValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, - JsonSchema parentSchema, ErrorMessageType errorMessageType, Keyword keyword, - ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, errorMessageType, keyword, validationContext); - VersionFlag dialect = this.validationContext.getMetaSchema().getSpecification(); - if (dialect == null || dialect.getVersionFlagValue() < VersionFlag.V201909.getVersionFlagValue()) { - assertionsEnabled = true; - } else { - // Check vocabulary - assertionsEnabled = isFormatAssertionVocabularyEnabled(dialect, - this.validationContext.getMetaSchema().getVocabularies()); - } - } - - protected boolean isFormatAssertionVocabularyEnabled() { - return isFormatAssertionVocabularyEnabled(this.validationContext.getMetaSchema().getSpecification(), - this.validationContext.getMetaSchema().getVocabularies()); - } - - protected boolean isFormatAssertionVocabularyEnabled(VersionFlag specification, Map vocabularies) { - if (VersionFlag.V202012.equals(specification)) { - String vocabulary = "https://json-schema.org/draft/2020-12/vocab/format-assertion"; - return vocabularies.containsKey(vocabulary); // doesn't matter if it is true or false - } else if (VersionFlag.V201909.equals(specification)) { - String vocabulary = "https://json-schema.org/draft/2019-09/vocab/format"; - return vocabularies.getOrDefault(vocabulary, false); - } - return false; - } - - protected boolean isAssertionsEnabled(ExecutionContext executionContext) { - if (Boolean.TRUE.equals(executionContext.getExecutionConfig().getFormatAssertionsEnabled())) { - return true; - } else if (Boolean.FALSE.equals(executionContext.getExecutionConfig().getFormatAssertionsEnabled())) { - return false; - } - return this.assertionsEnabled; - } -} diff --git a/src/main/java/com/networknt/schema/format/BaseFormatValidator.java b/src/main/java/com/networknt/schema/format/BaseFormatValidator.java new file mode 100644 index 000000000..31cda4d2b --- /dev/null +++ b/src/main/java/com/networknt/schema/format/BaseFormatValidator.java @@ -0,0 +1,56 @@ +package com.networknt.schema.format; + +import java.util.Map; + +import com.fasterxml.jackson.databind.JsonNode; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.SchemaContext; +import com.networknt.schema.SpecificationVersion; +import com.networknt.schema.keyword.BaseKeywordValidator; +import com.networknt.schema.keyword.Keyword; +import com.networknt.schema.path.NodePath; + +public abstract class BaseFormatValidator extends BaseKeywordValidator { + protected final boolean assertionsEnabled; + + public BaseFormatValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, + Schema parentSchema, Keyword keyword, + SchemaContext schemaContext) { + super(keyword, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); + SpecificationVersion dialect = this.schemaContext.getDialect().getSpecificationVersion(); + if (dialect == null || dialect.getOrder() < SpecificationVersion.DRAFT_2019_09.getOrder()) { + assertionsEnabled = true; + } else { + // Check vocabulary + assertionsEnabled = isFormatAssertionVocabularyEnabled(dialect, + this.schemaContext.getDialect().getVocabularies()); + } + } + + protected boolean isFormatAssertionVocabularyEnabled() { + return isFormatAssertionVocabularyEnabled(this.schemaContext.getDialect().getSpecificationVersion(), + this.schemaContext.getDialect().getVocabularies()); + } + + protected boolean isFormatAssertionVocabularyEnabled(SpecificationVersion specification, Map vocabularies) { + if (SpecificationVersion.DRAFT_2020_12.equals(specification)) { + String vocabulary = "https://json-schema.org/draft/2020-12/vocab/format-assertion"; + return vocabularies.containsKey(vocabulary); // doesn't matter if it is true or false + } else if (SpecificationVersion.DRAFT_2019_09.equals(specification)) { + String vocabulary = "https://json-schema.org/draft/2019-09/vocab/format"; + return vocabularies.getOrDefault(vocabulary, false); + } + return false; + } + + protected boolean isAssertionsEnabled(ExecutionContext executionContext) { + if (Boolean.TRUE.equals(executionContext.getExecutionConfig().getFormatAssertionsEnabled())) { + return true; + } else if (Boolean.FALSE.equals(executionContext.getExecutionConfig().getFormatAssertionsEnabled())) { + return false; + } + return this.assertionsEnabled; + } +} diff --git a/src/main/java/com/networknt/schema/format/DateFormat.java b/src/main/java/com/networknt/schema/format/DateFormat.java index c5d921c9e..3e30e499b 100644 --- a/src/main/java/com/networknt/schema/format/DateFormat.java +++ b/src/main/java/com/networknt/schema/format/DateFormat.java @@ -4,7 +4,6 @@ import java.time.format.DateTimeParseException; import com.networknt.schema.ExecutionContext; -import com.networknt.schema.Format; /** * Format for date. diff --git a/src/main/java/com/networknt/schema/format/DateTimeFormat.java b/src/main/java/com/networknt/schema/format/DateTimeFormat.java index a739c9c71..a12faa665 100644 --- a/src/main/java/com/networknt/schema/format/DateTimeFormat.java +++ b/src/main/java/com/networknt/schema/format/DateTimeFormat.java @@ -10,7 +10,6 @@ import com.ethlo.time.ITU; import com.ethlo.time.LeapSecondException; import com.networknt.schema.ExecutionContext; -import com.networknt.schema.Format; import com.networknt.schema.utils.Classes; /** diff --git a/src/main/java/com/networknt/schema/format/DurationFormat.java b/src/main/java/com/networknt/schema/format/DurationFormat.java index ca8d0e1fb..0d1f04411 100644 --- a/src/main/java/com/networknt/schema/format/DurationFormat.java +++ b/src/main/java/com/networknt/schema/format/DurationFormat.java @@ -4,8 +4,7 @@ import java.util.regex.Pattern; import com.networknt.schema.ExecutionContext; -import com.networknt.schema.Format; -import com.networknt.schema.ValidationContext; +import com.networknt.schema.SchemaContext; /** * Format for duration. @@ -17,7 +16,7 @@ public class DurationFormat implements Format { private static final Pattern LAX = Pattern.compile("^(?:[-+]?)P(?:[-+]?[0-9]+Y)?(?:[-+]?[0-9]+M)?(?:[-+]?[0-9]+W)?(?:[-+]?[0-9]+D)?(?:T(?:[-+]?[0-9]+H)?(?:[-+]?[0-9]+M)?(?:[-+]?[0-9]+(?:[.,][0-9]{0,9})?S)?)?$", Pattern.CASE_INSENSITIVE); @Override - public boolean matches(ExecutionContext executionContext, ValidationContext validationContext, String duration) { + public boolean matches(ExecutionContext executionContext, SchemaContext schemaContext, String duration) { if (null == duration) { return true; } @@ -26,13 +25,13 @@ public boolean matches(ExecutionContext executionContext, ValidationContext vali return false; } - Pattern pattern = isStrictValidation(validationContext) ? STRICT : LAX; + Pattern pattern = isStrictValidation(schemaContext) ? STRICT : LAX; Matcher matcher = pattern.matcher(duration); return matcher.matches(); } - protected boolean isStrictValidation(ValidationContext validationContext) { - return validationContext.getConfig().isStrict(DURATION); + protected boolean isStrictValidation(SchemaContext schemaContext) { + return schemaContext.getSchemaRegistryConfig().isStrict(DURATION); } @Override diff --git a/src/main/java/com/networknt/schema/format/EmailFormat.java b/src/main/java/com/networknt/schema/format/EmailFormat.java index 3a329e4d0..86cbb5106 100644 --- a/src/main/java/com/networknt/schema/format/EmailFormat.java +++ b/src/main/java/com/networknt/schema/format/EmailFormat.java @@ -18,7 +18,6 @@ import com.networknt.org.apache.commons.validator.routines.EmailValidator; import com.networknt.schema.ExecutionContext; -import com.networknt.schema.Format; /** * Format for email. diff --git a/src/main/java/com/networknt/schema/Format.java b/src/main/java/com/networknt/schema/format/Format.java similarity index 64% rename from src/main/java/com/networknt/schema/Format.java rename to src/main/java/com/networknt/schema/format/Format.java index f1632c0f4..cf8064c61 100644 --- a/src/main/java/com/networknt/schema/Format.java +++ b/src/main/java/com/networknt/schema/format/Format.java @@ -14,11 +14,18 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.format; import java.util.function.Supplier; import com.fasterxml.jackson.databind.JsonNode; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.MessageSourceError; +import com.networknt.schema.SchemaContext; +import com.networknt.schema.keyword.FormatValidator; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.utils.JsonType; +import com.networknt.schema.utils.TypeFactory; /** * Used to implement the various formats for the format keyword. @@ -39,10 +46,10 @@ public interface Format { * See jsv-messages.properties. *

* The following are the arguments.
- * {0} The instance location
- * {1} The format name
- * {2} The error message description
- * {3} The input value + * {0} The format name
+ * {1} The input value + *

+ * Note that the default localized messages do not use the input value. * * @return the message key */ @@ -50,20 +57,6 @@ default String getMessageKey() { return "format"; } - /** - * Gets the error message description. - *

- * Deprecated. Override getMessageKey() and set the localized message in the - * resource bundle or message source. - * - * @return the error message description. - */ - @Deprecated - default String getErrorMessageDescription() { - return ""; - } - - /** * Determines if the value matches the format. *

@@ -81,11 +74,11 @@ default boolean matches(ExecutionContext executionContext, String value) { * Determines if the value matches the format. * * @param executionContext the execution context - * @param validationContext the validation context + * @param schemaContext the schema context * @param value to match * @return true if matches */ - default boolean matches(ExecutionContext executionContext, ValidationContext validationContext, String value) { + default boolean matches(ExecutionContext executionContext, SchemaContext schemaContext, String value) { return matches(executionContext, value); } @@ -93,16 +86,16 @@ default boolean matches(ExecutionContext executionContext, ValidationContext val * Determines if the value matches the format. * * @param executionContext the execution context - * @param validationContext the validation context + * @param schemaContext the schema context * @param value to match * @return true if matches */ - default boolean matches(ExecutionContext executionContext, ValidationContext validationContext, JsonNode value) { - JsonType nodeType = TypeFactory.getValueNodeType(value, validationContext.getConfig()); + default boolean matches(ExecutionContext executionContext, SchemaContext schemaContext, JsonNode value) { + JsonType nodeType = TypeFactory.getValueNodeType(value, schemaContext.getSchemaRegistryConfig()); if (nodeType != JsonType.STRING) { return true; } - return matches(executionContext, validationContext, value.textValue()); + return matches(executionContext, schemaContext, value.textValue()); } /** @@ -111,7 +104,7 @@ default boolean matches(ExecutionContext executionContext, ValidationContext val * This can be implemented for non-string node types. * * @param executionContext the execution context - * @param validationContext the validation context + * @param schemaContext the schema context * @param node the node * @param rootNode the root node * @param instanceLocation the instance location @@ -119,9 +112,9 @@ default boolean matches(ExecutionContext executionContext, ValidationContext val * @param formatValidator the format validator * @return true if matches */ - default boolean matches(ExecutionContext executionContext, ValidationContext validationContext, JsonNode node, - JsonNode rootNode, JsonNodePath instanceLocation, boolean assertionsEnabled, FormatValidator formatValidator) { - return matches(executionContext, validationContext, node); + default boolean matches(ExecutionContext executionContext, SchemaContext schemaContext, JsonNode node, + JsonNode rootNode, NodePath instanceLocation, boolean assertionsEnabled, FormatValidator formatValidator) { + return matches(executionContext, schemaContext, node); } /** @@ -130,7 +123,7 @@ default boolean matches(ExecutionContext executionContext, ValidationContext val * This is the most flexible method to implement. * * @param executionContext the execution context - * @param validationContext the validation context + * @param schemaContext the schema context * @param node the node * @param rootNode the root node * @param instanceLocation the instance locaiton @@ -138,15 +131,15 @@ default boolean matches(ExecutionContext executionContext, ValidationContext val * @param message the message builder * @param formatValidator the format validator */ - default void validate(ExecutionContext executionContext, ValidationContext validationContext, - JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation, boolean assertionsEnabled, - Supplier message, + default void validate(ExecutionContext executionContext, SchemaContext schemaContext, + JsonNode node, JsonNode rootNode, NodePath instanceLocation, boolean assertionsEnabled, + Supplier message, FormatValidator formatValidator) { if (assertionsEnabled) { - if (!matches(executionContext, validationContext, node, rootNode, instanceLocation, assertionsEnabled, + if (!matches(executionContext, schemaContext, node, rootNode, instanceLocation, assertionsEnabled, formatValidator)) { executionContext.addError(message.get() - .arguments(this.getName(), this.getErrorMessageDescription(), node.asText()).build()); + .arguments(this.getName(), node.asText()).build()); } } } diff --git a/src/main/java/com/networknt/schema/Formats.java b/src/main/java/com/networknt/schema/format/Formats.java similarity index 82% rename from src/main/java/com/networknt/schema/Formats.java rename to src/main/java/com/networknt/schema/format/Formats.java index c9dd0bda9..7ef566e17 100644 --- a/src/main/java/com/networknt/schema/Formats.java +++ b/src/main/java/com/networknt/schema/format/Formats.java @@ -13,27 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.format; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import com.networknt.schema.format.DateFormat; -import com.networknt.schema.format.DateTimeFormat; -import com.networknt.schema.format.DurationFormat; -import com.networknt.schema.format.EmailFormat; -import com.networknt.schema.format.IPv6Format; -import com.networknt.schema.format.IdnEmailFormat; -import com.networknt.schema.format.IdnHostnameFormat; -import com.networknt.schema.format.IriFormat; -import com.networknt.schema.format.IriReferenceFormat; -import com.networknt.schema.format.PatternFormat; -import com.networknt.schema.format.RegexFormat; -import com.networknt.schema.format.TimeFormat; -import com.networknt.schema.format.UriFormat; -import com.networknt.schema.format.UriReferenceFormat; - /** * Formats. */ diff --git a/src/main/java/com/networknt/schema/format/IPv6Format.java b/src/main/java/com/networknt/schema/format/IPv6Format.java index ddcd2ce55..15298cb33 100644 --- a/src/main/java/com/networknt/schema/format/IPv6Format.java +++ b/src/main/java/com/networknt/schema/format/IPv6Format.java @@ -3,7 +3,6 @@ import java.util.regex.Pattern; import com.networknt.schema.ExecutionContext; -import com.networknt.schema.Format; /** * Format for ipv6. diff --git a/src/main/java/com/networknt/schema/format/IdnEmailFormat.java b/src/main/java/com/networknt/schema/format/IdnEmailFormat.java index 855ba2180..880071082 100644 --- a/src/main/java/com/networknt/schema/format/IdnEmailFormat.java +++ b/src/main/java/com/networknt/schema/format/IdnEmailFormat.java @@ -2,7 +2,6 @@ import com.networknt.org.apache.commons.validator.routines.EmailValidator; import com.networknt.schema.ExecutionContext; -import com.networknt.schema.Format; /** * Format for idn-email. diff --git a/src/main/java/com/networknt/schema/format/IdnHostnameFormat.java b/src/main/java/com/networknt/schema/format/IdnHostnameFormat.java index 7ba0e8606..e5f46808f 100644 --- a/src/main/java/com/networknt/schema/format/IdnHostnameFormat.java +++ b/src/main/java/com/networknt/schema/format/IdnHostnameFormat.java @@ -1,7 +1,6 @@ package com.networknt.schema.format; import com.networknt.schema.ExecutionContext; -import com.networknt.schema.Format; import com.networknt.schema.utils.RFC5892; /** diff --git a/src/main/java/com/networknt/schema/format/PatternFormat.java b/src/main/java/com/networknt/schema/format/PatternFormat.java index 79fa91753..c980da7ab 100644 --- a/src/main/java/com/networknt/schema/format/PatternFormat.java +++ b/src/main/java/com/networknt/schema/format/PatternFormat.java @@ -19,7 +19,6 @@ import java.util.regex.Pattern; import com.networknt.schema.ExecutionContext; -import com.networknt.schema.Format; /** * Format using a regex pattern. @@ -28,7 +27,6 @@ public class PatternFormat implements Format { private final String name; private final Pattern pattern; private final String messageKey; - private final String errorMessageDescription; /** * Constructor. @@ -37,19 +35,9 @@ public class PatternFormat implements Format { * * @param name the name * @param regex the regex - * @param errorMessageDescription the error message description */ - @Deprecated - public PatternFormat(String name, String regex, String errorMessageDescription) { + private PatternFormat(String name, String regex, String messageKey) { this.name = name; - this.errorMessageDescription = errorMessageDescription != null ? errorMessageDescription : regex; - this.messageKey = "format"; - this.pattern = Pattern.compile(regex); - } - - private PatternFormat(String name, String regex, String errorMessageDescription, String messageKey) { - this.name = name; - this.errorMessageDescription = errorMessageDescription != null ? errorMessageDescription : regex; this.messageKey = messageKey; this.pattern = Pattern.compile(regex); } @@ -63,7 +51,7 @@ private PatternFormat(String name, String regex, String errorMessageDescription, * @return the pattern format */ public static PatternFormat of(String name, String regex, String messageKey) { - return new PatternFormat(name, regex, null, messageKey != null ? messageKey : "format"); + return new PatternFormat(name, regex, messageKey != null ? messageKey : "format"); } @Override @@ -80,9 +68,4 @@ public String getName() { public String getMessageKey() { return this.messageKey; } - - @Override - public String getErrorMessageDescription() { - return this.errorMessageDescription; - } } diff --git a/src/main/java/com/networknt/schema/format/RegexFormat.java b/src/main/java/com/networknt/schema/format/RegexFormat.java index 191e6364f..dbb920cf8 100644 --- a/src/main/java/com/networknt/schema/format/RegexFormat.java +++ b/src/main/java/com/networknt/schema/format/RegexFormat.java @@ -14,8 +14,7 @@ package com.networknt.schema.format; import com.networknt.schema.ExecutionContext; -import com.networknt.schema.Format; -import com.networknt.schema.ValidationContext; +import com.networknt.schema.SchemaContext; import com.networknt.schema.regex.RegularExpression; /** @@ -23,10 +22,10 @@ */ public class RegexFormat implements Format { @Override - public boolean matches(ExecutionContext executionContext, ValidationContext validationContext, String value) { + public boolean matches(ExecutionContext executionContext, SchemaContext schemaContext, String value) { if (null == value) return true; try { - RegularExpression.compile(value, validationContext); + RegularExpression.compile(value, schemaContext); return true; } catch (RuntimeException e) { return false; diff --git a/src/main/java/com/networknt/schema/format/TimeFormat.java b/src/main/java/com/networknt/schema/format/TimeFormat.java index 17327ddc5..7b539b9ea 100644 --- a/src/main/java/com/networknt/schema/format/TimeFormat.java +++ b/src/main/java/com/networknt/schema/format/TimeFormat.java @@ -20,7 +20,6 @@ import java.time.temporal.TemporalAccessor; import com.networknt.schema.ExecutionContext; -import com.networknt.schema.Format; import static java.time.format.DateTimeFormatter.ISO_LOCAL_TIME; import static java.time.temporal.ChronoField.*; diff --git a/src/main/java/com/networknt/schema/AbstractKeyword.java b/src/main/java/com/networknt/schema/keyword/AbstractKeyword.java similarity index 97% rename from src/main/java/com/networknt/schema/AbstractKeyword.java rename to src/main/java/com/networknt/schema/keyword/AbstractKeyword.java index 3b6945d9f..3683b2123 100644 --- a/src/main/java/com/networknt/schema/AbstractKeyword.java +++ b/src/main/java/com/networknt/schema/keyword/AbstractKeyword.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import java.util.Objects; diff --git a/src/main/java/com/networknt/schema/AbstractJsonValidator.java b/src/main/java/com/networknt/schema/keyword/AbstractKeywordValidator.java similarity index 69% rename from src/main/java/com/networknt/schema/AbstractJsonValidator.java rename to src/main/java/com/networknt/schema/keyword/AbstractKeywordValidator.java index bf3fc5d53..9de8740fe 100644 --- a/src/main/java/com/networknt/schema/AbstractJsonValidator.java +++ b/src/main/java/com/networknt/schema/keyword/AbstractKeywordValidator.java @@ -14,35 +14,49 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import java.util.function.Consumer; import com.fasterxml.jackson.databind.JsonNode; -import com.networknt.schema.annotation.JsonNodeAnnotation; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.annotation.Annotation; +import com.networknt.schema.path.NodePath; /** - * Base {@link JsonValidator}. + * Abstract {@link KeywordValidator}. */ -public abstract class AbstractJsonValidator implements JsonValidator { - private final SchemaLocation schemaLocation; - private final JsonNode schemaNode; - private final JsonNodePath evaluationPath; +public abstract class AbstractKeywordValidator implements KeywordValidator { private final String keyword; + protected final JsonNode schemaNode; + protected final SchemaLocation schemaLocation; + + protected final NodePath evaluationPath; /** * Constructor. - * - * @param schemaLocation the schema location - * @param evaluationPath the evaluation path * @param keyword the keyword * @param schemaNode the schema node + * @param schemaLocation the schema location + * @param evaluationPath the evaluation path */ - public AbstractJsonValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, Keyword keyword, JsonNode schemaNode) { + public AbstractKeywordValidator(String keyword, JsonNode schemaNode, SchemaLocation schemaLocation, NodePath evaluationPath) { + this.keyword = keyword; + this.schemaNode = schemaNode; this.schemaLocation = schemaLocation; this.evaluationPath = evaluationPath; - this.keyword = keyword.getValue(); - this.schemaNode = schemaNode; + } + + /** + * Constructor. + * @param keyword the keyword + * @param schemaNode the schema node + * @param schemaLocation the schema location + * @param evaluationPath the evaluation path + */ + public AbstractKeywordValidator(Keyword keyword, JsonNode schemaNode, SchemaLocation schemaLocation, NodePath evaluationPath) { + this(keyword.getValue(), schemaNode, schemaLocation, evaluationPath); } @Override @@ -51,7 +65,7 @@ public SchemaLocation getSchemaLocation() { } @Override - public JsonNodePath getEvaluationPath() { + public NodePath getEvaluationPath() { return evaluationPath; } @@ -102,8 +116,8 @@ protected boolean collectAnnotations(ExecutionContext executionContext, String k * @param executionContext the execution context * @param customizer to customize the annotation */ - protected void putAnnotation(ExecutionContext executionContext, Consumer customizer) { - JsonNodeAnnotation.Builder builder = JsonNodeAnnotation.builder().evaluationPath(this.evaluationPath) + protected void putAnnotation(ExecutionContext executionContext, Consumer customizer) { + Annotation.Builder builder = Annotation.builder().evaluationPath(this.evaluationPath) .schemaLocation(this.schemaLocation).keyword(getKeyword()); customizer.accept(builder); executionContext.getAnnotations().put(builder.build()); diff --git a/src/main/java/com/networknt/schema/AdditionalPropertiesValidator.java b/src/main/java/com/networknt/schema/keyword/AdditionalPropertiesValidator.java similarity index 80% rename from src/main/java/com/networknt/schema/AdditionalPropertiesValidator.java rename to src/main/java/com/networknt/schema/keyword/AdditionalPropertiesValidator.java index 6b498c4fb..6359ef392 100644 --- a/src/main/java/com/networknt/schema/AdditionalPropertiesValidator.java +++ b/src/main/java/com/networknt/schema/keyword/AdditionalPropertiesValidator.java @@ -14,15 +14,17 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import com.fasterxml.jackson.databind.JsonNode; -import com.networknt.schema.annotation.JsonNodeAnnotation; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.SchemaContext; +import com.networknt.schema.annotation.Annotation; +import com.networknt.schema.path.NodePath; import com.networknt.schema.regex.RegularExpression; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; @@ -33,27 +35,25 @@ import java.util.Set; /** - * {@link JsonValidator} for additionalProperties. + * {@link KeywordValidator} for additionalProperties. */ -public class AdditionalPropertiesValidator extends BaseJsonValidator { - private static final Logger logger = LoggerFactory.getLogger(AdditionalPropertiesValidator.class); - +public class AdditionalPropertiesValidator extends BaseKeywordValidator { private final boolean allowAdditionalProperties; - private final JsonSchema additionalPropertiesSchema; + private final Schema additionalPropertiesSchema; private final Set allowedProperties; private final List patternProperties; private Boolean hasUnevaluatedPropertiesValidator; - public AdditionalPropertiesValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, JsonSchema parentSchema, - ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.ADDITIONAL_PROPERTIES, validationContext); + public AdditionalPropertiesValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, Schema parentSchema, + SchemaContext schemaContext) { + super(KeywordType.ADDITIONAL_PROPERTIES, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); if (schemaNode.isBoolean()) { allowAdditionalProperties = schemaNode.booleanValue(); additionalPropertiesSchema = null; } else if (schemaNode.isObject()) { allowAdditionalProperties = true; - additionalPropertiesSchema = validationContext.newSchema(schemaLocation, evaluationPath, schemaNode, parentSchema); + additionalPropertiesSchema = schemaContext.newSchema(schemaLocation, evaluationPath, schemaNode, parentSchema); } else { allowAdditionalProperties = false; additionalPropertiesSchema = null; @@ -73,7 +73,7 @@ public AdditionalPropertiesValidator(SchemaLocation schemaLocation, JsonNodePath if (patternPropertiesNode != null) { this.patternProperties = new ArrayList<>(patternPropertiesNode.size()); for (Iterator it = patternPropertiesNode.fieldNames(); it.hasNext(); ) { - patternProperties.add(RegularExpression.compile(it.next(), validationContext)); + patternProperties.add(RegularExpression.compile(it.next(), schemaContext)); } } else { this.patternProperties = Collections.emptyList(); @@ -82,13 +82,12 @@ public AdditionalPropertiesValidator(SchemaLocation schemaLocation, JsonNodePath @Override public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, - JsonNodePath instanceLocation) { + NodePath instanceLocation) { validate(executionContext, node, rootNode, instanceLocation, false); } protected void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, - JsonNodePath instanceLocation, boolean walk) { - debug(logger, executionContext, node, rootNode, instanceLocation); + NodePath instanceLocation, boolean walk) { if (!node.isObject()) { // ignore no object return; @@ -117,10 +116,10 @@ protected void validate(ExecutionContext executionContext, JsonNode node, JsonNo } if (!allowedProperties.contains(pname) && !handledByPatternProperties(pname)) { if (!allowAdditionalProperties) { - executionContext.addError(message().instanceNode(node).property(pname) + executionContext.addError(error().instanceNode(node).property(pname) .instanceLocation(instanceLocation) .locale(executionContext.getExecutionConfig().getLocale()) - .failFast(executionContext.isFailFast()).arguments(pname).build()); + .arguments(pname).build()); } else { if (additionalPropertiesSchema != null) { if (!walk) { @@ -135,7 +134,7 @@ protected void validate(ExecutionContext executionContext, JsonNode node, JsonNo } } if (collectAnnotations) { - executionContext.getAnnotations().put(JsonNodeAnnotation.builder().instanceLocation(instanceLocation) + executionContext.getAnnotations().put(Annotation.builder().instanceLocation(instanceLocation) .evaluationPath(this.evaluationPath).schemaLocation(this.schemaLocation).keyword(getKeyword()) .value(matchedInstancePropertyNames != null ? matchedInstancePropertyNames : Collections.emptySet()) .build()); @@ -143,7 +142,7 @@ protected void validate(ExecutionContext executionContext, JsonNode node, JsonNo } @Override - public void walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation, boolean shouldValidateSchema) { + public void walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation, boolean shouldValidateSchema) { if (shouldValidateSchema && node != null) { validate(executionContext, node, rootNode, instanceLocation, true); return; @@ -193,7 +192,7 @@ private boolean hasUnevaluatedPropertiesValidator() { } @Override - public void preloadJsonSchema() { + public void preloadSchema() { if(additionalPropertiesSchema != null) { additionalPropertiesSchema.initializeValidators(); } diff --git a/src/main/java/com/networknt/schema/keyword/AllOfValidator.java b/src/main/java/com/networknt/schema/keyword/AllOfValidator.java new file mode 100644 index 000000000..279cbd62b --- /dev/null +++ b/src/main/java/com/networknt/schema/keyword/AllOfValidator.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2016 Network New Technologies Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.networknt.schema.keyword; + +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.databind.JsonNode; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaContext; +import com.networknt.schema.SchemaException; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.utils.JsonType; +import com.networknt.schema.utils.TypeFactory; + +/** + * {@link KeywordValidator} for allOf. + */ +public class AllOfValidator extends BaseKeywordValidator { + private final List schemas; + + public AllOfValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, + Schema parentSchema, SchemaContext schemaContext) { + super(KeywordType.ALL_OF, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); + if (!schemaNode.isArray()) { + JsonType nodeType = TypeFactory.getValueNodeType(schemaNode, this.schemaContext.getSchemaRegistryConfig()); + throw new SchemaException(error().instanceNode(schemaNode).instanceLocation(schemaLocation.getFragment()) + .messageKey("type").arguments(nodeType.toString(), "array").build()); + } + int size = schemaNode.size(); + this.schemas = new ArrayList<>(size); + for (int i = 0; i < size; i++) { + this.schemas.add(schemaContext.newSchema(schemaLocation.append(i), evaluationPath.append(i), + schemaNode.get(i), parentSchema)); + } + } + + @Override + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, + NodePath instanceLocation) { + validate(executionContext, node, rootNode, instanceLocation, false); + } + + protected void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, + NodePath instanceLocation, boolean walk) { + for (Schema schema : this.schemas) { + if (!walk) { + schema.validate(executionContext, node, rootNode, instanceLocation); + } else { + schema.walk(executionContext, node, rootNode, instanceLocation, true); + } + } + } + + @Override + public void walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation, + boolean shouldValidateSchema) { + if (shouldValidateSchema && node != null) { + validate(executionContext, node, rootNode, instanceLocation, true); + return; + } + for (Schema schema : this.schemas) { + // Walk through the schema + schema.walk(executionContext, node, rootNode, instanceLocation, false); + } + } + + @Override + public void preloadSchema() { + preloadSchemas(this.schemas); + } +} diff --git a/src/main/java/com/networknt/schema/AnnotationKeyword.java b/src/main/java/com/networknt/schema/keyword/AnnotationKeyword.java similarity index 67% rename from src/main/java/com/networknt/schema/AnnotationKeyword.java rename to src/main/java/com/networknt/schema/keyword/AnnotationKeyword.java index 65aae35ee..1a0b17af0 100644 --- a/src/main/java/com/networknt/schema/AnnotationKeyword.java +++ b/src/main/java/com/networknt/schema/keyword/AnnotationKeyword.java @@ -14,23 +14,28 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import com.fasterxml.jackson.databind.JsonNode; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.SchemaContext; /** * Used for Keywords that have no validation aspect, but are part of the metaschema, where annotations may need to be collected. */ public class AnnotationKeyword extends AbstractKeyword { - private static final class Validator extends AbstractJsonValidator { - public Validator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, - JsonSchema parentSchema, ValidationContext validationContext, Keyword keyword) { - super(schemaLocation, evaluationPath, keyword, schemaNode); + private static final class Validator extends AbstractKeywordValidator { + public Validator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, + Schema parentSchema, SchemaContext schemaContext, Keyword keyword) { + super(keyword, schemaNode, schemaLocation, evaluationPath); } @Override - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) { + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation) { if (collectAnnotations(executionContext)) { Object value = getAnnotationValue(getSchemaNode()); if (value != null) { @@ -57,8 +62,8 @@ public AnnotationKeyword(String keyword) { } @Override - public JsonValidator newValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, - JsonSchema parentSchema, ValidationContext validationContext) { - return new Validator(schemaLocation, evaluationPath, schemaNode, parentSchema, validationContext, this); + public KeywordValidator newValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, + Schema parentSchema, SchemaContext schemaContext) { + return new Validator(schemaLocation, evaluationPath, schemaNode, parentSchema, schemaContext, this); } } diff --git a/src/main/java/com/networknt/schema/keyword/AnyOfValidator.java b/src/main/java/com/networknt/schema/keyword/AnyOfValidator.java new file mode 100644 index 000000000..45c1bf72a --- /dev/null +++ b/src/main/java/com/networknt/schema/keyword/AnyOfValidator.java @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2016 Network New Technologies Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.networknt.schema.keyword; + +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.databind.JsonNode; +import com.networknt.schema.Error; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaContext; +import com.networknt.schema.SchemaException; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.utils.JsonType; +import com.networknt.schema.utils.TypeFactory; + +/** + * {@link KeywordValidator} for anyOf. + */ +public class AnyOfValidator extends BaseKeywordValidator { + private final List schemas; + + private Boolean canShortCircuit = null; + + public AnyOfValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, + Schema parentSchema, SchemaContext schemaContext) { + super(KeywordType.ANY_OF, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); + if (!schemaNode.isArray()) { + JsonType nodeType = TypeFactory.getValueNodeType(schemaNode, this.schemaContext.getSchemaRegistryConfig()); + throw new SchemaException(error().instanceNode(schemaNode).instanceLocation(schemaLocation.getFragment()) + .messageKey("type").arguments(nodeType.toString(), "array").build()); + } + int size = schemaNode.size(); + this.schemas = new ArrayList<>(size); + for (int i = 0; i < size; i++) { + this.schemas.add(schemaContext.newSchema(schemaLocation.append(i), evaluationPath.append(i), + schemaNode.get(i), parentSchema)); + } + } + + @Override + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, + NodePath instanceLocation) { + validate(executionContext, node, rootNode, instanceLocation, false); + } + + protected void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, + NodePath instanceLocation, boolean walk) { + int numberOfValidSubSchemas = 0; + List existingErrors = executionContext.getErrors(); + List allErrors = null; // Keeps track of all the errors for reporting if in the end none of the schemas + // match + List discriminatorErrors = null; // The errors from the sub schema that match the discriminator + List subSchemaErrors = new ArrayList<>(); // Temporary errors from each sub schema execution + executionContext.setErrors(subSchemaErrors); + + // Save flag as nested schema evaluation shouldn't trigger fail fast + boolean failFast = executionContext.isFailFast(); + try { + executionContext.setFailFast(false); + for (Schema schema : this.schemas) { + subSchemaErrors.clear(); // Reuse and clear for each run + TypeValidator typeValidator = schema.getTypeValidator(); + if (typeValidator != null) { + // If schema has type validator and node type doesn't match with schemaType then + // ignore it + // For union type, it is a must to call TypeValidator + if (typeValidator.getSchemaType() != JsonType.UNION && !typeValidator.equalsToSchemaType(node)) { + typeValidator.validate(executionContext, node, rootNode, instanceLocation); + if (allErrors == null) { + allErrors = new ArrayList<>(); + } + allErrors.addAll(subSchemaErrors); + continue; + } + } + if (!walk) { + schema.validate(executionContext, node, rootNode, instanceLocation); + } else { + schema.walk(executionContext, node, rootNode, instanceLocation, true); + } + + // check if any validation errors have occurred + if (subSchemaErrors.isEmpty()) { + // we found a valid subschema, so increase counter + numberOfValidSubSchemas++; + } + + if (subSchemaErrors.isEmpty() && (!this.schemaContext.isDiscriminatorKeywordEnabled()) + && canShortCircuit() && canShortCircuit(executionContext)) { + // Successful so return only the existing errors, ie. no new errors + executionContext.setErrors(existingErrors); + return; + } else if (this.schemaContext.isDiscriminatorKeywordEnabled()) { + boolean discriminatorMatchFound = false; + DiscriminatorState discriminator = executionContext.getDiscriminatorMapping().get(instanceLocation); + JsonNode refNode = schema.getSchemaNode().get("$ref"); + if (discriminator != null && refNode != null) { + discriminatorMatchFound = discriminator.matches(refNode.asText()); + } + if (discriminatorMatchFound) { + /* + * Note that discriminator cannot change the outcome of the evaluation but can + * be used to filter off any additional messages + */ + if (!subSchemaErrors.isEmpty()) { + /* + * This means that the discriminated value has errors and doesn't match so these + * errors are the only ones that will be reported *IF* there are no other + * schemas that successfully validate to meet the requirement of anyOf. + * + * If there are any successful schemas as per anyOf, all these errors will be + * discarded. + */ + discriminatorErrors = new ArrayList<>(subSchemaErrors); + allErrors = null; // This is no longer needed + } + } + } + /* + * This adds all the errors for this schema to the list that contains all the + * errors for later reporting. + * + * There's no need to add these if there was a discriminator match with errors + * as only the discriminator errors will be reported if all the schemas fail. + */ + if (!subSchemaErrors.isEmpty() && discriminatorErrors == null) { + if (allErrors == null) { + allErrors = new ArrayList<>(); + } + allErrors.addAll(subSchemaErrors); + } + } + } finally { + // Restore flag + executionContext.setFailFast(failFast); + } + + if (this.schemaContext.isDiscriminatorKeywordEnabled()) { + /* + * The only case where the discriminator can change the outcome of the result is + * if the discriminator value does not match an implicit or explicit mapping + */ + /* + * If the discriminator value does not match an implicit or explicit mapping, no + * schema can be determined and validation SHOULD fail. Mapping keys MUST be + * string values, but tooling MAY convert response values to strings for + * comparison. + * + * https://spec.openapis.org/oas/v3.1.2#examples-0 + */ + DiscriminatorState state = executionContext.getDiscriminatorMapping().get(instanceLocation); + if (state != null && !state.hasMatchedSchema() && state.hasDiscriminatingValue()) { + // The check for state.hasDiscriminatingValue is due to issue 988 + // Note that this is related to the DiscriminatorValidator by default not + // generating an assertion + // if the discriminatingValue is not set in the payload + existingErrors.add(error().keyword("discriminator").instanceNode(node) + .instanceLocation(instanceLocation).locale(executionContext.getExecutionConfig().getLocale()) + .messageKey("discriminator.anyOf.no_match_found").arguments(state.getDiscriminatingValue()) + .build()); + } + } + + if (numberOfValidSubSchemas >= 1) { + // Successful so return only the existing errors, ie. no new errors + executionContext.setErrors(existingErrors); + } else { + if (discriminatorErrors != null) { + // If errors are present matching the discriminator, only these errors should be + // reported + existingErrors.addAll(discriminatorErrors); + } else if (allErrors != null) { + // As the anyOf has failed, report all the errors + existingErrors.addAll(allErrors); + } + executionContext.setErrors(existingErrors); + } + } + + @Override + public void walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation, + boolean shouldValidateSchema) { + if (shouldValidateSchema && node != null) { + validate(executionContext, node, rootNode, instanceLocation, true); + return; + } + for (Schema schema : this.schemas) { + schema.walk(executionContext, node, rootNode, instanceLocation, false); + } + } + + /** + * If annotation collection is enabled cannot short circuit. + * + * @see anyOf + * @param executionContext the execution context + * @return true if can short circuit + */ + protected boolean canShortCircuit(ExecutionContext executionContext) { + return !executionContext.getExecutionConfig().isAnnotationCollectionEnabled(); + } + + /** + * If annotations are require for evaluation cannot short circuit. + * + * @return true if can short circuit + */ + protected boolean canShortCircuit() { + if (this.canShortCircuit == null) { + boolean canShortCircuit = true; + for (KeywordValidator validator : getEvaluationParentSchema().getValidators()) { + if ("unevaluatedProperties".equals(validator.getKeyword()) + || "unevaluatedItems".equals(validator.getKeyword())) { + canShortCircuit = false; + } + } + this.canShortCircuit = canShortCircuit; + } + return this.canShortCircuit; + } + + @Override + public void preloadSchema() { + preloadSchemas(this.schemas); + canShortCircuit(); // cache flag + } +} \ No newline at end of file diff --git a/src/main/java/com/networknt/schema/keyword/BaseKeywordValidator.java b/src/main/java/com/networknt/schema/keyword/BaseKeywordValidator.java new file mode 100644 index 000000000..c58d4b8eb --- /dev/null +++ b/src/main/java/com/networknt/schema/keyword/BaseKeywordValidator.java @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2016 Network New Technologies Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.networknt.schema.keyword; + +import com.fasterxml.jackson.databind.JsonNode; +import com.networknt.schema.ErrorMessages; +import com.networknt.schema.Schema; +import com.networknt.schema.MessageSourceError; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.SchemaContext; + +import java.util.Collection; +import java.util.Map; + +/** + * Base {@link KeywordValidator}. + */ +public abstract class BaseKeywordValidator extends AbstractKeywordValidator { + protected final SchemaContext schemaContext; + + protected final Schema parentSchema; + protected final Map errorMessage; + + protected final Schema evaluationParentSchema; + + public BaseKeywordValidator(Keyword keyword, JsonNode schemaNode, SchemaLocation schemaLocation, + Schema parentSchema, SchemaContext schemaContext, + NodePath evaluationPath) { + super(keyword, schemaNode, schemaLocation, evaluationPath); + this.schemaContext = schemaContext; + + this.parentSchema = parentSchema; + if (keyword != null && parentSchema != null && schemaContext.getSchemaRegistryConfig().getErrorMessageKeyword() != null) { + this.errorMessage = ErrorMessages.getErrorMessage(parentSchema, + schemaContext.getSchemaRegistryConfig().getErrorMessageKeyword(), keyword.getValue()); + } else { + this.errorMessage = null; + } + this.evaluationParentSchema = null; + } + + /** + * Constructor to create a copy using fields. + * @param keyword the keyword + * @param schemaNode the schema node + * @param schemaLocation the schema location + * @param schemaContext the schema context + * @param parentSchema the parent schema + * @param evaluationPath the evaluation path + * @param evaluationParentSchema the evaluation parent schema + * @param errorMessage the error message + */ + protected BaseKeywordValidator( + Keyword keyword, + JsonNode schemaNode, + SchemaLocation schemaLocation, + SchemaContext schemaContext, + Schema parentSchema, + NodePath evaluationPath, + Schema evaluationParentSchema, + Map errorMessage) { + super(keyword, schemaNode, schemaLocation, evaluationPath); + this.schemaContext = schemaContext; + + this.parentSchema = parentSchema; + this.errorMessage = errorMessage; + + this.evaluationParentSchema = evaluationParentSchema; + } + + /** + * Gets the parent schema. + *

+ * This is the lexical parent schema. + * + * @return the parent schema + */ + public Schema getParentSchema() { + return this.parentSchema; + } + + /** + * Gets the evaluation parent schema. + *

+ * This is the dynamic parent schema when following references. + * + * @see Schema#fromRef(Schema, NodePath) + * @return the evaluation parent schema + */ + public Schema getEvaluationParentSchema() { + if (this.evaluationParentSchema != null) { + return this.evaluationParentSchema; + } + return getParentSchema(); + } + + protected String getNodeFieldType() { + JsonNode typeField = this.getParentSchema().getSchemaNode().get("type"); + if (typeField != null) { + return typeField.asText(); + } + return null; + } + + protected void preloadSchemas(final Collection schemas) { + for (final Schema schema : schemas) { + schema.initializeValidators(); + } + } + + /** + * Determines if the keyword exists adjacent in the evaluation path. + *

+ * This does not check if the keyword exists in the current meta schema as this + * can be a cross-draft case where the properties keyword is in a Draft 7 schema + * and the unevaluatedProperties keyword is in an outer Draft 2020-12 schema. + *

+ * The fact that the validator exists in the evaluation path implies that the + * keyword was valid in whatever meta schema for that schema it was created for. + * + * @param keyword the keyword to check + * @return true if found + */ + protected boolean hasAdjacentKeywordInEvaluationPath(String keyword) { + Schema schema = getEvaluationParentSchema(); + while (schema != null) { + for (KeywordValidator validator : schema.getValidators()) { + if (keyword.equals(validator.getKeyword())) { + return true; + } + } + Object element = schema.getEvaluationPath().getElement(-1); + if ("properties".equals(element) || "items".equals(element)) { + // If there is a change in instance location then return false + return false; + } + schema = schema.getEvaluationParentSchema(); + } + return false; + } + + protected MessageSourceError.Builder error() { + return MessageSourceError + .builder(this.schemaContext.getSchemaRegistryConfig().getMessageSource(), this.errorMessage) + .schemaNode(this.schemaNode).schemaLocation(this.schemaLocation).evaluationPath(this.evaluationPath) + .keyword(this.getKeyword()).messageKey(this.getKeyword()); + } +} diff --git a/src/main/java/com/networknt/schema/ConstValidator.java b/src/main/java/com/networknt/schema/keyword/ConstValidator.java similarity index 53% rename from src/main/java/com/networknt/schema/ConstValidator.java rename to src/main/java/com/networknt/schema/keyword/ConstValidator.java index db53eee8c..d1d1fec9f 100644 --- a/src/main/java/com/networknt/schema/ConstValidator.java +++ b/src/main/java/com/networknt/schema/keyword/ConstValidator.java @@ -13,35 +13,34 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import com.fasterxml.jackson.databind.JsonNode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.SchemaContext; /** - * {@link JsonValidator} for const. + * {@link KeywordValidator} for const. */ -public class ConstValidator extends BaseJsonValidator implements JsonValidator { - private static final Logger logger = LoggerFactory.getLogger(ConstValidator.class); - - public ConstValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, - JsonSchema parentSchema, ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.CONST, validationContext); +public class ConstValidator extends BaseKeywordValidator implements KeywordValidator { + public ConstValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, + Schema parentSchema, SchemaContext schemaContext) { + super(KeywordType.CONST, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); } - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) { - debug(logger, executionContext, node, rootNode, instanceLocation); - + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation) { if (schemaNode.isNumber() && node.isNumber()) { if (schemaNode.decimalValue().compareTo(node.decimalValue()) != 0) { - executionContext.addError(message().instanceNode(node).instanceLocation(instanceLocation) + executionContext.addError(error().instanceNode(node).instanceLocation(instanceLocation) .locale(executionContext.getExecutionConfig().getLocale()) - .failFast(executionContext.isFailFast()).arguments(schemaNode.asText(), node.asText()) + .arguments(schemaNode.asText(), node.asText()) .build()); } } else if (!schemaNode.equals(node)) { - executionContext.addError(message().instanceNode(node).instanceLocation(instanceLocation) + executionContext.addError(error().instanceNode(node).instanceLocation(instanceLocation) .locale(executionContext.getExecutionConfig().getLocale()).arguments(schemaNode.asText(), node.asText()).build()); } } diff --git a/src/main/java/com/networknt/schema/ContainsValidator.java b/src/main/java/com/networknt/schema/keyword/ContainsValidator.java similarity index 71% rename from src/main/java/com/networknt/schema/ContainsValidator.java rename to src/main/java/com/networknt/schema/keyword/ContainsValidator.java index a5f971454..381c72cbf 100644 --- a/src/main/java/com/networknt/schema/ContainsValidator.java +++ b/src/main/java/com/networknt/schema/keyword/ContainsValidator.java @@ -14,30 +14,32 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import com.fasterxml.jackson.databind.JsonNode; -import com.networknt.schema.annotation.JsonNodeAnnotation; +import com.networknt.schema.Error; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.SchemaContext; +import com.networknt.schema.annotation.Annotation; +import com.networknt.schema.path.NodePath; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import static com.networknt.schema.SpecificationVersionRange.MIN_DRAFT_2019_09; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.Optional; -import static com.networknt.schema.VersionCode.MinV201909; - /** - * {@link JsonValidator} for contains. + * {@link KeywordValidator} for contains. */ -public class ContainsValidator extends BaseJsonValidator { - private static final Logger logger = LoggerFactory.getLogger(ContainsValidator.class); +public class ContainsValidator extends BaseKeywordValidator { private static final String CONTAINS_MAX = "contains.max"; private static final String CONTAINS_MIN = "contains.min"; - private final JsonSchema schema; + private final Schema schema; private final boolean isMinV201909; private final Integer min; @@ -45,28 +47,28 @@ public class ContainsValidator extends BaseJsonValidator { private Boolean hasUnevaluatedItemsValidator = null; - public ContainsValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.CONTAINS, validationContext); + public ContainsValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, Schema parentSchema, SchemaContext schemaContext) { + super(KeywordType.CONTAINS, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); // Draft 6 added the contains keyword but maxContains and minContains first // appeared in Draft 2019-09 so the semantics of the validation changes // slightly. - this.isMinV201909 = MinV201909.getVersions().contains(this.validationContext.getMetaSchema().getSpecification()); + this.isMinV201909 = MIN_DRAFT_2019_09.getVersions().contains(this.schemaContext.getDialect().getSpecificationVersion()); Integer currentMax = null; Integer currentMin = null; if (schemaNode.isObject() || schemaNode.isBoolean()) { - this.schema = validationContext.newSchema(schemaLocation, evaluationPath, schemaNode, parentSchema); + this.schema = schemaContext.newSchema(schemaLocation, evaluationPath, schemaNode, parentSchema); JsonNode parentSchemaNode = parentSchema.getSchemaNode(); Optional maxNode = Optional - .ofNullable(parentSchemaNode.get(ValidatorTypeCode.MAX_CONTAINS.getValue())) + .ofNullable(parentSchemaNode.get(KeywordType.MAX_CONTAINS.getValue())) .filter(JsonNode::canConvertToExactIntegral); if (maxNode.isPresent()) { currentMax = maxNode.get().intValue(); } Optional minNode = Optional - .ofNullable(parentSchemaNode.get(ValidatorTypeCode.MIN_CONTAINS.getValue())) + .ofNullable(parentSchemaNode.get(KeywordType.MIN_CONTAINS.getValue())) .filter(JsonNode::canConvertToExactIntegral); if (minNode.isPresent()) { currentMin = minNode.get().intValue(); @@ -79,22 +81,20 @@ public ContainsValidator(SchemaLocation schemaLocation, JsonNodePath evaluationP } @Override - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) { - debug(logger, executionContext, node, rootNode, instanceLocation); - + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation) { // ignores non-arrays int actual = 0, i = 0; List indexes = new ArrayList<>(); // for the annotation if (null != this.schema && node.isArray()) { // Save flag as nested schema evaluation shouldn't trigger fail fast boolean failFast = executionContext.isFailFast(); - List existingErrors = executionContext.getErrors(); + List existingErrors = executionContext.getErrors(); try { executionContext.setFailFast(false); - List test = new ArrayList<>(); + List test = new ArrayList<>(); executionContext.setErrors(test); for (JsonNode n : node) { - JsonNodePath path = instanceLocation.append(i); + NodePath path = instanceLocation.append(i); this.schema.validate(executionContext, n, rootNode, path); if (test.isEmpty()) { ++actual; @@ -114,15 +114,15 @@ public void validate(ExecutionContext executionContext, JsonNode node, JsonNode m = this.min; } if (actual < m) { - boundsViolated(executionContext, isMinV201909 ? ValidatorTypeCode.MIN_CONTAINS : ValidatorTypeCode.CONTAINS, + boundsViolated(executionContext, isMinV201909 ? KeywordType.MIN_CONTAINS : KeywordType.CONTAINS, executionContext.getExecutionConfig().getLocale(), - executionContext.isFailFast(), node, instanceLocation, m); + node, instanceLocation, m); } if (this.max != null && actual > this.max) { - boundsViolated(executionContext, isMinV201909 ? ValidatorTypeCode.MAX_CONTAINS : ValidatorTypeCode.CONTAINS, + boundsViolated(executionContext, isMinV201909 ? KeywordType.MAX_CONTAINS : KeywordType.CONTAINS, executionContext.getExecutionConfig().getLocale(), - executionContext.isFailFast(), node, instanceLocation, this.max); + node, instanceLocation, this.max); } } @@ -139,12 +139,12 @@ public void validate(ExecutionContext executionContext, JsonNode node, JsonNode if (actual == i) { // evaluated all executionContext.getAnnotations() - .put(JsonNodeAnnotation.builder().instanceLocation(instanceLocation) + .put(Annotation.builder().instanceLocation(instanceLocation) .evaluationPath(this.evaluationPath).schemaLocation(this.schemaLocation) .keyword("contains").value(true).build()); } else { executionContext.getAnnotations() - .put(JsonNodeAnnotation.builder().instanceLocation(instanceLocation) + .put(Annotation.builder().instanceLocation(instanceLocation) .evaluationPath(this.evaluationPath).schemaLocation(this.schemaLocation) .keyword("contains").value(indexes).build()); } @@ -158,7 +158,7 @@ public void validate(ExecutionContext executionContext, JsonNode node, JsonNode // in the section for contains, the absence of this keyword's annotation causes // contains to assume a minimum value of 1. executionContext.getAnnotations() - .put(JsonNodeAnnotation.builder().instanceLocation(instanceLocation) + .put(Annotation.builder().instanceLocation(instanceLocation) .evaluationPath(this.evaluationPath.append(minContainsKeyword)) .schemaLocation(this.schemaLocation.append(minContainsKeyword)) .keyword(minContainsKeyword).value(this.min).build()); @@ -169,7 +169,7 @@ public void validate(ExecutionContext executionContext, JsonNode node, JsonNode String maxContainsKeyword = "maxContains"; if (collectAnnotations || collectAnnotations(executionContext, maxContainsKeyword)) { executionContext.getAnnotations() - .put(JsonNodeAnnotation.builder().instanceLocation(instanceLocation) + .put(Annotation.builder().instanceLocation(instanceLocation) .evaluationPath(this.evaluationPath.append(maxContainsKeyword)) .schemaLocation(this.schemaLocation.append(maxContainsKeyword)) .keyword(maxContainsKeyword).value(this.max).build()); @@ -179,22 +179,22 @@ public void validate(ExecutionContext executionContext, JsonNode node, JsonNode } @Override - public void preloadJsonSchema() { - Optional.ofNullable(this.schema).ifPresent(JsonSchema::initializeValidators); + public void preloadSchema() { + Optional.ofNullable(this.schema).ifPresent(Schema::initializeValidators); collectAnnotations(); // cache the flag } - private void boundsViolated(ExecutionContext executionContext, ValidatorTypeCode validatorTypeCode, Locale locale, boolean failFast, - JsonNode instanceNode, JsonNodePath instanceLocation, int bounds) { + private void boundsViolated(ExecutionContext executionContext, KeywordType validatorTypeCode, Locale locale, + JsonNode instanceNode, NodePath instanceLocation, int bounds) { String messageKey = "contains"; - if (ValidatorTypeCode.MIN_CONTAINS.equals(validatorTypeCode)) { + if (KeywordType.MIN_CONTAINS.equals(validatorTypeCode)) { messageKey = CONTAINS_MIN; - } else if (ValidatorTypeCode.MAX_CONTAINS.equals(validatorTypeCode)) { + } else if (KeywordType.MAX_CONTAINS.equals(validatorTypeCode)) { messageKey = CONTAINS_MAX; } - executionContext.addError(message().instanceNode(instanceNode).instanceLocation(instanceLocation).messageKey(messageKey) - .locale(locale).failFast(failFast).arguments(String.valueOf(bounds), this.schema.getSchemaNode().toString()) - .code(validatorTypeCode.getErrorCode()).type(validatorTypeCode.getValue()).build()); + executionContext.addError(error().instanceNode(instanceNode).instanceLocation(instanceLocation).messageKey(messageKey) + .locale(locale).arguments(String.valueOf(bounds), this.schema.getSchemaNode().toString()) + .keyword(validatorTypeCode.getValue()).build()); } /** diff --git a/src/main/java/com/networknt/schema/ContentEncodingValidator.java b/src/main/java/com/networknt/schema/keyword/ContentEncodingValidator.java similarity index 68% rename from src/main/java/com/networknt/schema/ContentEncodingValidator.java rename to src/main/java/com/networknt/schema/keyword/ContentEncodingValidator.java index 66335052d..d384c9fee 100644 --- a/src/main/java/com/networknt/schema/ContentEncodingValidator.java +++ b/src/main/java/com/networknt/schema/keyword/ContentEncodingValidator.java @@ -14,23 +14,26 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import com.fasterxml.jackson.databind.JsonNode; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.utils.JsonType; +import com.networknt.schema.utils.TypeFactory; +import com.networknt.schema.SchemaContext; import java.util.Base64; /** - * {@link JsonValidator} for contentEncoding. + * {@link KeywordValidator} for contentEncoding. *

* Note that since 2019-09 this keyword only generates annotations and not - * assertions. + * errors. */ -public class ContentEncodingValidator extends BaseJsonValidator { - private static final Logger logger = LoggerFactory.getLogger(ContentEncodingValidator.class); +public class ContentEncodingValidator extends BaseKeywordValidator { private final String contentEncoding; /** @@ -40,12 +43,12 @@ public class ContentEncodingValidator extends BaseJsonValidator { * @param evaluationPath the evaluation path * @param schemaNode the schema node * @param parentSchema the parent schema - * @param validationContext the validation context + * @param schemaContext the schema context */ - public ContentEncodingValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, - JsonSchema parentSchema, ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.CONTENT_ENCODING, - validationContext); + public ContentEncodingValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, + Schema parentSchema, SchemaContext schemaContext) { + super(KeywordType.CONTENT_ENCODING, schemaNode, schemaLocation, parentSchema, schemaContext, + evaluationPath); this.contentEncoding = schemaNode.textValue(); } @@ -64,11 +67,9 @@ private boolean matches(String value) { @Override public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, - JsonNodePath instanceLocation) { - debug(logger, executionContext, node, rootNode, instanceLocation); - + NodePath instanceLocation) { // Ignore non-strings - JsonType nodeType = TypeFactory.getValueNodeType(node, this.validationContext.getConfig()); + JsonType nodeType = TypeFactory.getValueNodeType(node, this.schemaContext.getSchemaRegistryConfig()); if (nodeType != JsonType.STRING) { return; } @@ -79,9 +80,9 @@ public void validate(ExecutionContext executionContext, JsonNode node, JsonNode } if (!matches(node.asText())) { - executionContext.addError(message().instanceNode(node).instanceLocation(instanceLocation) + executionContext.addError(error().instanceNode(node).instanceLocation(instanceLocation) .locale(executionContext.getExecutionConfig().getLocale()) - .failFast(executionContext.isFailFast()).arguments(this.contentEncoding) + .arguments(this.contentEncoding) .build()); } } diff --git a/src/main/java/com/networknt/schema/ContentMediaTypeValidator.java b/src/main/java/com/networknt/schema/keyword/ContentMediaTypeValidator.java similarity index 78% rename from src/main/java/com/networknt/schema/ContentMediaTypeValidator.java rename to src/main/java/com/networknt/schema/keyword/ContentMediaTypeValidator.java index 465f0d5f3..f4fe1044a 100644 --- a/src/main/java/com/networknt/schema/ContentMediaTypeValidator.java +++ b/src/main/java/com/networknt/schema/keyword/ContentMediaTypeValidator.java @@ -14,26 +14,29 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import java.nio.charset.StandardCharsets; import java.util.Base64; import java.util.regex.Pattern; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.SchemaContext; import com.networknt.schema.serialization.JsonMapperFactory; +import com.networknt.schema.utils.JsonType; +import com.networknt.schema.utils.TypeFactory; /** - * {@link JsonValidator} for contentMediaType. + * {@link KeywordValidator} for contentMediaType. *

- * Note that since 2019-09 this keyword only generates annotations and not assertions. + * Note that since 2019-09 this keyword only generates annotations and not errors. */ -public class ContentMediaTypeValidator extends BaseJsonValidator { - private static final Logger logger = LoggerFactory.getLogger(ContentMediaTypeValidator.class); +public class ContentMediaTypeValidator extends BaseKeywordValidator { private static final String PATTERN_STRING = "(application|audio|font|example|image|message|model|multipart|text|video|x-(?:[0-9A-Za-z!#$%&'*+.^_`|~-]+))/([0-9A-Za-z!#$%&'*+.^_`|~-]+)((?:[ \t]*;[ \t]*[0-9A-Za-z!#$%&'*+.^_`|~-]+=(?:[0-9A-Za-z!#$%&'*+.^_`|~-]+|\"(?:[^\"\\\\]|\\.)*\"))*)"; private static final Pattern PATTERN = Pattern.compile(PATTERN_STRING); private final String contentMediaType; @@ -45,11 +48,11 @@ public class ContentMediaTypeValidator extends BaseJsonValidator { * @param evaluationPath the evaluation path * @param schemaNode the schema node * @param parentSchema the parent schema - * @param validationContext the validation context + * @param schemaContext the schema context */ - public ContentMediaTypeValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, - JsonSchema parentSchema, ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.CONTENT_MEDIA_TYPE, validationContext); + public ContentMediaTypeValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, + Schema parentSchema, SchemaContext schemaContext) { + super(KeywordType.CONTENT_MEDIA_TYPE, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); this.contentMediaType = schemaNode.textValue(); } @@ -87,11 +90,9 @@ else if (!PATTERN.matcher(this.contentMediaType).matches()) { @Override public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, - JsonNodePath instanceLocation) { - debug(logger, executionContext, node, rootNode, instanceLocation); - + NodePath instanceLocation) { // Ignore non-strings - JsonType nodeType = TypeFactory.getValueNodeType(node, this.validationContext.getConfig()); + JsonType nodeType = TypeFactory.getValueNodeType(node, this.schemaContext.getSchemaRegistryConfig()); if (nodeType != JsonType.STRING) { return; } @@ -102,9 +103,9 @@ public void validate(ExecutionContext executionContext, JsonNode node, JsonNode } if (!matches(node.asText())) { - executionContext.addError(message().instanceNode(node).instanceLocation(instanceLocation) + executionContext.addError(error().instanceNode(node).instanceLocation(instanceLocation) .locale(executionContext.getExecutionConfig().getLocale()) - .failFast(executionContext.isFailFast()).arguments(this.contentMediaType) + .arguments(this.contentMediaType) .build()); } } diff --git a/src/main/java/com/networknt/schema/DependenciesValidator.java b/src/main/java/com/networknt/schema/keyword/DependenciesValidator.java similarity index 65% rename from src/main/java/com/networknt/schema/DependenciesValidator.java rename to src/main/java/com/networknt/schema/keyword/DependenciesValidator.java index 876f431bc..c3426f70c 100644 --- a/src/main/java/com/networknt/schema/DependenciesValidator.java +++ b/src/main/java/com/networknt/schema/keyword/DependenciesValidator.java @@ -14,21 +14,23 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import com.fasterxml.jackson.databind.JsonNode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.SchemaContext; import java.util.*; /** - * {@link JsonValidator} for dependencies. + * {@link KeywordValidator} for dependencies. */ -public class DependenciesValidator extends BaseJsonValidator implements JsonValidator { - private static final Logger logger = LoggerFactory.getLogger(DependenciesValidator.class); +public class DependenciesValidator extends BaseKeywordValidator implements KeywordValidator { private final Map> propertyDeps = new HashMap<>(); - private final Map schemaDeps = new HashMap<>(); + private final Map schemaDeps = new HashMap<>(); /** * Constructor. @@ -37,11 +39,11 @@ public class DependenciesValidator extends BaseJsonValidator implements JsonVali * @param evaluationPath the evaluation path * @param schemaNode the schema node * @param parentSchema the parent schema - * @param validationContext the validation context + * @param schemaContext the schema context */ - public DependenciesValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { + public DependenciesValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, Schema parentSchema, SchemaContext schemaContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.DEPENDENCIES, validationContext); + super(KeywordType.DEPENDENCIES, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); for (Iterator it = schemaNode.fieldNames(); it.hasNext(); ) { String pname = it.next(); @@ -56,29 +58,26 @@ public DependenciesValidator(SchemaLocation schemaLocation, JsonNodePath evaluat depsProps.add(pvalue.get(i).asText()); } } else if (pvalue.isObject() || pvalue.isBoolean()) { - schemaDeps.put(pname, validationContext.newSchema(schemaLocation.append(pname), + schemaDeps.put(pname, schemaContext.newSchema(schemaLocation.append(pname), evaluationPath.append(pname), pvalue, parentSchema)); } } } - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) { - debug(logger, executionContext, node, rootNode, instanceLocation); - + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation) { for (Iterator it = node.fieldNames(); it.hasNext(); ) { String pname = it.next(); List deps = propertyDeps.get(pname); if (deps != null && !deps.isEmpty()) { for (String field : deps) { if (node.get(field) == null) { - executionContext.addError(message().instanceNode(node).property(pname).instanceLocation(instanceLocation) + executionContext.addError(error().instanceNode(node).property(pname).instanceLocation(instanceLocation) .locale(executionContext.getExecutionConfig().getLocale()) - .failFast(executionContext.isFailFast()) .arguments(propertyDeps.toString()).build()); } } } - JsonSchema schema = schemaDeps.get(pname); + Schema schema = schemaDeps.get(pname); if (schema != null) { schema.validate(executionContext, node, rootNode, instanceLocation); } @@ -86,7 +85,7 @@ public void validate(ExecutionContext executionContext, JsonNode node, JsonNode } @Override - public void preloadJsonSchema() { - preloadJsonSchemas(schemaDeps.values()); + public void preloadSchema() { + preloadSchemas(schemaDeps.values()); } } diff --git a/src/main/java/com/networknt/schema/DependentRequired.java b/src/main/java/com/networknt/schema/keyword/DependentRequired.java similarity index 65% rename from src/main/java/com/networknt/schema/DependentRequired.java rename to src/main/java/com/networknt/schema/keyword/DependentRequired.java index da9294af7..d6848c438 100644 --- a/src/main/java/com/networknt/schema/DependentRequired.java +++ b/src/main/java/com/networknt/schema/keyword/DependentRequired.java @@ -14,24 +14,26 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import com.fasterxml.jackson.databind.JsonNode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.SchemaContext; import java.util.*; /** - * {@link JsonValidator} for dependentRequired. + * {@link KeywordValidator} for dependentRequired. */ -public class DependentRequired extends BaseJsonValidator implements JsonValidator { - private static final Logger logger = LoggerFactory.getLogger(DependentRequired.class); +public class DependentRequired extends BaseKeywordValidator implements KeywordValidator { private final Map> propertyDependencies = new HashMap<>(); - public DependentRequired(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { + public DependentRequired(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, Schema parentSchema, SchemaContext schemaContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.DEPENDENT_REQUIRED, validationContext); + super(KeywordType.DEPENDENT_REQUIRED, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); for (Iterator it = schemaNode.fieldNames(); it.hasNext(); ) { String pname = it.next(); @@ -46,18 +48,16 @@ public DependentRequired(SchemaLocation schemaLocation, JsonNodePath evaluationP } } - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) { - debug(logger, executionContext, node, rootNode, instanceLocation); - + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation) { for (Iterator it = node.fieldNames(); it.hasNext(); ) { String pname = it.next(); List dependencies = propertyDependencies.get(pname); if (dependencies != null && !dependencies.isEmpty()) { for (String field : dependencies) { if (node.get(field) == null) { - executionContext.addError(message().instanceNode(node).property(pname).instanceLocation(instanceLocation) + executionContext.addError(error().instanceNode(node).property(pname).instanceLocation(instanceLocation) .locale(executionContext.getExecutionConfig().getLocale()) - .failFast(executionContext.isFailFast()).arguments(field, pname) + .arguments(field, pname) .build()); } } diff --git a/src/main/java/com/networknt/schema/DependentSchemas.java b/src/main/java/com/networknt/schema/keyword/DependentSchemas.java similarity index 62% rename from src/main/java/com/networknt/schema/DependentSchemas.java rename to src/main/java/com/networknt/schema/keyword/DependentSchemas.java index b9bfa47b4..fb27538d2 100644 --- a/src/main/java/com/networknt/schema/DependentSchemas.java +++ b/src/main/java/com/networknt/schema/keyword/DependentSchemas.java @@ -14,30 +14,32 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import com.fasterxml.jackson.databind.JsonNode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.SchemaContext; import java.util.*; /** - * {@link JsonValidator} for dependentSchemas. + * {@link KeywordValidator} for dependentSchemas. */ -public class DependentSchemas extends BaseJsonValidator { - private static final Logger logger = LoggerFactory.getLogger(DependentSchemas.class); - private final Map schemaDependencies = new HashMap<>(); +public class DependentSchemas extends BaseKeywordValidator { + private final Map schemaDependencies = new HashMap<>(); - public DependentSchemas(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { + public DependentSchemas(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, Schema parentSchema, SchemaContext schemaContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.DEPENDENT_SCHEMAS, validationContext); + super(KeywordType.DEPENDENT_SCHEMAS, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); for (Iterator it = schemaNode.fieldNames(); it.hasNext(); ) { String pname = it.next(); JsonNode pvalue = schemaNode.get(pname); if (pvalue.isObject() || pvalue.isBoolean()) { - this.schemaDependencies.put(pname, validationContext.newSchema(schemaLocation.append(pname), + this.schemaDependencies.put(pname, schemaContext.newSchema(schemaLocation.append(pname), evaluationPath.append(pname), pvalue, parentSchema)); } } @@ -45,17 +47,15 @@ public DependentSchemas(SchemaLocation schemaLocation, JsonNodePath evaluationPa @Override public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, - JsonNodePath instanceLocation) { + NodePath instanceLocation) { validate(executionContext, node, rootNode, instanceLocation, false); } protected void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, - JsonNodePath instanceLocation, boolean walk) { - debug(logger, executionContext, node, rootNode, instanceLocation); - + NodePath instanceLocation, boolean walk) { for (Iterator it = node.fieldNames(); it.hasNext(); ) { String pname = it.next(); - JsonSchema schema = this.schemaDependencies.get(pname); + Schema schema = this.schemaDependencies.get(pname); if (schema != null) { if(!walk) { schema.validate(executionContext, node, rootNode, instanceLocation); @@ -67,17 +67,17 @@ protected void validate(ExecutionContext executionContext, JsonNode node, JsonNo } @Override - public void preloadJsonSchema() { - preloadJsonSchemas(this.schemaDependencies.values()); + public void preloadSchema() { + preloadSchemas(this.schemaDependencies.values()); } @Override - public void walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation, boolean shouldValidateSchema) { + public void walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation, boolean shouldValidateSchema) { if (shouldValidateSchema) { validate(executionContext, node, rootNode, instanceLocation, true); return; } - for (JsonSchema schema : this.schemaDependencies.values()) { + for (Schema schema : this.schemaDependencies.values()) { schema.walk(executionContext, node, rootNode, instanceLocation, false); } } diff --git a/src/main/java/com/networknt/schema/DisallowUnknownKeywordFactory.java b/src/main/java/com/networknt/schema/keyword/DisallowUnknownKeywordFactory.java similarity index 78% rename from src/main/java/com/networknt/schema/DisallowUnknownKeywordFactory.java rename to src/main/java/com/networknt/schema/keyword/DisallowUnknownKeywordFactory.java index f3397b957..30afa000b 100644 --- a/src/main/java/com/networknt/schema/DisallowUnknownKeywordFactory.java +++ b/src/main/java/com/networknt/schema/keyword/DisallowUnknownKeywordFactory.java @@ -13,11 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.networknt.schema.Error; +import com.networknt.schema.InvalidSchemaException; +import com.networknt.schema.SchemaContext; + /** * Unknown keyword factory that rejects unknown keywords. */ @@ -25,10 +29,10 @@ public class DisallowUnknownKeywordFactory implements KeywordFactory { private static final Logger logger = LoggerFactory.getLogger(DisallowUnknownKeywordFactory.class); @Override - public Keyword getKeyword(String value, ValidationContext validationContext) { + public Keyword getKeyword(String value, SchemaContext schemaContext) { logger.error("Keyword '{}' is unknown and must be configured on the meta-schema or vocabulary", value); - throw new InvalidSchemaException(ValidationMessage.builder() - .message("Keyword ''{1}'' is unknown and must be configured on the meta-schema or vocabulary") + throw new InvalidSchemaException(Error.builder() + .message("Keyword ''{0}'' is unknown and must be configured on the meta-schema or vocabulary") .arguments(value).build()); } diff --git a/src/main/java/com/networknt/schema/keyword/DiscriminatorState.java b/src/main/java/com/networknt/schema/keyword/DiscriminatorState.java new file mode 100644 index 000000000..a92095c3b --- /dev/null +++ b/src/main/java/com/networknt/schema/keyword/DiscriminatorState.java @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.networknt.schema.keyword; + +/** + * Discriminator state for an instance location. + */ +public class DiscriminatorState { + /** + * The propertyName field defined in the discriminator keyword schema. + */ + private String propertyName; + /** + * The discriminating value from the payload matching the property name. + */ + private String discriminatingValue; + /** + * The mapped schema from the mapping or the discriminating value if there is no + * mapping. + */ + private String mappedSchema = null; + + /** + * Whether the mapped schema is explicitly mapped using mapping or is the + * discriminating value. + */ + private boolean explicitMapping = false; + + /** + * The matched schema for the instance. + */ + private String matchedSchema; + + /** + * Determines if there is a match of the mapped schema to the ref and update the + * matched schema if there is a match. + * + * @param refSchema the $ref value + * @return true if there is a match + */ + public boolean matches(String refSchema) { + boolean discriminatorMatchFound = false; + String mappedSchema = getMappedSchema(); + if (mappedSchema != null) { + if (isExplicitMapping() && refSchema.equals(mappedSchema)) { + // Explicit matching + discriminatorMatchFound = true; + setMatchedSchema(refSchema); + } else if (!isExplicitMapping() && isImplicitMatch(refSchema, mappedSchema)) { + // Implicit matching + discriminatorMatchFound = true; + setMatchedSchema(refSchema); + } + } + return discriminatorMatchFound; + } + + /** + * Gets the property name defined in the discriminator keyword schema. + * + * @return + */ + public String getPropertyName() { + return propertyName; + } + + /** + * Sets the property name defined in the discriminator keyword schema. + * + * @param propertyName the property name + */ + public void setPropertyName(String propertyName) { + this.propertyName = propertyName; + } + + /** + * Gets the discriminating value, which is the value in the payload + * corresponding with the property name. + * + * @return the discriminating value + */ + public String getDiscriminatingValue() { + return discriminatingValue; + } + + /** + * Sets the discriminating value, which is the value in the payload + * corresponding with the property name. + * + * @param discriminatingValue + */ + public void setDiscriminatingValue(String discriminatingValue) { + this.discriminatingValue = discriminatingValue; + } + + /** + * Returns true if the discriminating value is found in the payload + * corresponding to the property name. + * + * @return true if the discriminating value is found in the payload + * corresponding to the property name + */ + public boolean hasDiscriminatingValue() { + return this.discriminatingValue != null; + } + + /** + * Gets the mapped schema which is the discriminating value mapped to the schema + * name or uri. + * + * @return the mapped schema + */ + public String getMappedSchema() { + return mappedSchema; + } + + /** + * Sets the mapped schema which is the discriminating value mapped to the schema + * name or uri. + * + * @param mappedSchema the mapped schema + */ + public void setMappedSchema(String mappedSchema) { + this.mappedSchema = mappedSchema; + } + + /** + * Gets whether the mapping is explicit using the mappings on the discriminator + * keyword. + * + * @return true if the mapping is explicitly mapped using mappings + */ + public boolean isExplicitMapping() { + return explicitMapping; + } + + /** + * Sets whether the mapping is explicit using the mappings on the discriminator + * keyword. + * + * @param explicitMapping true if explicitly mapped using mappings + */ + public void setExplicitMapping(boolean explicitMapping) { + this.explicitMapping = explicitMapping; + } + + /** + * Sets the matched schema $ref. + * + * @param matchedSchema the matched schema $ref + */ + public void setMatchedSchema(String matchedSchema) { + this.matchedSchema = matchedSchema; + } + + /** + * Gets the matched schema $ref. + * + * @return the matched schema $ref + */ + public String getMatchedSchema() { + return this.matchedSchema; + } + + /** + * Returns true if there was a schema that matched the discriminating value. + *

+ * If the discriminating value does not match an implicit or explicit mapping, + * no schema can be determined and validation SHOULD fail. Therefore if this + * returns false validation should fail. + *

+ * 4.8.25.4 + * Examples + * + * @return true if there was a schema that matched the discriminating value. + */ + public boolean hasMatchedSchema() { + return this.matchedSchema != null; + } + + /** + * Determine if there is an implicit match of the mapped schema to the ref. + * + * @param refSchema the $ref value + * @param mappedSchema the mapped schema + * @return true if there is a match + */ + private static boolean isImplicitMatch(String refSchema, String mappedSchema) { + /* + * To ensure that an ambiguous value (e.g. "foo") is treated as a relative URI + * reference by all implementations, authors MUST prefix it with the "." path + * segment (e.g. "./foo"). + */ + if (mappedSchema.startsWith(".")) { + return refSchema.equals(mappedSchema); + } else { + int found = refSchema.lastIndexOf('/'); + if (found == -1) { + return refSchema.equals(mappedSchema); + } else { + return refSchema.substring(found + 1).equals(mappedSchema); + } + } + } +} diff --git a/src/main/java/com/networknt/schema/keyword/DiscriminatorValidator.java b/src/main/java/com/networknt/schema/keyword/DiscriminatorValidator.java new file mode 100644 index 000000000..cdce9ac1d --- /dev/null +++ b/src/main/java/com/networknt/schema/keyword/DiscriminatorValidator.java @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.networknt.schema.keyword; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaContext; +import com.networknt.schema.SchemaException; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.path.NodePath; + +/** + * {@link KeywordValidator} for discriminator. + *

+ * Note that discriminator MUST NOT change the validation outcome of the schema. + *

+ * Discriminator + * Object + */ +public class DiscriminatorValidator extends BaseKeywordValidator { + /** + * The name of the property in the payload that will hold the discriminating + * value. This property SHOULD be required in the payload schema, as the + * behavior when the property is absent is undefined. + */ + private final String propertyName; + /** + * An object to hold mappings between payload values and schema names or URI + * references. + */ + private final Map mapping; + + /** + * The schema name or URI reference to a schema that is expected to validate the + * structure of the model when the discriminating property is not present in the + * payload or contains a value for which there is no explicit or implicit + * mapping. + *

+ * Since OpenAPI 3.2.0 + */ + private final String defaultMapping; + + public DiscriminatorValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, + Schema parentSchema, SchemaContext schemaContext) { + super(KeywordType.DISCRIMINATOR, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); + ObjectNode discriminator = schemaNode.isObject() ? (ObjectNode) schemaNode : null; + if (discriminator != null) { + JsonNode propertyName = discriminator.get("propertyName"); + /* + * There really should be a parse error if propertyName is not defined in the + * schema but there is non-specification compliant behavior if there are + * multiple discriminators on the same path if the propertyName is not defined. + */ + this.propertyName = propertyName != null ? propertyName.asText() : ""; + JsonNode mappingNode = discriminator.get("mapping"); + ObjectNode mapping = mappingNode != null && mappingNode.isObject() ? (ObjectNode) mappingNode : null; + if (mapping != null) { + this.mapping = new HashMap<>(); + for (Iterator> iter = mapping.fields(); iter.hasNext();) { + Entry entry = iter.next(); + this.mapping.put(entry.getKey(), entry.getValue().asText()); + } + } else { + this.mapping = Collections.emptyMap(); + } + + // Check if OpenAPI 3.2.0 + JsonNode defaultMapping = discriminator.get("defaultMapping"); + if (defaultMapping != null) { + this.defaultMapping = defaultMapping.asText(); + } else { + this.defaultMapping = null; + } + + } else { + this.propertyName = ""; + this.mapping = Collections.emptyMap(); + this.defaultMapping = null; + } + } + + @Override + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, + NodePath instanceLocation) { + DiscriminatorState state = null; + DiscriminatorState existing = executionContext.getDiscriminatorMapping().get(instanceLocation); + if (existing != null) { + /* + * By default this does not throw an exception unless strict for discriminator + * is set to true. + * + * This default is in line with the fact that the discriminator keyword doesn't + * affect validation but just helps to filter the messages. + */ + if (this.schemaContext.getSchemaRegistryConfig().isStrict("discriminator", Boolean.FALSE)) { + throw new SchemaException("Schema at " + this.schemaLocation + + " has a discriminator keyword for which another discriminator keyword has already been set for at " + + instanceLocation); + } + /* + * This allows a new discriminator keyword if the propertyName is empty or if + * the propertyName value is the same as the existing one. + * + * In the specification the behavior of this is undefined. There shouldn't be + * multiple matching discriminator keywords for the same instance. + * + * Also propertyName for the discriminator keyword should not be empty according + * to the specification. + */ + if (!"".equals(this.propertyName) && !existing.getPropertyName().equals(this.propertyName)) { + throw new SchemaException("Schema at " + this.schemaLocation + + " is redefining the discriminator property that has already been set for at " + + instanceLocation); + } + state = existing; + } else { + state = new DiscriminatorState(); + state.setPropertyName(this.propertyName); + executionContext.getDiscriminatorMapping().put(instanceLocation, state); + } + JsonNode discriminatingValueNode = node.get(state.getPropertyName()); + if (discriminatingValueNode != null && discriminatingValueNode.isTextual()) { + String discriminatingValue = discriminatingValueNode.asText(); + state.setDiscriminatingValue(discriminatingValue); + // Check for explicit mapping + String mappedSchema = mapping.get(discriminatingValue); + if (existing != null && mappedSchema != null) { + /* + * If the existing already has an explicit mapping and this doesn't tally with + * this one this is an issue as well. + */ + if (existing.isExplicitMapping() && !existing.getMappedSchema().equals(mappedSchema)) { + throw new SchemaException( + "Schema at " + this.schemaLocation + " is mapping that has already been set for " + + instanceLocation + " from " + existing.getMappedSchema() + " to " + mappedSchema); + } + } + if (mappedSchema != null) { + // Explicit mapping found + state.setMappedSchema(mappedSchema); + state.setExplicitMapping(true); + } else { + if (!state.isExplicitMapping()) { // only sets implicit if an explicit mapping was not previously set + // If explicit mapping not found use implicit value + state.setMappedSchema(discriminatingValue); + state.setExplicitMapping(false); + } + } + } else { + /* + * Since OpenAPI 3.2.0 if defaultMapping is set, then the property is optional. + */ + if (this.defaultMapping != null) { + state.setMappedSchema(defaultMapping); + state.setExplicitMapping(true); + return; + } + + /* + * The property is not present in the payload. This property SHOULD be required + * in the payload schema, as the behavior when the property is absent is + * undefined. + */ + /* + * By default this does not generate an assertion unless strict for + * discriminator is set to true. + * + * This default is in line with the intent that discriminator should be an + * annotation and not an assertion and shouldn't change the result which was why + * the specification changed from MUST to SHOULD. + */ + if (this.schemaContext.getSchemaRegistryConfig().isStrict("discriminator", Boolean.FALSE)) { + executionContext.addError(error().instanceNode(node).instanceLocation(instanceLocation) + .locale(executionContext.getExecutionConfig().getLocale()) + .messageKey("discriminator.missing_discriminating_value").arguments(this.propertyName).build()); + } + } + } + + /** + * Gets the property name of the discriminator. + * + * @return the property name + */ + public String getPropertyName() { + return propertyName; + } + + /** + * Gets the mapping to map the property name value to the schema name. + * + * @return the discriminator mappings + */ + public Map getMapping() { + return mapping; + } +} diff --git a/src/main/java/com/networknt/schema/DynamicRefValidator.java b/src/main/java/com/networknt/schema/keyword/DynamicRefValidator.java similarity index 60% rename from src/main/java/com/networknt/schema/DynamicRefValidator.java rename to src/main/java/com/networknt/schema/keyword/DynamicRefValidator.java index 1cf2d0632..35648c6f4 100644 --- a/src/main/java/com/networknt/schema/DynamicRefValidator.java +++ b/src/main/java/com/networknt/schema/keyword/DynamicRefValidator.java @@ -14,44 +14,50 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import com.fasterxml.jackson.databind.JsonNode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.networknt.schema.Error; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.InvalidSchemaRefException; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaException; +import com.networknt.schema.SchemaRef; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.utils.ThreadSafeCachingSupplier; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.SchemaContext; import java.util.function.Supplier; /** - * {@link JsonValidator} that resolves $dynamicRef. + * {@link KeywordValidator} that resolves $dynamicRef. */ -public class DynamicRefValidator extends BaseJsonValidator { - private static final Logger logger = LoggerFactory.getLogger(DynamicRefValidator.class); +public class DynamicRefValidator extends BaseKeywordValidator { + protected final SchemaRef schema; - protected final JsonSchemaRef schema; - - public DynamicRefValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.DYNAMIC_REF, validationContext); + public DynamicRefValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, Schema parentSchema, SchemaContext schemaContext) { + super(KeywordType.DYNAMIC_REF, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); String refValue = schemaNode.asText(); - this.schema = getRefSchema(parentSchema, validationContext, refValue, evaluationPath); + this.schema = getRefSchema(parentSchema, schemaContext, refValue, evaluationPath); } - static JsonSchemaRef getRefSchema(JsonSchema parentSchema, ValidationContext validationContext, String refValue, - JsonNodePath evaluationPath) { + static SchemaRef getRefSchema(Schema parentSchema, SchemaContext schemaContext, String refValue, + NodePath evaluationPath) { String ref = resolve(parentSchema, refValue); - return new JsonSchemaRef(getSupplier(() -> { - JsonSchema refSchema = validationContext.getDynamicAnchors().get(ref); + return new SchemaRef(getSupplier(() -> { + Schema refSchema = schemaContext.getDynamicAnchors().get(ref); if (refSchema == null) { // This is a $dynamicRef without a matching $dynamicAnchor // A $dynamicRef without a matching $dynamicAnchor in the same schema resource // behaves like a normal $ref to $anchor // A $dynamicRef without anchor in fragment behaves identical to $ref - JsonSchemaRef r = RefValidator.getRefSchema(parentSchema, validationContext, refValue, evaluationPath); + SchemaRef r = RefValidator.getRefSchema(parentSchema, schemaContext, refValue, evaluationPath); if (r != null) { refSchema = r.getSchema(); } } else { // Check parents - JsonSchema base = parentSchema; + Schema base = parentSchema; int index = ref.indexOf("#"); String anchor = ref.substring(index); String absoluteIri = ref.substring(0, index); @@ -61,7 +67,7 @@ static JsonSchemaRef getRefSchema(JsonSchema parentSchema, ValidationContext val if (!baseAbsoluteIri.equals(absoluteIri)) { absoluteIri = baseAbsoluteIri; String parentRef = SchemaLocation.resolve(base.getSchemaLocation(), anchor); - JsonSchema parentRefSchema = validationContext.getDynamicAnchors().get(parentRef); + Schema parentRefSchema = schemaContext.getDynamicAnchors().get(parentRef); if (parentRefSchema != null) { refSchema = parentRefSchema; } @@ -73,54 +79,52 @@ static JsonSchemaRef getRefSchema(JsonSchema parentSchema, ValidationContext val refSchema = refSchema.fromRef(parentSchema, evaluationPath); } return refSchema; - }, validationContext.getConfig().isCacheRefs())); + }, schemaContext.getSchemaRegistryConfig().isCacheRefs())); } static Supplier getSupplier(Supplier supplier, boolean cache) { - return cache ? new CachedSupplier<>(supplier) : supplier; + return cache ? new ThreadSafeCachingSupplier<>(supplier) : supplier; } - private static String resolve(JsonSchema parentSchema, String refValue) { + private static String resolve(Schema parentSchema, String refValue) { // $ref prevents a sibling $id from changing the base uri - JsonSchema base = parentSchema; - if (parentSchema.getId() != null && parentSchema.parentSchema != null) { - base = parentSchema.parentSchema; + Schema base = parentSchema; + if (parentSchema.getId() != null && parentSchema.getParentSchema() != null) { + base = parentSchema.getParentSchema(); } return SchemaLocation.resolve(base.getSchemaLocation(), refValue); } @Override - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) { - debug(logger, executionContext, node, rootNode, instanceLocation); - JsonSchema refSchema = this.schema.getSchema(); + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation) { + Schema refSchema = this.schema.getSchema(); if (refSchema == null) { - ValidationMessage validationMessage = message().type(ValidatorTypeCode.DYNAMIC_REF.getValue()) - .code("internal.unresolvedRef").message("{0}: Reference {1} cannot be resolved") + Error error = error().keyword(KeywordType.DYNAMIC_REF.getValue()) + .messageKey("internal.unresolvedRef").message("Reference {0} cannot be resolved") .instanceLocation(instanceLocation).evaluationPath(getEvaluationPath()) .arguments(schemaNode.asText()).build(); - throw new InvalidSchemaRefException(validationMessage); + throw new InvalidSchemaRefException(error); } refSchema.validate(executionContext, node, rootNode, instanceLocation); } @Override - public void walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation, boolean shouldValidateSchema) { - debug(logger, executionContext, node, rootNode, instanceLocation); + public void walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation, boolean shouldValidateSchema) { // This is important because if we use same JsonSchemaFactory for creating multiple JSONSchema instances, // these schemas will be cached along with config. We have to replace the config for cached $ref references // with the latest config. Reset the config. - JsonSchema refSchema = this.schema.getSchema(); + Schema refSchema = this.schema.getSchema(); if (refSchema == null) { - ValidationMessage validationMessage = message().type(ValidatorTypeCode.DYNAMIC_REF.getValue()) - .code("internal.unresolvedRef").message("{0}: Reference {1} cannot be resolved") + Error error = error().keyword(KeywordType.DYNAMIC_REF.getValue()) + .messageKey("internal.unresolvedRef").message("Reference {0} cannot be resolved") .instanceLocation(instanceLocation).evaluationPath(getEvaluationPath()) .arguments(schemaNode.asText()).build(); - throw new InvalidSchemaRefException(validationMessage); + throw new InvalidSchemaRefException(error); } if (node == null) { // Check for circular dependency SchemaLocation schemaLocation = refSchema.getSchemaLocation(); - JsonSchema check = refSchema; + Schema check = refSchema; boolean circularDependency = false; while (check.getEvaluationParentSchema() != null) { check = check.getEvaluationParentSchema(); @@ -136,26 +140,26 @@ public void walk(ExecutionContext executionContext, JsonNode node, JsonNode root refSchema.walk(executionContext, node, rootNode, instanceLocation, shouldValidateSchema); } - public JsonSchemaRef getSchemaRef() { + public SchemaRef getSchemaRef() { return this.schema; } @Override - public void preloadJsonSchema() { - JsonSchema jsonSchema = null; + public void preloadSchema() { + Schema jsonSchema = null; try { jsonSchema = this.schema.getSchema(); - } catch (JsonSchemaException e) { + } catch (SchemaException e) { throw e; } catch (RuntimeException e) { - throw new JsonSchemaException(e); + throw new SchemaException(e); } // Check for circular dependency // Only one cycle is pre-loaded // The rest of the cycles will load at execution time depending on the input // data SchemaLocation schemaLocation = jsonSchema.getSchemaLocation(); - JsonSchema check = jsonSchema; + Schema check = jsonSchema; boolean circularDependency = false; int depth = 0; while (check.getEvaluationParentSchema() != null) { @@ -166,8 +170,8 @@ public void preloadJsonSchema() { break; } } - if (this.validationContext.getConfig().isCacheRefs() && !circularDependency - && depth < this.validationContext.getConfig().getPreloadJsonSchemaRefMaxNestingDepth()) { + if (this.schemaContext.getSchemaRegistryConfig().isCacheRefs() && !circularDependency + && depth < this.schemaContext.getSchemaRegistryConfig().getPreloadSchemaRefMaxNestingDepth()) { jsonSchema.initializeValidators(); } } diff --git a/src/main/java/com/networknt/schema/EnumValidator.java b/src/main/java/com/networknt/schema/keyword/EnumValidator.java similarity index 79% rename from src/main/java/com/networknt/schema/EnumValidator.java rename to src/main/java/com/networknt/schema/keyword/EnumValidator.java index e474bcd4d..6ad8d9d50 100644 --- a/src/main/java/com/networknt/schema/EnumValidator.java +++ b/src/main/java/com/networknt/schema/keyword/EnumValidator.java @@ -14,14 +14,19 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.DecimalNode; import com.fasterxml.jackson.databind.node.NullNode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.utils.JsonType; +import com.networknt.schema.utils.TypeFactory; +import com.networknt.schema.SchemaContext; import java.math.BigDecimal; import java.util.Collections; @@ -29,11 +34,9 @@ import java.util.Set; /** - * {@link JsonValidator} for enum. + * {@link KeywordValidator} for enum. */ -public class EnumValidator extends BaseJsonValidator implements JsonValidator { - private static final Logger logger = LoggerFactory.getLogger(EnumValidator.class); - +public class EnumValidator extends BaseKeywordValidator implements KeywordValidator { private final Set nodes; private final String error; @@ -45,8 +48,8 @@ static String asText(JsonNode node) { return node.asText(); } - public EnumValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.ENUM, validationContext); + public EnumValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, Schema parentSchema, SchemaContext schemaContext) { + super(KeywordType.ENUM, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); if (schemaNode != null && schemaNode.isArray()) { nodes = new HashSet<>(); StringBuilder sb = new StringBuilder(); @@ -71,7 +74,7 @@ public EnumValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, } // check if the parent schema declares the fields as nullable - if (validationContext.getConfig().isNullableKeywordEnabled()) { + if (schemaContext.isNullableKeywordEnabled()) { JsonNode nullable = parentSchema.getSchemaNode().get("nullable"); if (nullable != null && nullable.asBoolean()) { nodes.add(NullNode.getInstance()); @@ -89,18 +92,16 @@ public EnumValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, } } - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) { - debug(logger, executionContext, node, rootNode, instanceLocation); - + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation) { if (node.isNumber()) { node = processNumberNode(node); } else if (node.isArray()) { node = processArrayNode((ArrayNode) node); } - if (!nodes.contains(node) && !( this.validationContext.getConfig().isTypeLoose() && isTypeLooseContainsInEnum(node))) { - executionContext.addError(message().instanceNode(node).instanceLocation(instanceLocation) + if (!nodes.contains(node) && !( this.schemaContext.getSchemaRegistryConfig().isTypeLoose() && isTypeLooseContainsInEnum(node))) { + executionContext.addError(error().instanceNode(node).instanceLocation(instanceLocation) .locale(executionContext.getExecutionConfig().getLocale()) - .failFast(executionContext.isFailFast()).arguments(error).build()); + .arguments(error).build()); } } @@ -110,7 +111,7 @@ public void validate(ExecutionContext executionContext, JsonNode node, JsonNode * @param node JsonNode to check */ private boolean isTypeLooseContainsInEnum(JsonNode node) { - if (TypeFactory.getValueNodeType(node, this.validationContext.getConfig()) == JsonType.STRING) { + if (TypeFactory.getValueNodeType(node, this.schemaContext.getSchemaRegistryConfig()) == JsonType.STRING) { String nodeText = node.textValue(); for (JsonNode n : nodes) { String value = n.asText(); diff --git a/src/main/java/com/networknt/schema/ExclusiveMaximumValidator.java b/src/main/java/com/networknt/schema/keyword/ExclusiveMaximumValidator.java similarity index 78% rename from src/main/java/com/networknt/schema/ExclusiveMaximumValidator.java rename to src/main/java/com/networknt/schema/keyword/ExclusiveMaximumValidator.java index c461a01c8..bc05fd9ae 100644 --- a/src/main/java/com/networknt/schema/ExclusiveMaximumValidator.java +++ b/src/main/java/com/networknt/schema/keyword/ExclusiveMaximumValidator.java @@ -14,29 +14,31 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import com.fasterxml.jackson.databind.JsonNode; -import com.networknt.schema.utils.JsonNodeUtil; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaException; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.SchemaContext; +import com.networknt.schema.utils.JsonNodeTypes; +import com.networknt.schema.utils.JsonType; import java.math.BigDecimal; import java.math.BigInteger; /** - * {@link JsonValidator} for exclusiveMaximum. + * {@link KeywordValidator} for exclusiveMaximum. */ -public class ExclusiveMaximumValidator extends BaseJsonValidator { - private static final Logger logger = LoggerFactory.getLogger(ExclusiveMaximumValidator.class); - +public class ExclusiveMaximumValidator extends BaseKeywordValidator { private final ThresholdMixin typedMaximum; - public ExclusiveMaximumValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, final JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.EXCLUSIVE_MAXIMUM, validationContext); + public ExclusiveMaximumValidator(SchemaLocation schemaLocation, NodePath evaluationPath, final JsonNode schemaNode, Schema parentSchema, SchemaContext schemaContext) { + super(KeywordType.EXCLUSIVE_MAXIMUM, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); if (!schemaNode.isNumber()) { - throw new JsonSchemaException("exclusiveMaximum value is not a number"); + throw new SchemaException("exclusiveMaximum value is not a number"); } final String maximumText = schemaNode.asText(); if ((schemaNode.isLong() || schemaNode.isInt()) && (JsonType.INTEGER.toString().equals(getNodeFieldType()))) { @@ -95,18 +97,15 @@ public String thresholdValue() { } } - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) { - debug(logger, executionContext, node, rootNode, instanceLocation); - - if (!JsonNodeUtil.isNumber(node, validationContext.getConfig())) { + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation) { + if (!JsonNodeTypes.isNumber(node, schemaContext.getSchemaRegistryConfig())) { // maximum only applies to numbers return; } if (typedMaximum.crossesThreshold(node)) { - executionContext.addError(message().instanceNode(node).instanceLocation(instanceLocation) + executionContext.addError(error().instanceNode(node).instanceLocation(instanceLocation) .locale(executionContext.getExecutionConfig().getLocale()) - .failFast(executionContext.isFailFast()) .arguments(typedMaximum.thresholdValue()).build()); } } diff --git a/src/main/java/com/networknt/schema/ExclusiveMinimumValidator.java b/src/main/java/com/networknt/schema/keyword/ExclusiveMinimumValidator.java similarity index 79% rename from src/main/java/com/networknt/schema/ExclusiveMinimumValidator.java rename to src/main/java/com/networknt/schema/keyword/ExclusiveMinimumValidator.java index c00281ae1..297259121 100644 --- a/src/main/java/com/networknt/schema/ExclusiveMinimumValidator.java +++ b/src/main/java/com/networknt/schema/keyword/ExclusiveMinimumValidator.java @@ -14,33 +14,35 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import com.fasterxml.jackson.databind.JsonNode; -import com.networknt.schema.utils.JsonNodeUtil; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaException; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.SchemaContext; +import com.networknt.schema.utils.JsonNodeTypes; +import com.networknt.schema.utils.JsonType; import java.math.BigDecimal; import java.math.BigInteger; /** - * {@link JsonValidator} for exclusiveMinimum. + * {@link KeywordValidator} for exclusiveMinimum. */ -public class ExclusiveMinimumValidator extends BaseJsonValidator { - private static final Logger logger = LoggerFactory.getLogger(ExclusiveMinimumValidator.class); - +public class ExclusiveMinimumValidator extends BaseKeywordValidator { /** * In order to limit number of `if` statements in `validate` method, all the * logic of picking the right comparison is abstracted into a mixin. */ private final ThresholdMixin typedMinimum; - public ExclusiveMinimumValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, final JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.EXCLUSIVE_MINIMUM, validationContext); + public ExclusiveMinimumValidator(SchemaLocation schemaLocation, NodePath evaluationPath, final JsonNode schemaNode, Schema parentSchema, SchemaContext schemaContext) { + super(KeywordType.EXCLUSIVE_MINIMUM, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); if (!schemaNode.isNumber()) { - throw new JsonSchemaException("exclusiveMinimum value is not a number"); + throw new SchemaException("exclusiveMinimum value is not a number"); } final String minimumText = schemaNode.asText(); if ((schemaNode.isLong() || schemaNode.isInt()) && JsonType.INTEGER.toString().equals(getNodeFieldType())) { @@ -102,18 +104,15 @@ public String thresholdValue() { } } - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) { - debug(logger, executionContext, node, rootNode, instanceLocation); - - if (!JsonNodeUtil.isNumber(node, this.validationContext.getConfig())) { + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation) { + if (!JsonNodeTypes.isNumber(node, this.schemaContext.getSchemaRegistryConfig())) { // minimum only applies to numbers return; } if (typedMinimum.crossesThreshold(node)) { - executionContext.addError(message().instanceNode(node).instanceLocation(instanceLocation) + executionContext.addError(error().instanceNode(node).instanceLocation(instanceLocation) .locale(executionContext.getExecutionConfig().getLocale()) - .failFast(executionContext.isFailFast()) .arguments(typedMinimum.thresholdValue()).build()); } } diff --git a/src/main/java/com/networknt/schema/FalseValidator.java b/src/main/java/com/networknt/schema/keyword/FalseValidator.java similarity index 52% rename from src/main/java/com/networknt/schema/FalseValidator.java rename to src/main/java/com/networknt/schema/keyword/FalseValidator.java index a33a2b745..dd1aaf578 100644 --- a/src/main/java/com/networknt/schema/FalseValidator.java +++ b/src/main/java/com/networknt/schema/keyword/FalseValidator.java @@ -13,30 +13,30 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import com.fasterxml.jackson.databind.JsonNode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.SchemaContext; /** - * {@link JsonValidator} for false. + * {@link KeywordValidator} for false. */ -public class FalseValidator extends BaseJsonValidator implements JsonValidator { - private static final Logger logger = LoggerFactory.getLogger(FalseValidator.class); - +public class FalseValidator extends BaseKeywordValidator implements KeywordValidator { private final String reason; - public FalseValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, final JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.FALSE, validationContext); + public FalseValidator(SchemaLocation schemaLocation, NodePath evaluationPath, final JsonNode schemaNode, Schema parentSchema, SchemaContext schemaContext) { + super(KeywordType.FALSE, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); this.reason = this.evaluationPath.getParent().getName(-1); } - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) { - debug(logger, executionContext, node, rootNode, instanceLocation); + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation) { // For the false validator, it is always not valid - executionContext.addError(message().instanceNode(node).instanceLocation(instanceLocation) + executionContext.addError(error().instanceNode(node).instanceLocation(instanceLocation) .locale(executionContext.getExecutionConfig().getLocale()) - .failFast(executionContext.isFailFast()).arguments(reason).build()); + .arguments(reason).build()); } } diff --git a/src/main/java/com/networknt/schema/FormatKeyword.java b/src/main/java/com/networknt/schema/keyword/FormatKeyword.java similarity index 68% rename from src/main/java/com/networknt/schema/FormatKeyword.java rename to src/main/java/com/networknt/schema/keyword/FormatKeyword.java index cb2031ffb..1c21e4f13 100644 --- a/src/main/java/com/networknt/schema/FormatKeyword.java +++ b/src/main/java/com/networknt/schema/keyword/FormatKeyword.java @@ -14,9 +14,14 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import com.fasterxml.jackson.databind.JsonNode; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.format.Format; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.SchemaContext; import java.util.Collection; import java.util.Collections; @@ -27,21 +32,19 @@ */ public class FormatKeyword implements Keyword { private final String value; - private final ErrorMessageType errorMessageType; private final Map formats; public FormatKeyword(Map formats) { - this(ValidatorTypeCode.FORMAT, formats); + this(KeywordType.FORMAT, formats); } - public FormatKeyword(ValidatorTypeCode type, Map formats) { - this(type.getValue(), type, formats); + public FormatKeyword(Keyword type, Map formats) { + this(type.getValue(), formats); } - public FormatKeyword(String value, ErrorMessageType errorMessageType, Map formats) { + public FormatKeyword(String value, Map formats) { this.value = value; this.formats = formats; - this.errorMessageType = errorMessageType; } Collection getFormats() { @@ -49,14 +52,14 @@ Collection getFormats() { } @Override - public JsonValidator newValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { + public KeywordValidator newValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, Schema parentSchema, SchemaContext schemaContext) { Format format = null; if (schemaNode != null && schemaNode.isTextual()) { String formatName = schemaNode.textValue(); format = this.formats.get(formatName); } - return new FormatValidator(schemaLocation, evaluationPath, schemaNode, parentSchema, validationContext, format, - errorMessageType, this); + return new FormatValidator(schemaLocation, evaluationPath, schemaNode, parentSchema, schemaContext, format, + this); } @Override diff --git a/src/main/java/com/networknt/schema/FormatValidator.java b/src/main/java/com/networknt/schema/keyword/FormatValidator.java similarity index 72% rename from src/main/java/com/networknt/schema/FormatValidator.java rename to src/main/java/com/networknt/schema/keyword/FormatValidator.java index 4725786f0..aa26df6d4 100644 --- a/src/main/java/com/networknt/schema/FormatValidator.java +++ b/src/main/java/com/networknt/schema/keyword/FormatValidator.java @@ -14,10 +14,16 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import com.fasterxml.jackson.databind.JsonNode; -import com.networknt.schema.format.BaseFormatJsonValidator; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.SchemaContext; +import com.networknt.schema.format.BaseFormatValidator; +import com.networknt.schema.format.Format; +import com.networknt.schema.path.NodePath; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -27,23 +33,18 @@ /** * Validator for Format. */ -public class FormatValidator extends BaseFormatJsonValidator implements JsonValidator { +public class FormatValidator extends BaseFormatValidator implements KeywordValidator { private static final Logger logger = LoggerFactory.getLogger(FormatValidator.class); private final Format format; - public FormatValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, - JsonSchema parentSchema, ValidationContext validationContext, Format format, - ErrorMessageType errorMessageType, Keyword keyword) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, errorMessageType, keyword, validationContext); + public FormatValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, + Schema parentSchema, SchemaContext schemaContext, Format format, + Keyword keyword) { + super(schemaLocation, evaluationPath, schemaNode, parentSchema, keyword, schemaContext); this.format = format; } - public FormatValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, - JsonSchema parentSchema, ValidationContext validationContext, Format format, ValidatorTypeCode type) { - this(schemaLocation, evaluationPath, schemaNode, parentSchema, validationContext, format, type, type); - } - /** * Gets the annotation value. * @@ -56,8 +57,8 @@ protected Object getAnnotationValue() { return this.schemaNode.isTextual() ? schemaNode.textValue() : null; } - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) { - debug(logger, executionContext, node, rootNode, instanceLocation); + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation) { + /* * Annotations must be collected even if the format is unknown according to the specification. */ @@ -72,12 +73,12 @@ public void validate(ExecutionContext executionContext, JsonNode node, JsonNode boolean assertionsEnabled = isAssertionsEnabled(executionContext); if (this.format != null) { try { - format.validate(executionContext, validationContext, node, rootNode, instanceLocation, + format.validate(executionContext, schemaContext, node, rootNode, instanceLocation, assertionsEnabled, - () -> this.message().instanceNode(node).instanceLocation(instanceLocation) + () -> this.error().instanceNode(node).instanceLocation(instanceLocation) .messageKey(format.getMessageKey()) .locale(executionContext.getExecutionConfig().getLocale()) - .failFast(executionContext.isFailFast()), + , this); } catch (PatternSyntaxException pse) { // String is considered valid if pattern is invalid @@ -98,13 +99,13 @@ public void validate(ExecutionContext executionContext, JsonNode node, JsonNode * @param instanceLocation the instance location */ protected void validateUnknownFormat(ExecutionContext executionContext, - JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) { + JsonNode node, JsonNode rootNode, NodePath instanceLocation) { /* * Unknown formats should create an assertion if the vocab is specified * according to the specification. */ if (createUnknownFormatAssertions(executionContext) && this.schemaNode.isTextual()) { - executionContext.addError(message().instanceLocation(instanceLocation).instanceNode(node) + executionContext.addError(error().instanceLocation(instanceLocation).instanceNode(node) .messageKey("format.unknown").arguments(schemaNode.textValue()).build()); } } @@ -136,6 +137,6 @@ protected boolean createUnknownFormatAssertions(ExecutionContext executionContex * @return whether to perform strict handling */ protected boolean isStrict(ExecutionContext executionContext) { - return this.validationContext.getConfig().isStrict(getKeyword(), Boolean.FALSE); + return this.schemaContext.getSchemaRegistryConfig().isStrict(getKeyword(), Boolean.FALSE); } } diff --git a/src/main/java/com/networknt/schema/IfValidator.java b/src/main/java/com/networknt/schema/keyword/IfValidator.java similarity index 68% rename from src/main/java/com/networknt/schema/IfValidator.java rename to src/main/java/com/networknt/schema/keyword/IfValidator.java index 5a4bfb2e5..65923bdc6 100644 --- a/src/main/java/com/networknt/schema/IfValidator.java +++ b/src/main/java/com/networknt/schema/keyword/IfValidator.java @@ -14,46 +14,47 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import com.fasterxml.jackson.databind.JsonNode; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.networknt.schema.Error; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.SchemaContext; import java.util.*; /** - * {@link JsonValidator} for if. + * {@link KeywordValidator} for if. */ -public class IfValidator extends BaseJsonValidator { - private static final Logger logger = LoggerFactory.getLogger(IfValidator.class); - +public class IfValidator extends BaseKeywordValidator { private static final List KEYWORDS = Arrays.asList("if", "then", "else"); - private final JsonSchema ifSchema; - private final JsonSchema thenSchema; - private final JsonSchema elseSchema; + private final Schema ifSchema; + private final Schema thenSchema; + private final Schema elseSchema; - public IfValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.IF_THEN_ELSE, validationContext); + public IfValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, Schema parentSchema, SchemaContext schemaContext) { + super(KeywordType.IF_THEN_ELSE, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); - JsonSchema foundIfSchema = null; - JsonSchema foundThenSchema = null; - JsonSchema foundElseSchema = null; + Schema foundIfSchema = null; + Schema foundThenSchema = null; + Schema foundElseSchema = null; for (final String keyword : KEYWORDS) { final JsonNode node = parentSchema.getSchemaNode().get(keyword); - final SchemaLocation schemaLocationOfSchema = parentSchema.schemaLocation.append(keyword); - final JsonNodePath evaluationPathOfSchema = parentSchema.evaluationPath.append(keyword); + final SchemaLocation schemaLocationOfSchema = parentSchema.getSchemaLocation().append(keyword); + final NodePath evaluationPathOfSchema = parentSchema.getEvaluationPath().append(keyword); if (keyword.equals("if")) { - foundIfSchema = validationContext.newSchema(schemaLocationOfSchema, evaluationPathOfSchema, node, + foundIfSchema = schemaContext.newSchema(schemaLocationOfSchema, evaluationPathOfSchema, node, parentSchema); } else if (keyword.equals("then") && node != null) { - foundThenSchema = validationContext.newSchema(schemaLocationOfSchema, evaluationPathOfSchema, node, + foundThenSchema = schemaContext.newSchema(schemaLocationOfSchema, evaluationPathOfSchema, node, parentSchema); } else if (keyword.equals("else") && node != null) { - foundElseSchema = validationContext.newSchema(schemaLocationOfSchema, evaluationPathOfSchema, node, + foundElseSchema = schemaContext.newSchema(schemaLocationOfSchema, evaluationPathOfSchema, node, parentSchema); } } @@ -64,15 +65,15 @@ public IfValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, J } @Override - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) { - debug(logger, executionContext, node, rootNode, instanceLocation); + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation) { + boolean ifConditionPassed = false; // Save flag as nested schema evaluation shouldn't trigger fail fast boolean failFast = executionContext.isFailFast(); - List existingErrors = executionContext.getErrors(); - List test = new ArrayList<>(); + List existingErrors = executionContext.getErrors(); + List test = new ArrayList<>(); executionContext.setErrors(test); try { executionContext.setFailFast(false); @@ -92,7 +93,7 @@ public void validate(ExecutionContext executionContext, JsonNode node, JsonNode } @Override - public void preloadJsonSchema() { + public void preloadSchema() { if (null != this.ifSchema) { this.ifSchema.initializeValidators(); } @@ -105,14 +106,14 @@ public void preloadJsonSchema() { } @Override - public void walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation, boolean shouldValidateSchema) { + public void walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation, boolean shouldValidateSchema) { boolean checkCondition = node != null && shouldValidateSchema; boolean ifConditionPassed = false; // Save flag as nested schema evaluation shouldn't trigger fail fast boolean failFast = executionContext.isFailFast(); - List existingErrors = executionContext.getErrors(); - List test = new ArrayList<>(); + List existingErrors = executionContext.getErrors(); + List test = new ArrayList<>(); executionContext.setErrors(test); try { executionContext.setFailFast(false); diff --git a/src/main/java/com/networknt/schema/ItemsValidator.java b/src/main/java/com/networknt/schema/keyword/ItemsLegacyValidator.java similarity index 74% rename from src/main/java/com/networknt/schema/ItemsValidator.java rename to src/main/java/com/networknt/schema/keyword/ItemsLegacyValidator.java index 0cf913cd4..92ead9533 100644 --- a/src/main/java/com/networknt/schema/ItemsValidator.java +++ b/src/main/java/com/networknt/schema/keyword/ItemsLegacyValidator.java @@ -14,53 +14,55 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ArrayNode; -import com.networknt.schema.annotation.JsonNodeAnnotation; -import com.networknt.schema.utils.JsonSchemaRefs; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaRef; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.SchemaContext; +import com.networknt.schema.annotation.Annotation; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.utils.SchemaRefs; import java.util.*; /** - * {@link JsonValidator} for items V4 to V2019-09. + * {@link KeywordValidator} for items Draft 4 to Draft 2019-09. */ -public class ItemsValidator extends BaseJsonValidator { - private static final Logger logger = LoggerFactory.getLogger(ItemsValidator.class); +public class ItemsLegacyValidator extends BaseKeywordValidator { private static final String PROPERTY_ADDITIONAL_ITEMS = "additionalItems"; - private final JsonSchema schema; - private final List tupleSchema; + private final Schema schema; + private final List tupleSchema; private final Boolean additionalItems; - private final JsonSchema additionalSchema; + private final Schema additionalSchema; private Boolean hasUnevaluatedItemsValidator = null; - private final JsonNodePath additionalItemsEvaluationPath; + private final NodePath additionalItemsEvaluationPath; private final SchemaLocation additionalItemsSchemaLocation; private final JsonNode additionalItemsSchemaNode; - public ItemsValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.ITEMS, validationContext); + public ItemsLegacyValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, Schema parentSchema, SchemaContext schemaContext) { + super(KeywordType.ITEMS_LEGACY, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); Boolean additionalItems = null; - JsonSchema foundSchema = null; - JsonSchema foundAdditionalSchema = null; + Schema foundSchema = null; + Schema foundAdditionalSchema = null; JsonNode additionalItemsSchemaNode = null; if (schemaNode.isObject() || schemaNode.isBoolean()) { - foundSchema = validationContext.newSchema(schemaLocation, evaluationPath, schemaNode, parentSchema); + foundSchema = schemaContext.newSchema(schemaLocation, evaluationPath, schemaNode, parentSchema); this.tupleSchema = Collections.emptyList(); } else { int i = 0; this.tupleSchema = new ArrayList<>(schemaNode.size()); for (JsonNode s : schemaNode) { - this.tupleSchema.add(validationContext.newSchema(schemaLocation.append(i), evaluationPath.append(i), + this.tupleSchema.add(schemaContext.newSchema(schemaLocation.append(i), evaluationPath.append(i), s, parentSchema)); i++; } @@ -71,25 +73,25 @@ public ItemsValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath if (addItemNode.isBoolean()) { additionalItems = addItemNode.asBoolean(); } else if (addItemNode.isObject()) { - foundAdditionalSchema = validationContext.newSchema( - parentSchema.schemaLocation.append(PROPERTY_ADDITIONAL_ITEMS), - parentSchema.evaluationPath.append(PROPERTY_ADDITIONAL_ITEMS), addItemNode, parentSchema); + foundAdditionalSchema = schemaContext.newSchema( + parentSchema.getSchemaLocation().append(PROPERTY_ADDITIONAL_ITEMS), + parentSchema.getEvaluationPath().append(PROPERTY_ADDITIONAL_ITEMS), addItemNode, parentSchema); } } } this.additionalItems = additionalItems; this.schema = foundSchema; this.additionalSchema = foundAdditionalSchema; - this.additionalItemsEvaluationPath = parentSchema.evaluationPath.append(PROPERTY_ADDITIONAL_ITEMS); - this.additionalItemsSchemaLocation = parentSchema.schemaLocation.append(PROPERTY_ADDITIONAL_ITEMS); + this.additionalItemsEvaluationPath = parentSchema.getEvaluationPath().append(PROPERTY_ADDITIONAL_ITEMS); + this.additionalItemsSchemaLocation = parentSchema.getSchemaLocation().append(PROPERTY_ADDITIONAL_ITEMS); this.additionalItemsSchemaNode = additionalItemsSchemaNode; } @Override - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) { - debug(logger, executionContext, node, rootNode, instanceLocation); + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation) { + - if (!node.isArray() && !this.validationContext.getConfig().isTypeLoose()) { + if (!node.isArray() && !this.schemaContext.getSchemaRegistryConfig().isTypeLoose()) { // ignores non-arrays return; } @@ -100,7 +102,7 @@ public void validate(ExecutionContext executionContext, JsonNode node, JsonNode if (this.schema != null) { // Applies to all executionContext.getAnnotations() - .put(JsonNodeAnnotation.builder().instanceLocation(instanceLocation) + .put(Annotation.builder().instanceLocation(instanceLocation) .evaluationPath(this.evaluationPath).schemaLocation(this.schemaLocation) .keyword(getKeyword()).value(true).build()); } else if (this.tupleSchema != null) { @@ -110,13 +112,13 @@ public void validate(ExecutionContext executionContext, JsonNode node, JsonNode if (items > schemas) { // More items than schemas so the keyword only applied to the number of schemas executionContext.getAnnotations() - .put(JsonNodeAnnotation.builder().instanceLocation(instanceLocation) + .put(Annotation.builder().instanceLocation(instanceLocation) .evaluationPath(this.evaluationPath).schemaLocation(this.schemaLocation) .keyword(getKeyword()).value(schemas).build()); } else { // Applies to all executionContext.getAnnotations() - .put(JsonNodeAnnotation.builder().instanceLocation(instanceLocation) + .put(Annotation.builder().instanceLocation(instanceLocation) .evaluationPath(this.evaluationPath).schemaLocation(this.schemaLocation) .keyword(getKeyword()).value(true).build()); } @@ -141,7 +143,7 @@ public void validate(ExecutionContext executionContext, JsonNode node, JsonNode if (hasAdditionalItem) { if (collectAnnotations || collectAnnotations(executionContext, "additionalItems")) { executionContext.getAnnotations() - .put(JsonNodeAnnotation.builder().instanceLocation(instanceLocation) + .put(Annotation.builder().instanceLocation(instanceLocation) .evaluationPath(this.additionalItemsEvaluationPath) .schemaLocation(this.additionalItemsSchemaLocation) .keyword("additionalItems").value(true).build()); @@ -150,9 +152,9 @@ public void validate(ExecutionContext executionContext, JsonNode node, JsonNode } private boolean doValidate(ExecutionContext executionContext, int i, JsonNode node, - JsonNode rootNode, JsonNodePath instanceLocation) { + JsonNode rootNode, NodePath instanceLocation) { boolean isAdditionalItem = false; - JsonNodePath path = instanceLocation.append(i); + NodePath path = instanceLocation.append(i); if (this.schema != null) { // validate with item schema (the whole array has the same item @@ -175,14 +177,15 @@ private boolean doValidate(ExecutionContext executionContext, int i, JsonNode no // evaluatedItems.add(path); } else { // no additional item allowed, return error - executionContext.addError(message().instanceNode(rootNode).instanceLocation(instanceLocation) - .type("additionalItems") + executionContext.addError(error().instanceNode(rootNode).instanceLocation(instanceLocation) + .keyword("additionalItems") .messageKey("additionalItems") .evaluationPath(this.additionalItemsEvaluationPath) .schemaLocation(this.additionalItemsSchemaLocation) .schemaNode(this.additionalItemsSchemaNode) .locale(executionContext.getExecutionConfig().getLocale()) - .failFast(executionContext.isFailFast()).arguments(i).build()); + .index(i) + .arguments(i).build()); } } } @@ -191,7 +194,7 @@ private boolean doValidate(ExecutionContext executionContext, int i, JsonNode no } @Override - public void walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation, boolean shouldValidateSchema) { + public void walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation, boolean shouldValidateSchema) { boolean collectAnnotations = collectAnnotations(); // Add items annotation @@ -199,7 +202,7 @@ public void walk(ExecutionContext executionContext, JsonNode node, JsonNode root if (this.schema != null) { // Applies to all executionContext.getAnnotations() - .put(JsonNodeAnnotation.builder().instanceLocation(instanceLocation) + .put(Annotation.builder().instanceLocation(instanceLocation) .evaluationPath(this.evaluationPath).schemaLocation(this.schemaLocation) .keyword(getKeyword()).value(true).build()); } else if (this.tupleSchema != null) { @@ -209,13 +212,13 @@ public void walk(ExecutionContext executionContext, JsonNode node, JsonNode root if (items > schemas) { // More items than schemas so the keyword only applied to the number of schemas executionContext.getAnnotations() - .put(JsonNodeAnnotation.builder().instanceLocation(instanceLocation) + .put(Annotation.builder().instanceLocation(instanceLocation) .evaluationPath(this.evaluationPath).schemaLocation(this.schemaLocation) .keyword(getKeyword()).value(schemas).build()); } else { // Applies to all executionContext.getAnnotations() - .put(JsonNodeAnnotation.builder().instanceLocation(instanceLocation) + .put(Annotation.builder().instanceLocation(instanceLocation) .evaluationPath(this.evaluationPath).schemaLocation(this.schemaLocation) .keyword(getKeyword()).value(true).build()); } @@ -228,7 +231,7 @@ public void walk(ExecutionContext executionContext, JsonNode node, JsonNode root int count = Math.max(1, node.size()); ArrayNode arrayNode = (ArrayNode) node; JsonNode defaultNode = null; - if (this.validationContext.getConfig().getApplyDefaultsStrategy().shouldApplyArrayDefaults()) { + if (executionContext.getWalkConfig().getApplyDefaultsStrategy().shouldApplyArrayDefaults()) { defaultNode = getDefaultNode(this.schema); } for (int i = 0; i < count; i++) { @@ -239,10 +242,10 @@ public void walk(ExecutionContext executionContext, JsonNode node, JsonNode root n = defaultNode; } } - walkSchema(executionContext, this.schema, n, rootNode, instanceLocation.append(i), shouldValidateSchema, ValidatorTypeCode.ITEMS.getValue()); + walkSchema(executionContext, this.schema, n, rootNode, instanceLocation.append(i), shouldValidateSchema, KeywordType.ITEMS_LEGACY.getValue()); } } else { - walkSchema(executionContext, this.schema, null, rootNode, instanceLocation.append(0), shouldValidateSchema, ValidatorTypeCode.ITEMS.getValue()); + walkSchema(executionContext, this.schema, null, rootNode, instanceLocation.append(0), shouldValidateSchema, KeywordType.ITEMS_LEGACY.getValue()); } } else if (this.tupleSchema != null) { @@ -253,7 +256,7 @@ else if (this.tupleSchema != null) { ArrayNode arrayNode = (ArrayNode) node; JsonNode defaultNode = null; JsonNode n = arrayNode.get(i); - if (this.validationContext.getConfig().getApplyDefaultsStrategy().shouldApplyArrayDefaults()) { + if (executionContext.getWalkConfig().getApplyDefaultsStrategy().shouldApplyArrayDefaults()) { defaultNode = getDefaultNode(this.tupleSchema.get(i)); } if (n != null) { @@ -263,10 +266,10 @@ else if (this.tupleSchema != null) { } } walkSchema(executionContext, this.tupleSchema.get(i), n, rootNode, instanceLocation.append(i), - shouldValidateSchema, ValidatorTypeCode.ITEMS.getValue()); + shouldValidateSchema, KeywordType.ITEMS_LEGACY.getValue()); } else { walkSchema(executionContext, this.tupleSchema.get(i), null, rootNode, instanceLocation.append(i), - shouldValidateSchema, ValidatorTypeCode.ITEMS.getValue()); + shouldValidateSchema, KeywordType.ITEMS_LEGACY.getValue()); } } if (this.additionalSchema != null) { @@ -280,7 +283,7 @@ else if (this.tupleSchema != null) { ArrayNode arrayNode = (ArrayNode) node; JsonNode defaultNode = null; JsonNode n = arrayNode.get(i); - if (this.validationContext.getConfig().getApplyDefaultsStrategy().shouldApplyArrayDefaults()) { + if (executionContext.getWalkConfig().getApplyDefaultsStrategy().shouldApplyArrayDefaults()) { defaultNode = getDefaultNode(this.additionalSchema); } if (n != null) { @@ -303,7 +306,7 @@ else if (this.tupleSchema != null) { if (hasAdditionalItem) { if (collectAnnotations || collectAnnotations(executionContext, "additionalItems")) { executionContext.getAnnotations() - .put(JsonNodeAnnotation.builder().instanceLocation(instanceLocation) + .put(Annotation.builder().instanceLocation(instanceLocation) .evaluationPath(this.additionalItemsEvaluationPath) .schemaLocation(this.additionalItemsSchemaLocation) .keyword("additionalItems").value(true).build()); @@ -313,10 +316,10 @@ else if (this.tupleSchema != null) { } } - private static JsonNode getDefaultNode(JsonSchema schema) { + private static JsonNode getDefaultNode(Schema schema) { JsonNode result = schema.getSchemaNode().get("default"); if (result == null) { - JsonSchemaRef schemaRef = JsonSchemaRefs.from(schema); + SchemaRef schemaRef = SchemaRefs.from(schema); if (schemaRef != null) { result = getDefaultNode(schemaRef.getSchema()); } @@ -324,24 +327,24 @@ private static JsonNode getDefaultNode(JsonSchema schema) { return result; } - private void walkSchema(ExecutionContext executionContext, JsonSchema walkSchema, JsonNode node, JsonNode rootNode, - JsonNodePath instanceLocation, boolean shouldValidateSchema, String keyword) { - boolean executeWalk = this.validationContext.getConfig().getItemWalkListenerRunner().runPreWalkListeners(executionContext, keyword, + private void walkSchema(ExecutionContext executionContext, Schema walkSchema, JsonNode node, JsonNode rootNode, + NodePath instanceLocation, boolean shouldValidateSchema, String keyword) { + boolean executeWalk = executionContext.getWalkConfig().getItemWalkListenerRunner().runPreWalkListeners(executionContext, keyword, node, rootNode, instanceLocation, walkSchema, this); int currentErrors = executionContext.getErrors().size(); if (executeWalk) { walkSchema.walk(executionContext, node, rootNode, instanceLocation, shouldValidateSchema); } - this.validationContext.getConfig().getItemWalkListenerRunner().runPostWalkListeners(executionContext, keyword, node, rootNode, + executionContext.getWalkConfig().getItemWalkListenerRunner().runPostWalkListeners(executionContext, keyword, node, rootNode, instanceLocation, walkSchema, this, executionContext.getErrors().subList(currentErrors, executionContext.getErrors().size())); } - public List getTupleSchema() { + public List getTupleSchema() { return this.tupleSchema; } - public JsonSchema getSchema() { + public Schema getSchema() { return this.schema; } @@ -357,11 +360,11 @@ private boolean hasUnevaluatedItemsValidator() { } @Override - public void preloadJsonSchema() { + public void preloadSchema() { if (null != this.schema) { this.schema.initializeValidators(); } - preloadJsonSchemas(this.tupleSchema); + preloadSchemas(this.tupleSchema); if (null != this.additionalSchema) { this.additionalSchema.initializeValidators(); } diff --git a/src/main/java/com/networknt/schema/ItemsValidator202012.java b/src/main/java/com/networknt/schema/keyword/ItemsValidator.java similarity index 71% rename from src/main/java/com/networknt/schema/ItemsValidator202012.java rename to src/main/java/com/networknt/schema/keyword/ItemsValidator.java index 859f7542a..644f2e62d 100644 --- a/src/main/java/com/networknt/schema/ItemsValidator202012.java +++ b/src/main/java/com/networknt/schema/keyword/ItemsValidator.java @@ -14,32 +14,33 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ArrayNode; -import com.networknt.schema.annotation.JsonNodeAnnotation; -import com.networknt.schema.utils.JsonSchemaRefs; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaRef; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.SchemaContext; +import com.networknt.schema.annotation.Annotation; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.utils.SchemaRefs; /** - * {@link JsonValidator} for items from V2012-12. + * {@link KeywordValidator} for items from Draft 2012-12. */ -public class ItemsValidator202012 extends BaseJsonValidator { - private static final Logger logger = LoggerFactory.getLogger(ItemsValidator202012.class); - - private final JsonSchema schema; +public class ItemsValidator extends BaseKeywordValidator { + private final Schema schema; private final int prefixCount; private final boolean additionalItems; private Boolean hasUnevaluatedItemsValidator = null; - public ItemsValidator202012(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, - JsonSchema parentSchema, ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.ITEMS_202012, - validationContext); + public ItemsValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, + Schema parentSchema, SchemaContext schemaContext) { + super(KeywordType.ITEMS, schemaNode, schemaLocation, parentSchema, schemaContext, + evaluationPath); JsonNode prefixItems = parentSchema.getSchemaNode().get("prefixItems"); if (prefixItems instanceof ArrayNode) { @@ -51,7 +52,7 @@ public ItemsValidator202012(SchemaLocation schemaLocation, JsonNodePath evaluati } if (schemaNode.isObject() || schemaNode.isBoolean()) { - this.schema = validationContext.newSchema(schemaLocation, evaluationPath, schemaNode, parentSchema); + this.schema = schemaContext.newSchema(schemaLocation, evaluationPath, schemaNode, parentSchema); } else { throw new IllegalArgumentException("The value of 'items' MUST be a valid JSON Schema."); } @@ -61,14 +62,14 @@ public ItemsValidator202012(SchemaLocation schemaLocation, JsonNodePath evaluati @Override public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, - JsonNodePath instanceLocation) { - debug(logger, executionContext, node, rootNode, instanceLocation); + NodePath instanceLocation) { + // ignores non-arrays if (node.isArray()) { boolean evaluated = false; for (int i = this.prefixCount; i < node.size(); ++i) { - JsonNodePath path = instanceLocation.append(i); + NodePath path = instanceLocation.append(i); // validate with item schema (the whole array has the same item schema) if (additionalItems) { this.schema.validate(executionContext, node.get(i), rootNode, path); @@ -76,9 +77,9 @@ public void validate(ExecutionContext executionContext, JsonNode node, JsonNode // This handles the case where "items": false as the boolean false schema doesn't // generate a helpful message int x = i; - executionContext.addError(message().instanceNode(node).instanceLocation(instanceLocation) + executionContext.addError(error().instanceNode(node).instanceLocation(instanceLocation) .locale(executionContext.getExecutionConfig().getLocale()) - .failFast(executionContext.isFailFast()).arguments(x).build()); + .index(x).arguments(x).build()); } evaluated = true; } @@ -86,7 +87,7 @@ public void validate(ExecutionContext executionContext, JsonNode node, JsonNode if (collectAnnotations() || collectAnnotations(executionContext)) { // Applies to all executionContext.getAnnotations() - .put(JsonNodeAnnotation.builder().instanceLocation(instanceLocation) + .put(Annotation.builder().instanceLocation(instanceLocation) .evaluationPath(this.evaluationPath).schemaLocation(this.schemaLocation) .keyword(getKeyword()).value(true).build()); } @@ -96,11 +97,11 @@ public void validate(ExecutionContext executionContext, JsonNode node, JsonNode @Override public void walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, - JsonNodePath instanceLocation, boolean shouldValidateSchema) { + NodePath instanceLocation, boolean shouldValidateSchema) { if (node instanceof ArrayNode) { ArrayNode arrayNode = (ArrayNode) node; JsonNode defaultNode = null; - if (this.validationContext.getConfig().getApplyDefaultsStrategy().shouldApplyArrayDefaults() + if (executionContext.getWalkConfig().getApplyDefaultsStrategy().shouldApplyArrayDefaults() && this.schema != null) { defaultNode = getDefaultNode(this.schema); } @@ -121,7 +122,7 @@ public void walk(ExecutionContext executionContext, JsonNode node, JsonNode root if (collectAnnotations() || collectAnnotations(executionContext)) { // Applies to all executionContext.getAnnotations() - .put(JsonNodeAnnotation.builder().instanceLocation(instanceLocation) + .put(Annotation.builder().instanceLocation(instanceLocation) .evaluationPath(this.evaluationPath).schemaLocation(this.schemaLocation) .keyword(getKeyword()).value(true).build()); } @@ -134,10 +135,10 @@ public void walk(ExecutionContext executionContext, JsonNode node, JsonNode root } } - private static JsonNode getDefaultNode(JsonSchema schema) { + private static JsonNode getDefaultNode(Schema schema) { JsonNode result = schema.getSchemaNode().get("default"); if (result == null) { - JsonSchemaRef schemaRef = JsonSchemaRefs.from(schema); + SchemaRef schemaRef = SchemaRefs.from(schema); if (schemaRef != null) { result = getDefaultNode(schemaRef.getSchema()); } @@ -145,12 +146,12 @@ private static JsonNode getDefaultNode(JsonSchema schema) { return result; } - private void walkSchema(ExecutionContext executionContext, JsonSchema walkSchema, JsonNode node, JsonNode rootNode, - JsonNodePath instanceLocation, boolean shouldValidateSchema) { + private void walkSchema(ExecutionContext executionContext, Schema walkSchema, JsonNode node, JsonNode rootNode, + NodePath instanceLocation, boolean shouldValidateSchema) { //@formatter:off - boolean executeWalk = this.validationContext.getConfig().getItemWalkListenerRunner().runPreWalkListeners( + boolean executeWalk = executionContext.getWalkConfig().getItemWalkListenerRunner().runPreWalkListeners( executionContext, - ValidatorTypeCode.ITEMS.getValue(), + KeywordType.ITEMS_LEGACY.getValue(), node, rootNode, instanceLocation, @@ -160,9 +161,9 @@ private void walkSchema(ExecutionContext executionContext, JsonSchema walkSchema if (executeWalk) { walkSchema.walk(executionContext, node, rootNode, instanceLocation, shouldValidateSchema); } - this.validationContext.getConfig().getItemWalkListenerRunner().runPostWalkListeners( + executionContext.getWalkConfig().getItemWalkListenerRunner().runPostWalkListeners( executionContext, - ValidatorTypeCode.ITEMS.getValue(), + KeywordType.ITEMS_LEGACY.getValue(), node, rootNode, instanceLocation, @@ -172,12 +173,12 @@ private void walkSchema(ExecutionContext executionContext, JsonSchema walkSchema //@formatter:on } - public JsonSchema getSchema() { + public Schema getSchema() { return this.schema; } @Override - public void preloadJsonSchema() { + public void preloadSchema() { this.schema.initializeValidators(); collectAnnotations(); // cache the flag } diff --git a/src/main/java/com/networknt/schema/Keyword.java b/src/main/java/com/networknt/schema/keyword/Keyword.java similarity index 68% rename from src/main/java/com/networknt/schema/Keyword.java rename to src/main/java/com/networknt/schema/keyword/Keyword.java index 592c80384..93a01b666 100644 --- a/src/main/java/com/networknt/schema/Keyword.java +++ b/src/main/java/com/networknt/schema/keyword/Keyword.java @@ -14,9 +14,14 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import com.fasterxml.jackson.databind.JsonNode; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaException; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.SchemaContext; /** * Represents a keyword. @@ -36,11 +41,11 @@ public interface Keyword { * @param evaluationPath the evaluation path * @param schemaNode the schema node * @param parentSchema the parent schema - * @param validationContext the validation context + * @param schemaContext the schema context * @return the validation - * @throws JsonSchemaException the exception + * @throws SchemaException the exception * @throws Exception the exception */ - JsonValidator newValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, - JsonSchema parentSchema, ValidationContext validationContext) throws JsonSchemaException, Exception; + KeywordValidator newValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, + Schema parentSchema, SchemaContext schemaContext) throws SchemaException, Exception; } diff --git a/src/main/java/com/networknt/schema/KeywordFactory.java b/src/main/java/com/networknt/schema/keyword/KeywordFactory.java similarity index 78% rename from src/main/java/com/networknt/schema/KeywordFactory.java rename to src/main/java/com/networknt/schema/keyword/KeywordFactory.java index e887bc580..f1f6967d2 100644 --- a/src/main/java/com/networknt/schema/KeywordFactory.java +++ b/src/main/java/com/networknt/schema/keyword/KeywordFactory.java @@ -13,7 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; + +import com.networknt.schema.SchemaContext; /** * Factory for {@link Keyword}. @@ -24,8 +26,8 @@ public interface KeywordFactory { * Gets the keyword given the keyword value. * * @param value the keyword value - * @param validationContext the validationContext + * @param schemaContext the schemaContext * @return the keyword */ - Keyword getKeyword(String value, ValidationContext validationContext); + Keyword getKeyword(String value, SchemaContext schemaContext); } diff --git a/src/main/java/com/networknt/schema/keyword/KeywordType.java b/src/main/java/com/networknt/schema/keyword/KeywordType.java new file mode 100644 index 000000000..d89e4b1ca --- /dev/null +++ b/src/main/java/com/networknt/schema/keyword/KeywordType.java @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2016 Network New Technologies Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.networknt.schema.keyword; + +import com.fasterxml.jackson.databind.JsonNode; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.SpecificationVersion; +import com.networknt.schema.SpecificationVersionRange; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.SchemaContext; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@FunctionalInterface +interface ValidatorFactory { + KeywordValidator newInstance(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, + Schema parentSchema, SchemaContext schemaContext); +} + +public enum KeywordType implements Keyword { + ADDITIONAL_PROPERTIES("additionalProperties", AdditionalPropertiesValidator::new, SpecificationVersionRange.MAX_DRAFT_7), + ALL_OF("allOf", AllOfValidator::new, SpecificationVersionRange.MAX_DRAFT_7), + ANY_OF("anyOf", AnyOfValidator::new, SpecificationVersionRange.MAX_DRAFT_7), + CONST("const", ConstValidator::new, SpecificationVersionRange.DRAFT_6_TO_DRAFT_7), + CONTAINS("contains", ContainsValidator::new, SpecificationVersionRange.DRAFT_6_TO_DRAFT_7), + CONTENT_ENCODING("contentEncoding", ContentEncodingValidator::new, SpecificationVersionRange.DRAFT_7), + CONTENT_MEDIA_TYPE("contentMediaType", ContentMediaTypeValidator::new, SpecificationVersionRange.DRAFT_7), + DEPENDENCIES("dependencies", DependenciesValidator::new, SpecificationVersionRange.ALL_VERSIONS), + DEPENDENT_REQUIRED("dependentRequired", DependentRequired::new, SpecificationVersionRange.NONE), + DEPENDENT_SCHEMAS("dependentSchemas", DependentSchemas::new, SpecificationVersionRange.NONE), + DISCRIMINATOR("discriminator", DiscriminatorValidator::new, SpecificationVersionRange.NONE), + DYNAMIC_REF("$dynamicRef", DynamicRefValidator::new, SpecificationVersionRange.NONE), + ENUM("enum", EnumValidator::new, SpecificationVersionRange.MAX_DRAFT_7), + EXCLUSIVE_MAXIMUM("exclusiveMaximum", ExclusiveMaximumValidator::new, SpecificationVersionRange.DRAFT_6_TO_DRAFT_7), + EXCLUSIVE_MINIMUM("exclusiveMinimum", ExclusiveMinimumValidator::new, SpecificationVersionRange.DRAFT_6_TO_DRAFT_7), + FALSE("false", FalseValidator::new, SpecificationVersionRange.MIN_DRAFT_6), + FORMAT("format", null, SpecificationVersionRange.MAX_DRAFT_7) { + @Override public KeywordValidator newValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, Schema parentSchema, SchemaContext schemaContext) { + throw new UnsupportedOperationException("Use FormatKeyword instead"); + } + }, + ID("id", null, SpecificationVersionRange.ALL_VERSIONS), + IF_THEN_ELSE("if", IfValidator::new, SpecificationVersionRange.DRAFT_7), + ITEMS("items", ItemsValidator::new, SpecificationVersionRange.NONE), + ITEMS_LEGACY("items", ItemsLegacyValidator::new, SpecificationVersionRange.MAX_DRAFT_7), + MAX_CONTAINS("maxContains",MinMaxContainsValidator::new, SpecificationVersionRange.NONE), + MAX_ITEMS("maxItems", MaxItemsValidator::new, SpecificationVersionRange.MAX_DRAFT_7), + MAX_LENGTH("maxLength", MaxLengthValidator::new, SpecificationVersionRange.MAX_DRAFT_7), + MAX_PROPERTIES("maxProperties", MaxPropertiesValidator::new, SpecificationVersionRange.MAX_DRAFT_7), + MAXIMUM("maximum", MaximumValidator::new, SpecificationVersionRange.MAX_DRAFT_7), + MIN_CONTAINS("minContains", MinMaxContainsValidator::new, SpecificationVersionRange.NONE), + MIN_ITEMS("minItems", MinItemsValidator::new, SpecificationVersionRange.MAX_DRAFT_7), + MIN_LENGTH("minLength", MinLengthValidator::new, SpecificationVersionRange.MAX_DRAFT_7), + MIN_PROPERTIES("minProperties", MinPropertiesValidator::new, SpecificationVersionRange.MAX_DRAFT_7), + MINIMUM("minimum", MinimumValidator::new, SpecificationVersionRange.MAX_DRAFT_7), + MULTIPLE_OF("multipleOf", MultipleOfValidator::new, SpecificationVersionRange.MAX_DRAFT_7), + NOT_ALLOWED("notAllowed", NotAllowedValidator::new, SpecificationVersionRange.ALL_VERSIONS), + NOT("not", NotValidator::new, SpecificationVersionRange.MAX_DRAFT_7), + ONE_OF("oneOf", OneOfValidator::new, SpecificationVersionRange.MAX_DRAFT_7), + PATTERN_PROPERTIES("patternProperties", PatternPropertiesValidator::new, SpecificationVersionRange.MAX_DRAFT_7), + PATTERN("pattern", PatternValidator::new, SpecificationVersionRange.MAX_DRAFT_7), + PREFIX_ITEMS("prefixItems", PrefixItemsValidator::new, SpecificationVersionRange.NONE), + PROPERTIES("properties", PropertiesValidator::new, SpecificationVersionRange.MAX_DRAFT_7), + PROPERTY_DEPENDENCIES("propertyDependencies", PropertyDependenciesValidator::new, SpecificationVersionRange.NONE), + PROPERTY_NAMES("propertyNames", PropertyNamesValidator::new, SpecificationVersionRange.DRAFT_6_TO_DRAFT_7), + READ_ONLY("readOnly", ReadOnlyValidator::new, SpecificationVersionRange.DRAFT_7), + RECURSIVE_REF("$recursiveRef", RecursiveRefValidator::new, SpecificationVersionRange.NONE), + REF("$ref", RefValidator::new, SpecificationVersionRange.MAX_DRAFT_7), + REQUIRED("required", RequiredValidator::new, SpecificationVersionRange.MAX_DRAFT_7), + TRUE("true", TrueValidator::new, SpecificationVersionRange.MIN_DRAFT_6), + TYPE("type", TypeValidator::new, SpecificationVersionRange.MAX_DRAFT_7), + UNEVALUATED_ITEMS("unevaluatedItems", UnevaluatedItemsValidator::new, SpecificationVersionRange.NONE), + UNEVALUATED_PROPERTIES("unevaluatedProperties",UnevaluatedPropertiesValidator::new,SpecificationVersionRange.NONE), + UNION_TYPE("unionType", UnionTypeValidator::new, SpecificationVersionRange.NONE), + UNIQUE_ITEMS("uniqueItems", UniqueItemsValidator::new, SpecificationVersionRange.MAX_DRAFT_7), + WRITE_ONLY("writeOnly", WriteOnlyValidator::new, SpecificationVersionRange.DRAFT_7), + ; + + private static final Map CONSTANTS = new HashMap<>(); + + static { + for (KeywordType c : values()) { + CONSTANTS.put(c.value, c); + } + } + + private final String value; + private final ValidatorFactory validatorFactory; + private final SpecificationVersionRange specificationVersionRange; + + KeywordType(String value, ValidatorFactory validatorFactory, SpecificationVersionRange specificationVersionRange) { + this.value = value; + this.validatorFactory = validatorFactory; + this.specificationVersionRange = specificationVersionRange; + } + + public static List getKeywords(SpecificationVersion specificationVersion) { + final List result = new ArrayList<>(); + for (KeywordType keyword : values()) { + if (keyword.getSpecificationVersionRange().getVersions().contains(specificationVersion)) { + result.add(keyword); + } + } + return result; + } + + public static KeywordType fromValue(String value) { + KeywordType constant = CONSTANTS.get(value); + if (constant == null) { + throw new IllegalArgumentException(value); + } + return constant; + } + + @Override + public KeywordValidator newValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, + Schema parentSchema, SchemaContext schemaContext) { + if (this.validatorFactory == null) { + throw new UnsupportedOperationException("No suitable validator for " + getValue()); + } + return validatorFactory.newInstance(schemaLocation, evaluationPath, schemaNode, parentSchema, + schemaContext); + } + + @Override + public String toString() { + return this.value; + } + + @Override + public String getValue() { + return this.value; + } + + public SpecificationVersionRange getSpecificationVersionRange() { + return this.specificationVersionRange; + } +} diff --git a/src/main/java/com/networknt/schema/JsonValidator.java b/src/main/java/com/networknt/schema/keyword/KeywordValidator.java similarity index 60% rename from src/main/java/com/networknt/schema/JsonValidator.java rename to src/main/java/com/networknt/schema/keyword/KeywordValidator.java index d81d01bb8..dbf561da8 100644 --- a/src/main/java/com/networknt/schema/JsonValidator.java +++ b/src/main/java/com/networknt/schema/keyword/KeywordValidator.java @@ -14,21 +14,24 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; + +import com.networknt.schema.SchemaException; +import com.networknt.schema.Validator; /** * KeywordValidator interface implemented by all keyword validators. */ -public interface JsonValidator extends JsonSchemaValidator { +public interface KeywordValidator extends Validator { /** - * In case the {@link com.networknt.schema.JsonValidator} has a related {@link com.networknt.schema.JsonSchema} or several - * ones, calling preloadJsonSchema will actually load the schema document(s) eagerly. + * In case the {@link com.networknt.schema.keyword.KeywordValidator} has a related {@link com.networknt.schema.Schema} or several + * ones, calling preloadSchema will actually load the schema document(s) eagerly. * - * @throws JsonSchemaException (a {@link java.lang.RuntimeException}) in case the {@link com.networknt.schema.JsonSchema} or nested schemas + * @throws SchemaException (a {@link java.lang.RuntimeException}) in case the {@link com.networknt.schema.Schema} or nested schemas * are invalid (like $ref not resolving) * @since 1.0.54 */ - default void preloadJsonSchema() throws JsonSchemaException { + default void preloadSchema() throws SchemaException { // do nothing by default - to be overridden in subclasses } diff --git a/src/main/java/com/networknt/schema/MaxItemsValidator.java b/src/main/java/com/networknt/schema/keyword/MaxItemsValidator.java similarity index 50% rename from src/main/java/com/networknt/schema/MaxItemsValidator.java rename to src/main/java/com/networknt/schema/keyword/MaxItemsValidator.java index 75a4fbcae..11b405213 100644 --- a/src/main/java/com/networknt/schema/MaxItemsValidator.java +++ b/src/main/java/com/networknt/schema/keyword/MaxItemsValidator.java @@ -14,23 +14,23 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import com.fasterxml.jackson.databind.JsonNode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.SchemaContext; /** - * {@link JsonValidator} for maxItems. + * {@link KeywordValidator} for maxItems. */ -public class MaxItemsValidator extends BaseJsonValidator implements JsonValidator { - - private static final Logger logger = LoggerFactory.getLogger(MaxItemsValidator.class); - +public class MaxItemsValidator extends BaseKeywordValidator implements KeywordValidator { private final int max; - public MaxItemsValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.MAX_ITEMS, validationContext); + public MaxItemsValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, Schema parentSchema, SchemaContext schemaContext) { + super(KeywordType.MAX_ITEMS, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); if (schemaNode.canConvertToExactIntegral()) { this.max = schemaNode.intValue(); } else { @@ -38,20 +38,20 @@ public MaxItemsValidator(SchemaLocation schemaLocation, JsonNodePath evaluationP } } - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) { - debug(logger, executionContext, node, rootNode, instanceLocation); + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation) { + if (node.isArray()) { if (node.size() > this.max) { - executionContext.addError(message().instanceNode(node).instanceLocation(instanceLocation) + executionContext.addError(error().instanceNode(node).instanceLocation(instanceLocation) .locale(executionContext.getExecutionConfig().getLocale()) - .failFast(executionContext.isFailFast()).arguments(this.max, node.size()).build()); + .arguments(this.max, node.size()).build()); } - } else if (this.validationContext.getConfig().isTypeLoose()) { + } else if (this.schemaContext.getSchemaRegistryConfig().isTypeLoose()) { if (1 > this.max) { - executionContext.addError(message().instanceNode(node).instanceLocation(instanceLocation) + executionContext.addError(error().instanceNode(node).instanceLocation(instanceLocation) .locale(executionContext.getExecutionConfig().getLocale()) - .failFast(executionContext.isFailFast()).arguments(this.max, 1).build()); + .arguments(this.max, 1).build()); } } } diff --git a/src/main/java/com/networknt/schema/MaxLengthValidator.java b/src/main/java/com/networknt/schema/keyword/MaxLengthValidator.java similarity index 55% rename from src/main/java/com/networknt/schema/MaxLengthValidator.java rename to src/main/java/com/networknt/schema/keyword/MaxLengthValidator.java index fb8504d49..bb6312092 100644 --- a/src/main/java/com/networknt/schema/MaxLengthValidator.java +++ b/src/main/java/com/networknt/schema/keyword/MaxLengthValidator.java @@ -14,22 +14,25 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import com.fasterxml.jackson.databind.JsonNode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.utils.JsonType; +import com.networknt.schema.utils.TypeFactory; +import com.networknt.schema.SchemaContext; /** - * {@link JsonValidator} for maxLength. + * {@link KeywordValidator} for maxLength. */ -public class MaxLengthValidator extends BaseJsonValidator implements JsonValidator { - private static final Logger logger = LoggerFactory.getLogger(MaxLengthValidator.class); - +public class MaxLengthValidator extends BaseKeywordValidator implements KeywordValidator { private final int maxLength; - public MaxLengthValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.MAX_LENGTH, validationContext); + public MaxLengthValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, Schema parentSchema, SchemaContext schemaContext) { + super(KeywordType.MAX_LENGTH, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); if (schemaNode != null && schemaNode.canConvertToExactIntegral()) { this.maxLength = schemaNode.intValue(); } else { @@ -37,18 +40,18 @@ public MaxLengthValidator(SchemaLocation schemaLocation, JsonNodePath evaluation } } - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) { - debug(logger, executionContext, node, rootNode, instanceLocation); + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation) { + - JsonType nodeType = TypeFactory.getValueNodeType(node, this.validationContext.getConfig()); + JsonType nodeType = TypeFactory.getValueNodeType(node, this.schemaContext.getSchemaRegistryConfig()); if (nodeType != JsonType.STRING) { // ignore no-string typs return; } if (node.textValue().codePointCount(0, node.textValue().length()) > this.maxLength) { - executionContext.addError(message().instanceNode(node).instanceLocation(instanceLocation) + executionContext.addError(error().instanceNode(node).instanceLocation(instanceLocation) .locale(executionContext.getExecutionConfig().getLocale()) - .failFast(executionContext.isFailFast()).arguments(this.maxLength).build()); + .arguments(this.maxLength).build()); } } diff --git a/src/main/java/com/networknt/schema/MaxPropertiesValidator.java b/src/main/java/com/networknt/schema/keyword/MaxPropertiesValidator.java similarity index 54% rename from src/main/java/com/networknt/schema/MaxPropertiesValidator.java rename to src/main/java/com/networknt/schema/keyword/MaxPropertiesValidator.java index 432186140..20719d936 100644 --- a/src/main/java/com/networknt/schema/MaxPropertiesValidator.java +++ b/src/main/java/com/networknt/schema/keyword/MaxPropertiesValidator.java @@ -14,23 +14,24 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import com.fasterxml.jackson.databind.JsonNode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.SchemaContext; /** - * {@link JsonValidator}for maxProperties. + * {@link KeywordValidator}for maxProperties. */ -public class MaxPropertiesValidator extends BaseJsonValidator implements JsonValidator { - private static final Logger logger = LoggerFactory.getLogger(MaxPropertiesValidator.class); - +public class MaxPropertiesValidator extends BaseKeywordValidator implements KeywordValidator { private final int max; - public MaxPropertiesValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, JsonSchema parentSchema, - ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.MAX_PROPERTIES, validationContext); + public MaxPropertiesValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, Schema parentSchema, + SchemaContext schemaContext) { + super(KeywordType.MAX_PROPERTIES, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); if (schemaNode.canConvertToExactIntegral()) { max = schemaNode.intValue(); } else { @@ -38,14 +39,14 @@ public MaxPropertiesValidator(SchemaLocation schemaLocation, JsonNodePath evalua } } - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) { - debug(logger, executionContext, node, rootNode, instanceLocation); + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation) { + if (node.isObject()) { if (node.size() > max) { - executionContext.addError(message().instanceNode(node).instanceLocation(instanceLocation) + executionContext.addError(error().instanceNode(node).instanceLocation(instanceLocation) .locale(executionContext.getExecutionConfig().getLocale()) - .failFast(executionContext.isFailFast()).arguments(max).build()); + .arguments(max).build()); } } } diff --git a/src/main/java/com/networknt/schema/MaximumValidator.java b/src/main/java/com/networknt/schema/keyword/MaximumValidator.java similarity index 79% rename from src/main/java/com/networknt/schema/MaximumValidator.java rename to src/main/java/com/networknt/schema/keyword/MaximumValidator.java index 0c6630b94..c7d6e3a78 100644 --- a/src/main/java/com/networknt/schema/MaximumValidator.java +++ b/src/main/java/com/networknt/schema/keyword/MaximumValidator.java @@ -14,22 +14,25 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import com.fasterxml.jackson.databind.JsonNode; -import com.networknt.schema.utils.JsonNodeUtil; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaException; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.SchemaContext; +import com.networknt.schema.utils.JsonNodeTypes; +import com.networknt.schema.utils.JsonType; import java.math.BigDecimal; import java.math.BigInteger; /** - * {@link JsonValidator} for maxmimum. + * {@link KeywordValidator} for maxmimum. */ -public class MaximumValidator extends BaseJsonValidator { - private static final Logger logger = LoggerFactory.getLogger(MaximumValidator.class); +public class MaximumValidator extends BaseKeywordValidator { private static final String PROPERTY_EXCLUSIVE_MAXIMUM = "exclusiveMaximum"; private final boolean excludeEqual; @@ -37,10 +40,10 @@ public class MaximumValidator extends BaseJsonValidator { private final ThresholdMixin typedMaximum; - public MaximumValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, final JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.MAXIMUM, validationContext); + public MaximumValidator(SchemaLocation schemaLocation, NodePath evaluationPath, final JsonNode schemaNode, Schema parentSchema, SchemaContext schemaContext) { + super(KeywordType.MAXIMUM, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); if (!schemaNode.isNumber()) { - throw new JsonSchemaException("maximum value is not a number"); + throw new SchemaException("maximum value is not a number"); } JsonNode exclusiveMaximumNode = getParentSchema().getSchemaNode().get(PROPERTY_EXCLUSIVE_MAXIMUM); @@ -107,18 +110,17 @@ public String thresholdValue() { } } - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) { - debug(logger, executionContext, node, rootNode, instanceLocation); + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation) { + - if (!JsonNodeUtil.isNumber(node, this.validationContext.getConfig())) { + if (!JsonNodeTypes.isNumber(node, this.schemaContext.getSchemaRegistryConfig())) { // maximum only applies to numbers return; } if (this.typedMaximum.crossesThreshold(node)) { - executionContext.addError(message().instanceNode(node).instanceLocation(instanceLocation) + executionContext.addError(error().instanceNode(node).instanceLocation(instanceLocation) .locale(executionContext.getExecutionConfig().getLocale()) - .failFast(executionContext.isFailFast()) .arguments(this.typedMaximum.thresholdValue()).build()); } } diff --git a/src/main/java/com/networknt/schema/MinItemsValidator.java b/src/main/java/com/networknt/schema/keyword/MinItemsValidator.java similarity index 50% rename from src/main/java/com/networknt/schema/MinItemsValidator.java rename to src/main/java/com/networknt/schema/keyword/MinItemsValidator.java index 41da79afb..48181b1a5 100644 --- a/src/main/java/com/networknt/schema/MinItemsValidator.java +++ b/src/main/java/com/networknt/schema/keyword/MinItemsValidator.java @@ -14,42 +14,43 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import com.fasterxml.jackson.databind.JsonNode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.SchemaContext; /** - * {@link JsonValidator} for minItems. + * {@link KeywordValidator} for minItems. */ -public class MinItemsValidator extends BaseJsonValidator implements JsonValidator { - private static final Logger logger = LoggerFactory.getLogger(MinItemsValidator.class); - +public class MinItemsValidator extends BaseKeywordValidator implements KeywordValidator { private int min = 0; - public MinItemsValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.MIN_ITEMS, validationContext); + public MinItemsValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, Schema parentSchema, SchemaContext schemaContext) { + super(KeywordType.MIN_ITEMS, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); if (schemaNode.canConvertToExactIntegral()) { min = schemaNode.intValue(); } } - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) { - debug(logger, executionContext, node, rootNode, instanceLocation); + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation) { + if (node.isArray()) { if (node.size() < min) { - executionContext.addError(message().instanceNode(node).instanceLocation(instanceLocation) + executionContext.addError(error().instanceNode(node).instanceLocation(instanceLocation) .locale(executionContext.getExecutionConfig().getLocale()) - .failFast(executionContext.isFailFast()).arguments(min, node.size()) + .arguments(min, node.size()) .build()); } - } else if (this.validationContext.getConfig().isTypeLoose()) { + } else if (this.schemaContext.getSchemaRegistryConfig().isTypeLoose()) { if (1 < min) { - executionContext.addError(message().instanceNode(node).instanceLocation(instanceLocation) + executionContext.addError(error().instanceNode(node).instanceLocation(instanceLocation) .locale(executionContext.getExecutionConfig().getLocale()) - .failFast(executionContext.isFailFast()).arguments(min, 1).build()); + .arguments(min, 1).build()); } } } diff --git a/src/main/java/com/networknt/schema/MinLengthValidator.java b/src/main/java/com/networknt/schema/keyword/MinLengthValidator.java similarity index 55% rename from src/main/java/com/networknt/schema/MinLengthValidator.java rename to src/main/java/com/networknt/schema/keyword/MinLengthValidator.java index cce1f97b4..456367bb9 100644 --- a/src/main/java/com/networknt/schema/MinLengthValidator.java +++ b/src/main/java/com/networknt/schema/keyword/MinLengthValidator.java @@ -14,41 +14,44 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import com.fasterxml.jackson.databind.JsonNode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.utils.JsonType; +import com.networknt.schema.utils.TypeFactory; +import com.networknt.schema.SchemaContext; /** - * {@link JsonValidator} for minLength. + * {@link KeywordValidator} for minLength. */ -public class MinLengthValidator extends BaseJsonValidator implements JsonValidator { - private static final Logger logger = LoggerFactory.getLogger(MinLengthValidator.class); - +public class MinLengthValidator extends BaseKeywordValidator implements KeywordValidator { private int minLength; - public MinLengthValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.MIN_LENGTH, validationContext); + public MinLengthValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, Schema parentSchema, SchemaContext schemaContext) { + super(KeywordType.MIN_LENGTH, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); minLength = Integer.MIN_VALUE; if (schemaNode != null && schemaNode.canConvertToExactIntegral()) { minLength = schemaNode.intValue(); } } - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) { - debug(logger, executionContext, node, rootNode, instanceLocation); + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation) { + - JsonType nodeType = TypeFactory.getValueNodeType(node, this.validationContext.getConfig()); + JsonType nodeType = TypeFactory.getValueNodeType(node, this.schemaContext.getSchemaRegistryConfig()); if (nodeType != JsonType.STRING) { // ignore non-string types return; } if (node.textValue().codePointCount(0, node.textValue().length()) < minLength) { - executionContext.addError(message().instanceNode(node).instanceLocation(instanceLocation) + executionContext.addError(error().instanceNode(node).instanceLocation(instanceLocation) .locale(executionContext.getExecutionConfig().getLocale()) - .failFast(executionContext.isFailFast()).arguments(minLength).build()); + .arguments(minLength).build()); } } diff --git a/src/main/java/com/networknt/schema/MinMaxContainsValidator.java b/src/main/java/com/networknt/schema/keyword/MinMaxContainsValidator.java similarity index 78% rename from src/main/java/com/networknt/schema/MinMaxContainsValidator.java rename to src/main/java/com/networknt/schema/keyword/MinMaxContainsValidator.java index 3cbcc476e..68d0b3564 100644 --- a/src/main/java/com/networknt/schema/MinMaxContainsValidator.java +++ b/src/main/java/com/networknt/schema/keyword/MinMaxContainsValidator.java @@ -1,23 +1,28 @@ -package com.networknt.schema; +package com.networknt.schema.keyword; import com.fasterxml.jackson.databind.JsonNode; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.SchemaContext; import java.util.LinkedHashSet; import java.util.Set; /** - * {@link JsonValidator} for {@literal maxContains} and {@literal minContains} in a schema. + * {@link KeywordValidator} for {@literal maxContains} and {@literal minContains} in a schema. *

* This validator only checks that the schema is valid. The functionality for * testing whether an instance array conforms to the {@literal maxContains} * and {@literal minContains} constraints exists within {@code ContainsValidator}. */ -public class MinMaxContainsValidator extends BaseJsonValidator { +public class MinMaxContainsValidator extends BaseKeywordValidator { private final Set analysis; - public MinMaxContainsValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, JsonSchema parentSchema, - ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.MAX_CONTAINS, validationContext); + public MinMaxContainsValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, Schema parentSchema, + SchemaContext schemaContext) { + super(KeywordType.MAX_CONTAINS, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); Set analysis = null; int min = 1; @@ -58,14 +63,13 @@ public MinMaxContainsValidator(SchemaLocation schemaLocation, JsonNodePath evalu @Override public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, - JsonNodePath instanceLocation) { + NodePath instanceLocation) { if (this.analysis != null) { this.analysis.stream() - .map(analysis -> message().instanceNode(node) + .map(analysis -> error().instanceNode(node) .instanceLocation(instanceLocation) .messageKey(analysis.getMessageKey()).locale(executionContext.getExecutionConfig().getLocale()) - .failFast(executionContext.isFailFast()) - .type(analysis.getMessageKey()) + .keyword(analysis.getMessageKey()) .arguments(parentSchema.getSchemaNode().toString()).build()) .forEach(executionContext::addError); } diff --git a/src/main/java/com/networknt/schema/MinPropertiesValidator.java b/src/main/java/com/networknt/schema/keyword/MinPropertiesValidator.java similarity index 54% rename from src/main/java/com/networknt/schema/MinPropertiesValidator.java rename to src/main/java/com/networknt/schema/keyword/MinPropertiesValidator.java index 36584c162..bf6142746 100644 --- a/src/main/java/com/networknt/schema/MinPropertiesValidator.java +++ b/src/main/java/com/networknt/schema/keyword/MinPropertiesValidator.java @@ -14,23 +14,24 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import com.fasterxml.jackson.databind.JsonNode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.SchemaContext; /** - * {@link JsonValidator} for minProperties. + * {@link KeywordValidator} for minProperties. */ -public class MinPropertiesValidator extends BaseJsonValidator implements JsonValidator { - private static final Logger logger = LoggerFactory.getLogger(MinPropertiesValidator.class); - +public class MinPropertiesValidator extends BaseKeywordValidator implements KeywordValidator { protected final int min; - public MinPropertiesValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, JsonSchema parentSchema, - ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.MIN_PROPERTIES, validationContext); + public MinPropertiesValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, Schema parentSchema, + SchemaContext schemaContext) { + super(KeywordType.MIN_PROPERTIES, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); if (schemaNode.canConvertToExactIntegral()) { min = schemaNode.intValue(); } else { @@ -38,14 +39,14 @@ public MinPropertiesValidator(SchemaLocation schemaLocation, JsonNodePath evalua } } - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) { - debug(logger, executionContext, node, rootNode, instanceLocation); + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation) { + if (node.isObject()) { if (node.size() < min) { - executionContext.addError(message().instanceNode(node).instanceLocation(instanceLocation) + executionContext.addError(error().instanceNode(node).instanceLocation(instanceLocation) .locale(executionContext.getExecutionConfig().getLocale()) - .failFast(executionContext.isFailFast()).arguments(min).build()); + .arguments(min).build()); } } } diff --git a/src/main/java/com/networknt/schema/MinimumValidator.java b/src/main/java/com/networknt/schema/keyword/MinimumValidator.java similarity index 80% rename from src/main/java/com/networknt/schema/MinimumValidator.java rename to src/main/java/com/networknt/schema/keyword/MinimumValidator.java index 877518732..2d9f7f3cd 100644 --- a/src/main/java/com/networknt/schema/MinimumValidator.java +++ b/src/main/java/com/networknt/schema/keyword/MinimumValidator.java @@ -14,22 +14,25 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import com.fasterxml.jackson.databind.JsonNode; -import com.networknt.schema.utils.JsonNodeUtil; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaException; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.SchemaContext; +import com.networknt.schema.utils.JsonNodeTypes; +import com.networknt.schema.utils.JsonType; import java.math.BigDecimal; import java.math.BigInteger; /** - * {@link JsonValidator} for minimum. + * {@link KeywordValidator} for minimum. */ -public class MinimumValidator extends BaseJsonValidator { - private static final Logger logger = LoggerFactory.getLogger(MinimumValidator.class); +public class MinimumValidator extends BaseKeywordValidator { private static final String PROPERTY_EXCLUSIVE_MINIMUM = "exclusiveMinimum"; private final boolean excludeEqual; @@ -40,11 +43,11 @@ public class MinimumValidator extends BaseJsonValidator { */ private final ThresholdMixin typedMinimum; - public MinimumValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, final JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.MINIMUM, validationContext); + public MinimumValidator(SchemaLocation schemaLocation, NodePath evaluationPath, final JsonNode schemaNode, Schema parentSchema, SchemaContext schemaContext) { + super(KeywordType.MINIMUM, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); if (!schemaNode.isNumber()) { - throw new JsonSchemaException("minimum value is not a number"); + throw new SchemaException("minimum value is not a number"); } JsonNode exclusiveMinimumNode = getParentSchema().getSchemaNode().get(PROPERTY_EXCLUSIVE_MINIMUM); @@ -114,18 +117,17 @@ public String thresholdValue() { } } - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) { - debug(logger, executionContext, node, rootNode, instanceLocation); + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation) { + - if (!JsonNodeUtil.isNumber(node, this.validationContext.getConfig())) { + if (!JsonNodeTypes.isNumber(node, this.schemaContext.getSchemaRegistryConfig())) { // minimum only applies to numbers return; } if (this.typedMinimum.crossesThreshold(node)) { - executionContext.addError(message().instanceNode(node).instanceLocation(instanceLocation) + executionContext.addError(error().instanceNode(node).instanceLocation(instanceLocation) .locale(executionContext.getExecutionConfig().getLocale()) - .failFast(executionContext.isFailFast()) .arguments(this.typedMinimum.thresholdValue()).build()); } } diff --git a/src/main/java/com/networknt/schema/MultipleOfValidator.java b/src/main/java/com/networknt/schema/keyword/MultipleOfValidator.java similarity index 68% rename from src/main/java/com/networknt/schema/MultipleOfValidator.java rename to src/main/java/com/networknt/schema/keyword/MultipleOfValidator.java index e3089cdea..a69c41121 100644 --- a/src/main/java/com/networknt/schema/MultipleOfValidator.java +++ b/src/main/java/com/networknt/schema/keyword/MultipleOfValidator.java @@ -14,40 +14,40 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import com.fasterxml.jackson.databind.JsonNode; -import com.networknt.schema.utils.JsonNodeUtil; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.SchemaContext; +import com.networknt.schema.utils.JsonNodeTypes; import java.math.BigDecimal; /** - * {@link JsonValidator} for multipleOf. + * {@link KeywordValidator} for multipleOf. */ -public class MultipleOfValidator extends BaseJsonValidator implements JsonValidator { - private static final Logger logger = LoggerFactory.getLogger(MultipleOfValidator.class); - +public class MultipleOfValidator extends BaseKeywordValidator implements KeywordValidator { private final BigDecimal divisor; - public MultipleOfValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, - JsonSchema parentSchema, ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.MULTIPLE_OF, validationContext); + public MultipleOfValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, + Schema parentSchema, SchemaContext schemaContext) { + super(KeywordType.MULTIPLE_OF, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); this.divisor = getDivisor(schemaNode); } public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, - JsonNodePath instanceLocation) { - debug(logger, executionContext, node, rootNode, instanceLocation); + NodePath instanceLocation) { + if (this.divisor != null) { BigDecimal dividend = getDividend(node); if (dividend != null) { if (dividend.divideAndRemainder(this.divisor)[1].abs().compareTo(BigDecimal.ZERO) > 0) { - executionContext.addError(message().instanceNode(node).instanceLocation(instanceLocation) + executionContext.addError(error().instanceNode(node).instanceLocation(instanceLocation) .locale(executionContext.getExecutionConfig().getLocale()) - .failFast(executionContext.isFailFast()).arguments(this.divisor) + .arguments(this.divisor) .build()); } } @@ -83,8 +83,8 @@ protected BigDecimal getDividend(JsonNode node) { // convert to BigDecimal since double type is not accurate enough to do the // division and multiple return node.isBigDecimal() ? node.decimalValue() : BigDecimal.valueOf(node.doubleValue()); - } else if (this.validationContext.getConfig().isTypeLoose() - && JsonNodeUtil.isNumber(node, this.validationContext.getConfig())) { + } else if (this.schemaContext.getSchemaRegistryConfig().isTypeLoose() + && JsonNodeTypes.isNumber(node, this.schemaContext.getSchemaRegistryConfig())) { // handling for type loose return new BigDecimal(node.textValue()); } diff --git a/src/main/java/com/networknt/schema/NonValidationKeyword.java b/src/main/java/com/networknt/schema/keyword/NonValidationKeyword.java similarity index 55% rename from src/main/java/com/networknt/schema/NonValidationKeyword.java rename to src/main/java/com/networknt/schema/keyword/NonValidationKeyword.java index 2b2cde777..83c857e0c 100644 --- a/src/main/java/com/networknt/schema/NonValidationKeyword.java +++ b/src/main/java/com/networknt/schema/keyword/NonValidationKeyword.java @@ -14,9 +14,14 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import com.fasterxml.jackson.databind.JsonNode; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.SchemaContext; import java.util.Iterator; import java.util.Map.Entry; @@ -26,30 +31,30 @@ */ public class NonValidationKeyword extends AbstractKeyword { - private static final class Validator extends AbstractJsonValidator { - public Validator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, - JsonSchema parentSchema, ValidationContext validationContext, Keyword keyword) { - super(schemaLocation, evaluationPath, keyword, schemaNode); - String id = validationContext.resolveSchemaId(schemaNode); - String anchor = validationContext.getMetaSchema().readAnchor(schemaNode); - String dynamicAnchor = validationContext.getMetaSchema().readDynamicAnchor(schemaNode); + private static final class Validator extends AbstractKeywordValidator { + public Validator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, + Schema parentSchema, SchemaContext schemaContext, Keyword keyword) { + super(keyword, schemaNode, schemaLocation, evaluationPath); + String id = schemaContext.resolveSchemaId(schemaNode); + String anchor = schemaContext.getDialect().readAnchor(schemaNode); + String dynamicAnchor = schemaContext.getDialect().readDynamicAnchor(schemaNode); if (id != null || anchor != null || dynamicAnchor != null) { // Used to register schema resources with $id - validationContext.newSchema(schemaLocation, evaluationPath, schemaNode, parentSchema); + schemaContext.newSchema(schemaLocation, evaluationPath, schemaNode, parentSchema); } if ("$defs".equals(keyword.getValue()) || "definitions".equals(keyword.getValue())) { for (Iterator> field = schemaNode.fields(); field.hasNext(); ) { Entry property = field.next(); SchemaLocation location = schemaLocation.append(property.getKey()); - JsonSchema schema = validationContext.newSchema(location, evaluationPath.append(property.getKey()), + Schema schema = schemaContext.newSchema(location, evaluationPath.append(property.getKey()), property.getValue(), parentSchema); - validationContext.getSchemaReferences().put(location.toString(), schema); + schemaContext.getSchemaReferences().put(location.toString(), schema); } } } @Override - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) { + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation) { // Do nothing } } @@ -59,8 +64,8 @@ public NonValidationKeyword(String keyword) { } @Override - public JsonValidator newValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, - JsonSchema parentSchema, ValidationContext validationContext) { - return new Validator(schemaLocation, evaluationPath, schemaNode, parentSchema, validationContext, this); + public KeywordValidator newValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, + Schema parentSchema, SchemaContext schemaContext) { + return new Validator(schemaLocation, evaluationPath, schemaNode, parentSchema, schemaContext, this); } } diff --git a/src/main/java/com/networknt/schema/NotAllowedValidator.java b/src/main/java/com/networknt/schema/keyword/NotAllowedValidator.java similarity index 59% rename from src/main/java/com/networknt/schema/NotAllowedValidator.java rename to src/main/java/com/networknt/schema/keyword/NotAllowedValidator.java index 78f6c0c84..332650609 100644 --- a/src/main/java/com/networknt/schema/NotAllowedValidator.java +++ b/src/main/java/com/networknt/schema/keyword/NotAllowedValidator.java @@ -14,24 +14,25 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import com.fasterxml.jackson.databind.JsonNode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.SchemaContext; import java.util.*; /** - * {@link JsonValidator} for notAllowed. + * {@link KeywordValidator} for notAllowed. */ -public class NotAllowedValidator extends BaseJsonValidator implements JsonValidator { - private static final Logger logger = LoggerFactory.getLogger(NotAllowedValidator.class); - +public class NotAllowedValidator extends BaseKeywordValidator implements KeywordValidator { private final List fieldNames; - public NotAllowedValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.NOT_ALLOWED, validationContext); + public NotAllowedValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, Schema parentSchema, SchemaContext schemaContext) { + super(KeywordType.NOT_ALLOWED, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); if (schemaNode.isArray()) { int size = schemaNode.size(); this.fieldNames = new ArrayList<>(size); @@ -43,17 +44,17 @@ public NotAllowedValidator(SchemaLocation schemaLocation, JsonNodePath evaluatio } } - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) { - debug(logger, executionContext, node, rootNode, instanceLocation); + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation) { + for (String fieldName : fieldNames) { JsonNode propertyNode = node.get(fieldName); if (propertyNode != null) { - executionContext.addError(message().property(fieldName).instanceNode(node) + executionContext.addError(error().property(fieldName).instanceNode(node) .instanceLocation(instanceLocation.append(fieldName)) .locale(executionContext.getExecutionConfig().getLocale()) - .failFast(executionContext.isFailFast()).arguments(fieldName).build()); + .arguments(fieldName).build()); } } } diff --git a/src/main/java/com/networknt/schema/NotValidator.java b/src/main/java/com/networknt/schema/keyword/NotValidator.java similarity index 61% rename from src/main/java/com/networknt/schema/NotValidator.java rename to src/main/java/com/networknt/schema/keyword/NotValidator.java index 67c607994..36b53c760 100644 --- a/src/main/java/com/networknt/schema/NotValidator.java +++ b/src/main/java/com/networknt/schema/keyword/NotValidator.java @@ -14,43 +14,44 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import com.fasterxml.jackson.databind.JsonNode; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.networknt.schema.Error; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.SchemaContext; import java.util.*; /** - * {@link JsonValidator} for not. + * {@link KeywordValidator} for not. */ -public class NotValidator extends BaseJsonValidator { - private static final Logger logger = LoggerFactory.getLogger(NotValidator.class); - - private final JsonSchema schema; +public class NotValidator extends BaseKeywordValidator { + private final Schema schema; - public NotValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.NOT, validationContext); - this.schema = validationContext.newSchema(schemaLocation, evaluationPath, schemaNode, parentSchema); + public NotValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, Schema parentSchema, SchemaContext schemaContext) { + super(KeywordType.NOT, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); + this.schema = schemaContext.newSchema(schemaLocation, evaluationPath, schemaNode, parentSchema); } @Override public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, - JsonNodePath instanceLocation) { + NodePath instanceLocation) { validate(executionContext, node, rootNode, instanceLocation, false); } protected void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, - JsonNodePath instanceLocation, boolean walk) { + NodePath instanceLocation, boolean walk) { + - debug(logger, executionContext, node, rootNode, instanceLocation); // Save flag as nested schema evaluation shouldn't trigger fail fast boolean failFast = executionContext.isFailFast(); - List existingErrors = executionContext.getErrors(); - List test = new ArrayList<>(); + List existingErrors = executionContext.getErrors(); + List test = new ArrayList<>(); executionContext.setErrors(test); try { executionContext.setFailFast(false); @@ -65,15 +66,15 @@ protected void validate(ExecutionContext executionContext, JsonNode node, JsonNo executionContext.setErrors(existingErrors); } if (test.isEmpty()) { - executionContext.addError(message().instanceNode(node).instanceLocation(instanceLocation) + executionContext.addError(error().instanceNode(node).instanceLocation(instanceLocation) .locale(executionContext.getExecutionConfig().getLocale()) - .failFast(executionContext.isFailFast()).arguments(this.schema.toString()) + .arguments(this.schemaNode.toString()) .build()); } } @Override - public void walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation, boolean shouldValidateSchema) { + public void walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation, boolean shouldValidateSchema) { if (shouldValidateSchema && node != null) { validate(executionContext, node, rootNode, instanceLocation, true); return; @@ -83,7 +84,7 @@ public void walk(ExecutionContext executionContext, JsonNode node, JsonNode root } @Override - public void preloadJsonSchema() { + public void preloadSchema() { if (null != this.schema) { this.schema.initializeValidators(); } diff --git a/src/main/java/com/networknt/schema/keyword/OneOfValidator.java b/src/main/java/com/networknt/schema/keyword/OneOfValidator.java new file mode 100644 index 000000000..eee38b822 --- /dev/null +++ b/src/main/java/com/networknt/schema/keyword/OneOfValidator.java @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2016 Network New Technologies Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.networknt.schema.keyword; + +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.databind.JsonNode; +import com.networknt.schema.Error; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaContext; +import com.networknt.schema.SchemaException; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.utils.JsonType; +import com.networknt.schema.utils.TypeFactory; + +/** + * {@link KeywordValidator} for oneOf. + */ +public class OneOfValidator extends BaseKeywordValidator { + private final List schemas; + + private Boolean canShortCircuit = null; + + public OneOfValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, + Schema parentSchema, SchemaContext schemaContext) { + super(KeywordType.ONE_OF, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); + if (!schemaNode.isArray()) { + JsonType nodeType = TypeFactory.getValueNodeType(schemaNode, this.schemaContext.getSchemaRegistryConfig()); + throw new SchemaException(error().instanceNode(schemaNode).instanceLocation(schemaLocation.getFragment()) + .messageKey("type").arguments(nodeType.toString(), "array").build()); + } + int size = schemaNode.size(); + this.schemas = new ArrayList<>(size); + for (int i = 0; i < size; i++) { + JsonNode childNode = schemaNode.get(i); + this.schemas.add(schemaContext.newSchema(schemaLocation.append(i), evaluationPath.append(i), childNode, + parentSchema)); + } + } + + @Override + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, + NodePath instanceLocation) { + validate(executionContext, node, rootNode, instanceLocation, false); + } + + protected void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, + NodePath instanceLocation, boolean walk) { + int numberOfValidSchema = 0; + int index = 0; + List indexes = null; + List existingErrors = executionContext.getErrors(); + List allErrors = null; // Keeps track of all the errors for reporting if in the end none or more than + // one sub schema matches + List discriminatorErrors = null; // The errors from the sub schema that match the discriminator + List subSchemaErrors = new ArrayList<>(); // Temporary errors from each sub schema execution + + executionContext.setErrors(subSchemaErrors); + // Save flag as nested schema evaluation shouldn't trigger fail fast + boolean failFast = executionContext.isFailFast(); + try { + executionContext.setFailFast(false); + for (Schema schema : this.schemas) { + subSchemaErrors.clear(); + if (!walk) { + schema.validate(executionContext, node, rootNode, instanceLocation); + } else { + schema.walk(executionContext, node, rootNode, instanceLocation, true); + } + + // check if any validation errors have occurred + if (subSchemaErrors.isEmpty()) { // No new errors + numberOfValidSchema++; + if (indexes == null) { + indexes = new ArrayList<>(); + } + indexes.add(Integer.toString(index)); + } + + if (numberOfValidSchema > 1 && canShortCircuit()) { + // short-circuit + // note that the short circuit means that only 2 valid schemas are reported even + // if could be more + break; + } + + if (this.schemaContext.isDiscriminatorKeywordEnabled()) { + boolean discriminatorMatchFound = false; + DiscriminatorState discriminator = executionContext.getDiscriminatorMapping().get(instanceLocation); + JsonNode refNode = schema.getSchemaNode().get("$ref"); + if (discriminator != null && refNode != null && discriminator.hasDiscriminatingValue()) { + discriminatorMatchFound = discriminator.matches(refNode.asText()); + if (discriminatorMatchFound) { + /* + * Note that discriminator cannot change the outcome of the evaluation but can + * be used to filter off any additional messages + * + * The discriminator will cause all messages other than the one with the // + * matching discriminator to be discarded. + */ + if (!subSchemaErrors.isEmpty()) { + /* + * This means that the discriminated value has errors and doesn't match so these + * errors are the only ones that will be reported *IF* there are no other + * schemas that successfully validate to meet the requirement of anyOf. + * + * If there are any successful schemas as per anyOf, all these errors will be + * discarded. + */ + discriminatorErrors = new ArrayList<>(subSchemaErrors); + allErrors = null; // This is no longer needed + } + } + } else { + // This is the normal handling when discriminators aren't enabled + if (discriminatorErrors == null) { + if (allErrors == null) { + allErrors = new ArrayList<>(); + } + allErrors.addAll(subSchemaErrors); + } + } + } else if (!subSchemaErrors.isEmpty() && reportChildErrors(executionContext)) { + // This is the normal handling when discriminators aren't enabled + if (allErrors == null) { + allErrors = new ArrayList<>(); + } + allErrors.addAll(subSchemaErrors); + } + index++; + } + + if (this.schemaContext.isDiscriminatorKeywordEnabled()) { + /* + * The only case where the discriminator can change the outcome of the result is + * if the discriminator value does not match an implicit or explicit mapping + */ + /* + * If the discriminator value does not match an implicit or explicit mapping, no + * schema can be determined and validation SHOULD fail. Mapping keys MUST be + * string values, but tooling MAY convert response values to strings for + * comparison. + * + * https://spec.openapis.org/oas/v3.1.2#examples-0 + */ + DiscriminatorState state = executionContext.getDiscriminatorMapping().get(instanceLocation); + if (state != null && !state.hasMatchedSchema() && state.hasDiscriminatingValue()) { + // The check for state.hasDiscriminatingValue is due to issue 988 + // Note that this is related to the DiscriminatorValidator by default not + // generating an assertion + // if the discriminatingValue is not set in the payload + existingErrors + .add(error().keyword("discriminator").instanceNode(node).instanceLocation(instanceLocation) + .locale(executionContext.getExecutionConfig().getLocale()) + .messageKey("discriminator.oneOf.no_match_found") + .arguments(state.getDiscriminatingValue()).build()); + } + } + } finally { + // Restore flag + executionContext.setFailFast(failFast); + } + + if (numberOfValidSchema != 1) { + /* + * Ensure there is always an "oneOf" error reported if number of valid schemas + * is not equal to 1 + */ + Error message = error().instanceNode(node).instanceLocation(instanceLocation) + .messageKey(numberOfValidSchema > 1 ? "oneOf.indexes" : "oneOf") + .locale(executionContext.getExecutionConfig().getLocale()) + .arguments(Integer.toString(numberOfValidSchema), + numberOfValidSchema > 1 ? String.join(", ", indexes) : "") + .build(); + existingErrors.add(message); + + if (discriminatorErrors != null) { + existingErrors.addAll(discriminatorErrors); + } else if (allErrors != null) { + existingErrors.addAll(allErrors); + } + } + executionContext.setErrors(existingErrors); + return; + } + + /** + * Determines if child errors should be reported. + * + * @param executionContext the execution context + * @return true if child errors should be reported + */ + protected boolean reportChildErrors(ExecutionContext executionContext) { + // check the original flag if it's going to fail fast anyway + // no point aggregating all the errors + return !executionContext.getExecutionConfig().isFailFast(); + } + + protected boolean canShortCircuit() { + if (this.canShortCircuit == null) { + boolean canShortCircuit = true; + for (KeywordValidator validator : getEvaluationParentSchema().getValidators()) { + if ("unevaluatedProperties".equals(validator.getKeyword()) + || "unevaluatedItems".equals(validator.getKeyword())) { + canShortCircuit = false; + } + } + this.canShortCircuit = canShortCircuit; + } + return this.canShortCircuit; + } + + @Override + public void walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation, + boolean shouldValidateSchema) { + if (shouldValidateSchema && node != null) { + validate(executionContext, node, rootNode, instanceLocation, true); + } else { + for (Schema schema : this.schemas) { + schema.walk(executionContext, node, rootNode, instanceLocation, false); + } + } + } + + @Override + public void preloadSchema() { + for (Schema schema : this.schemas) { + schema.initializeValidators(); + } + canShortCircuit(); // cache the flag + } +} diff --git a/src/main/java/com/networknt/schema/PatternPropertiesValidator.java b/src/main/java/com/networknt/schema/keyword/PatternPropertiesValidator.java similarity index 68% rename from src/main/java/com/networknt/schema/PatternPropertiesValidator.java rename to src/main/java/com/networknt/schema/keyword/PatternPropertiesValidator.java index 95403ad0d..2af8ee6d2 100644 --- a/src/main/java/com/networknt/schema/PatternPropertiesValidator.java +++ b/src/main/java/com/networknt/schema/keyword/PatternPropertiesValidator.java @@ -14,43 +14,45 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import com.fasterxml.jackson.databind.JsonNode; -import com.networknt.schema.annotation.JsonNodeAnnotation; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaException; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.SchemaContext; +import com.networknt.schema.annotation.Annotation; +import com.networknt.schema.path.NodePath; import com.networknt.schema.regex.RegularExpression; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.util.*; /** - * {@link JsonValidator} for patternProperties. + * {@link KeywordValidator} for patternProperties. */ -public class PatternPropertiesValidator extends BaseJsonValidator { +public class PatternPropertiesValidator extends BaseKeywordValidator { public static final String PROPERTY = "patternProperties"; - private static final Logger logger = LoggerFactory.getLogger(PatternPropertiesValidator.class); - private final Map schemas = new IdentityHashMap<>(); + private final Map schemas = new IdentityHashMap<>(); private Boolean hasUnevaluatedPropertiesValidator = null; - public PatternPropertiesValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, JsonSchema parentSchema, - ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.PATTERN_PROPERTIES, validationContext); + public PatternPropertiesValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, Schema parentSchema, + SchemaContext schemaContext) { + super(KeywordType.PATTERN_PROPERTIES, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); if (!schemaNode.isObject()) { - throw new JsonSchemaException("patternProperties must be an object node"); + throw new SchemaException("patternProperties must be an object node"); } Iterator names = schemaNode.fieldNames(); while (names.hasNext()) { String name = names.next(); - RegularExpression pattern = RegularExpression.compile(name, validationContext); - schemas.put(pattern, validationContext.newSchema(schemaLocation.append(name), evaluationPath.append(name), + RegularExpression pattern = RegularExpression.compile(name, schemaContext); + schemas.put(pattern, schemaContext.newSchema(schemaLocation.append(name), evaluationPath.append(name), schemaNode.get(name), parentSchema)); } } - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) { - debug(logger, executionContext, node, rootNode, instanceLocation); + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation) { + if (!node.isObject()) { return; @@ -61,9 +63,9 @@ public void validate(ExecutionContext executionContext, JsonNode node, JsonNode while (names.hasNext()) { String name = names.next(); JsonNode n = node.get(name); - for (Map.Entry entry : schemas.entrySet()) { + for (Map.Entry entry : schemas.entrySet()) { if (entry.getKey().matches(name)) { - JsonNodePath path = instanceLocation.append(name); + NodePath path = instanceLocation.append(name); int currentErrors = executionContext.getErrors().size(); entry.getValue().validate(executionContext, n, rootNode, path); if (currentErrors == executionContext.getErrors().size()) { // No new errors @@ -79,7 +81,7 @@ public void validate(ExecutionContext executionContext, JsonNode node, JsonNode } if (collectAnnotations) { executionContext.getAnnotations() - .put(JsonNodeAnnotation.builder().instanceLocation(instanceLocation) + .put(Annotation.builder().instanceLocation(instanceLocation) .evaluationPath(this.evaluationPath).schemaLocation(this.schemaLocation) .keyword(getKeyword()) .value(matchedInstancePropertyNames != null ? matchedInstancePropertyNames @@ -100,8 +102,8 @@ private boolean hasUnevaluatedPropertiesValidator() { } @Override - public void preloadJsonSchema() { - preloadJsonSchemas(schemas.values()); + public void preloadSchema() { + preloadSchemas(schemas.values()); collectAnnotations(); // cache the flag } } diff --git a/src/main/java/com/networknt/schema/PatternValidator.java b/src/main/java/com/networknt/schema/keyword/PatternValidator.java similarity index 65% rename from src/main/java/com/networknt/schema/PatternValidator.java rename to src/main/java/com/networknt/schema/keyword/PatternValidator.java index b4b29e733..3af2bb054 100644 --- a/src/main/java/com/networknt/schema/PatternValidator.java +++ b/src/main/java/com/networknt/schema/keyword/PatternValidator.java @@ -14,26 +14,36 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import com.fasterxml.jackson.databind.JsonNode; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.FailFastAssertionException; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaException; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.SchemaContext; import com.networknt.schema.regex.RegularExpression; +import com.networknt.schema.utils.JsonType; +import com.networknt.schema.utils.TypeFactory; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Optional; -public class PatternValidator extends BaseJsonValidator { +public class PatternValidator extends BaseKeywordValidator { private static final Logger logger = LoggerFactory.getLogger(PatternValidator.class); private final String pattern; private final RegularExpression compiledPattern; - public PatternValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.PATTERN, validationContext); + public PatternValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, Schema parentSchema, SchemaContext schemaContext) { + super(KeywordType.PATTERN, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); this.pattern = Optional.ofNullable(schemaNode).filter(JsonNode::isTextual).map(JsonNode::textValue).orElse(null); try { - this.compiledPattern = RegularExpression.compile(this.pattern, validationContext); + this.compiledPattern = RegularExpression.compile(this.pattern, schemaContext); } catch (RuntimeException e) { e.setStackTrace(new StackTraceElement[0]); logger.error("Failed to compile pattern '{}': {}", this.pattern, e.getMessage()); @@ -46,22 +56,22 @@ private boolean matches(String value) { } @Override - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) { - debug(logger, executionContext, node, rootNode, instanceLocation); + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation) { + - JsonType nodeType = TypeFactory.getValueNodeType(node, this.validationContext.getConfig()); + JsonType nodeType = TypeFactory.getValueNodeType(node, this.schemaContext.getSchemaRegistryConfig()); if (nodeType != JsonType.STRING) { return; } try { if (!matches(node.asText())) { - executionContext.addError(message().instanceNode(node).instanceLocation(instanceLocation) + executionContext.addError(error().instanceNode(node).instanceLocation(instanceLocation) .locale(executionContext.getExecutionConfig().getLocale()) - .failFast(executionContext.isFailFast()).arguments(this.pattern).build()); + .arguments(this.pattern).build()); return; } - } catch (JsonSchemaException | FailFastAssertionException e) { + } catch (SchemaException | FailFastAssertionException e) { throw e; } catch (RuntimeException e) { logger.error("Failed to apply pattern '{}' at {}: {}", this.pattern, instanceLocation, e.getMessage()); diff --git a/src/main/java/com/networknt/schema/PrefixItemsValidator.java b/src/main/java/com/networknt/schema/keyword/PrefixItemsValidator.java similarity index 71% rename from src/main/java/com/networknt/schema/PrefixItemsValidator.java rename to src/main/java/com/networknt/schema/keyword/PrefixItemsValidator.java index 9abaa1848..2db49e477 100644 --- a/src/main/java/com/networknt/schema/PrefixItemsValidator.java +++ b/src/main/java/com/networknt/schema/keyword/PrefixItemsValidator.java @@ -14,37 +14,38 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ArrayNode; -import com.networknt.schema.annotation.JsonNodeAnnotation; -import com.networknt.schema.utils.JsonSchemaRefs; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaRef; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.SchemaContext; +import com.networknt.schema.annotation.Annotation; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.utils.SchemaRefs; import java.util.ArrayList; import java.util.List; /** - * {@link JsonValidator} for prefixItems. + * {@link KeywordValidator} for prefixItems. */ -public class PrefixItemsValidator extends BaseJsonValidator { - private static final Logger logger = LoggerFactory.getLogger(PrefixItemsValidator.class); - - private final List tupleSchema; +public class PrefixItemsValidator extends BaseKeywordValidator { + private final List tupleSchema; private Boolean hasUnevaluatedItemsValidator = null; - public PrefixItemsValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.PREFIX_ITEMS, validationContext); + public PrefixItemsValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, Schema parentSchema, SchemaContext schemaContext) { + super(KeywordType.PREFIX_ITEMS, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); if (schemaNode instanceof ArrayNode && !schemaNode.isEmpty()) { int i = 0; this.tupleSchema = new ArrayList<>(schemaNode.size()); for (JsonNode s : schemaNode) { - this.tupleSchema.add(validationContext.newSchema(schemaLocation.append(i), evaluationPath.append(i), s, + this.tupleSchema.add(schemaContext.newSchema(schemaLocation.append(i), evaluationPath.append(i), s, parentSchema)); i++; } @@ -54,13 +55,13 @@ public PrefixItemsValidator(SchemaLocation schemaLocation, JsonNodePath evaluati } @Override - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) { - debug(logger, executionContext, node, rootNode, instanceLocation); + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation) { + // ignores non-arrays if (node.isArray()) { int count = Math.min(node.size(), this.tupleSchema.size()); for (int i = 0; i < count; ++i) { - JsonNodePath path = instanceLocation.append(i); + NodePath path = instanceLocation.append(i); this.tupleSchema.get(i).validate(executionContext, node.get(i), rootNode, path); } @@ -72,13 +73,13 @@ public void validate(ExecutionContext executionContext, JsonNode node, JsonNode if (items > schemas) { // More items than schemas so the keyword only applied to the number of schemas executionContext.getAnnotations() - .put(JsonNodeAnnotation.builder().instanceLocation(instanceLocation) + .put(Annotation.builder().instanceLocation(instanceLocation) .evaluationPath(this.evaluationPath).schemaLocation(this.schemaLocation) .keyword(getKeyword()).value(schemas).build()); } else { // Applies to all executionContext.getAnnotations() - .put(JsonNodeAnnotation.builder().instanceLocation(instanceLocation) + .put(Annotation.builder().instanceLocation(instanceLocation) .evaluationPath(this.evaluationPath).schemaLocation(this.schemaLocation) .keyword(getKeyword()).value(true).build()); } @@ -87,13 +88,13 @@ public void validate(ExecutionContext executionContext, JsonNode node, JsonNode } @Override - public void walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation, boolean shouldValidateSchema) { + public void walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation, boolean shouldValidateSchema) { if (node instanceof ArrayNode) { ArrayNode array = (ArrayNode) node; int count = this.tupleSchema.size(); for (int i = 0; i < count; ++i) { JsonNode n = node.get(i); - if (this.validationContext.getConfig().getApplyDefaultsStrategy().shouldApplyArrayDefaults()) { + if (executionContext.getWalkConfig().getApplyDefaultsStrategy().shouldApplyArrayDefaults()) { JsonNode defaultNode = getDefaultNode(this.tupleSchema.get(i)); if (n != null) { // Defaults only set if array index is explicitly null @@ -114,13 +115,13 @@ public void walk(ExecutionContext executionContext, JsonNode node, JsonNode root if (items > schemas) { // More items than schemas so the keyword only applied to the number of schemas executionContext.getAnnotations() - .put(JsonNodeAnnotation.builder().instanceLocation(instanceLocation) + .put(Annotation.builder().instanceLocation(instanceLocation) .evaluationPath(this.evaluationPath).schemaLocation(this.schemaLocation) .keyword(getKeyword()).value(schemas).build()); } else { // Applies to all executionContext.getAnnotations() - .put(JsonNodeAnnotation.builder().instanceLocation(instanceLocation) + .put(Annotation.builder().instanceLocation(instanceLocation) .evaluationPath(this.evaluationPath).schemaLocation(this.schemaLocation) .keyword(getKeyword()).value(true).build()); } @@ -133,10 +134,10 @@ public void walk(ExecutionContext executionContext, JsonNode node, JsonNode root } } - private static JsonNode getDefaultNode(JsonSchema schema) { + private static JsonNode getDefaultNode(Schema schema) { JsonNode result = schema.getSchemaNode().get("default"); if (result == null) { - JsonSchemaRef schemaRef = JsonSchemaRefs.from(schema); + SchemaRef schemaRef = SchemaRefs.from(schema); if (schemaRef != null) { result = getDefaultNode(schemaRef.getSchema()); } @@ -145,17 +146,17 @@ private static JsonNode getDefaultNode(JsonSchema schema) { } private void doWalk(ExecutionContext executionContext, int i, - JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation, boolean shouldValidateSchema) { + JsonNode node, JsonNode rootNode, NodePath instanceLocation, boolean shouldValidateSchema) { walkSchema(executionContext, this.tupleSchema.get(i), node, rootNode, instanceLocation.append(i), shouldValidateSchema); } - private void walkSchema(ExecutionContext executionContext, JsonSchema walkSchema, JsonNode node, JsonNode rootNode, - JsonNodePath instanceLocation, boolean shouldValidateSchema) { + private void walkSchema(ExecutionContext executionContext, Schema walkSchema, JsonNode node, JsonNode rootNode, + NodePath instanceLocation, boolean shouldValidateSchema) { //@formatter:off - boolean executeWalk = this.validationContext.getConfig().getItemWalkListenerRunner().runPreWalkListeners( + boolean executeWalk = executionContext.getWalkConfig().getItemWalkListenerRunner().runPreWalkListeners( executionContext, - ValidatorTypeCode.PREFIX_ITEMS.getValue(), + KeywordType.PREFIX_ITEMS.getValue(), node, rootNode, instanceLocation, @@ -165,9 +166,9 @@ private void walkSchema(ExecutionContext executionContext, JsonSchema walkSchema if (executeWalk) { walkSchema.walk(executionContext, node, rootNode, instanceLocation, shouldValidateSchema); } - this.validationContext.getConfig().getItemWalkListenerRunner().runPostWalkListeners( + executionContext.getWalkConfig().getItemWalkListenerRunner().runPostWalkListeners( executionContext, - ValidatorTypeCode.PREFIX_ITEMS.getValue(), + KeywordType.PREFIX_ITEMS.getValue(), node, rootNode, instanceLocation, @@ -177,7 +178,7 @@ private void walkSchema(ExecutionContext executionContext, JsonSchema walkSchema //@formatter:on } - public List getTupleSchema() { + public List getTupleSchema() { return this.tupleSchema; } @@ -193,8 +194,8 @@ private boolean hasUnevaluatedItemsValidator() { } @Override - public void preloadJsonSchema() { - preloadJsonSchemas(this.tupleSchema); + public void preloadSchema() { + preloadSchemas(this.tupleSchema); collectAnnotations(); // cache the flag } diff --git a/src/main/java/com/networknt/schema/PropertiesValidator.java b/src/main/java/com/networknt/schema/keyword/PropertiesValidator.java similarity index 67% rename from src/main/java/com/networknt/schema/PropertiesValidator.java rename to src/main/java/com/networknt/schema/keyword/PropertiesValidator.java index c64e767ef..ba92c18fa 100644 --- a/src/main/java/com/networknt/schema/PropertiesValidator.java +++ b/src/main/java/com/networknt/schema/keyword/PropertiesValidator.java @@ -14,18 +14,21 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.JsonNodeType; import com.fasterxml.jackson.databind.node.MissingNode; import com.fasterxml.jackson.databind.node.ObjectNode; -import com.networknt.schema.annotation.JsonNodeAnnotation; -import com.networknt.schema.utils.JsonSchemaRefs; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaRef; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.SchemaContext; +import com.networknt.schema.annotation.Annotation; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.utils.SchemaRefs; import com.networknt.schema.walk.WalkListenerRunner; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashMap; @@ -35,41 +38,40 @@ import java.util.Set; /** - * {@link JsonValidator} for properties. + * {@link KeywordValidator} for properties. */ -public class PropertiesValidator extends BaseJsonValidator { +public class PropertiesValidator extends BaseKeywordValidator { public static final String PROPERTY = "properties"; - private static final Logger logger = LoggerFactory.getLogger(PropertiesValidator.class); - private final Map schemas = new LinkedHashMap<>(); + private final Map schemas = new LinkedHashMap<>(); private Boolean hasUnevaluatedPropertiesValidator; - public PropertiesValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.PROPERTIES, validationContext); + public PropertiesValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, Schema parentSchema, SchemaContext schemaContext) { + super(KeywordType.PROPERTIES, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); for (Iterator> it = schemaNode.fields(); it.hasNext();) { Entry entry = it.next(); String pname = entry.getKey(); - this.schemas.put(pname, validationContext.newSchema(schemaLocation.append(pname), + this.schemas.put(pname, schemaContext.newSchema(schemaLocation.append(pname), evaluationPath.append(pname), entry.getValue(), parentSchema)); } } @Override public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, - JsonNodePath instanceLocation) { + NodePath instanceLocation) { validate(executionContext, node, rootNode, instanceLocation, false); } protected void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, - JsonNodePath instanceLocation, boolean walk) { - debug(logger, executionContext, node, rootNode, instanceLocation); + NodePath instanceLocation, boolean walk) { + Set matchedInstancePropertyNames = null; boolean collectAnnotations = collectAnnotations() || collectAnnotations(executionContext); - for (Entry entry : this.schemas.entrySet()) { + for (Entry entry : this.schemas.entrySet()) { JsonNode propertyNode = node.get(entry.getKey()); if (propertyNode != null) { - JsonNodePath path = instanceLocation.append(entry.getKey()); + NodePath path = instanceLocation.append(entry.getKey()); if (collectAnnotations) { if (matchedInstancePropertyNames == null) { matchedInstancePropertyNames = new LinkedHashSet<>(); @@ -81,7 +83,7 @@ protected void validate(ExecutionContext executionContext, JsonNode node, JsonNo entry.getValue().validate(executionContext, propertyNode, rootNode, path); } else { // check if walker is enabled. If it is enabled it is upto the walker implementation to decide about the validation. - walkSchema(executionContext, entry, node, rootNode, instanceLocation, true, this.validationContext.getConfig().getPropertyWalkListenerRunner()); + walkSchema(executionContext, entry, node, rootNode, instanceLocation, true, executionContext.getWalkConfig().getPropertyWalkListenerRunner()); } } else { if (walk) { @@ -90,13 +92,13 @@ protected void validate(ExecutionContext executionContext, JsonNode node, JsonNo // null. // The actual walk needs to be skipped as the validators assume that node is not // null. - walkSchema(executionContext, entry, node, rootNode, instanceLocation, true, this.validationContext.getConfig().getPropertyWalkListenerRunner()); + walkSchema(executionContext, entry, node, rootNode, instanceLocation, true, executionContext.getWalkConfig().getPropertyWalkListenerRunner()); } } } if (collectAnnotations) { executionContext.getAnnotations() - .put(JsonNodeAnnotation.builder().instanceLocation(instanceLocation) + .put(Annotation.builder().instanceLocation(instanceLocation) .evaluationPath(this.evaluationPath).schemaLocation(this.schemaLocation) .keyword(getKeyword()).value(matchedInstancePropertyNames == null ? Collections.emptySet() : matchedInstancePropertyNames) @@ -105,17 +107,17 @@ protected void validate(ExecutionContext executionContext, JsonNode node, JsonNo } @Override - public void walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation, boolean shouldValidateSchema) { - if (this.validationContext.getConfig().getApplyDefaultsStrategy().shouldApplyPropertyDefaults() && null != node + public void walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation, boolean shouldValidateSchema) { + if (executionContext.getWalkConfig().getApplyDefaultsStrategy().shouldApplyPropertyDefaults() && null != node && node.getNodeType() == JsonNodeType.OBJECT) { - applyPropertyDefaults((ObjectNode) node); + applyPropertyDefaults((ObjectNode) node, executionContext); } if (shouldValidateSchema) { validate(executionContext, node == null ? MissingNode.getInstance() : node, rootNode, instanceLocation, true); } else { - WalkListenerRunner propertyWalkListenerRunner = this.validationContext.getConfig().getPropertyWalkListenerRunner(); - for (Map.Entry entry : this.schemas.entrySet()) { + WalkListenerRunner propertyWalkListenerRunner = executionContext.getWalkConfig().getPropertyWalkListenerRunner(); + for (Map.Entry entry : this.schemas.entrySet()) { walkSchema(executionContext, entry, node, rootNode, instanceLocation, shouldValidateSchema, propertyWalkListenerRunner); } } @@ -132,15 +134,15 @@ private boolean hasUnevaluatedPropertiesValidator() { return hasUnevaluatedPropertiesValidator; } - private void applyPropertyDefaults(ObjectNode node) { - for (Map.Entry entry : this.schemas.entrySet()) { + private void applyPropertyDefaults(ObjectNode node, ExecutionContext executionContext) { + for (Map.Entry entry : this.schemas.entrySet()) { JsonNode propertyNode = node.get(entry.getKey()); JsonNode defaultNode = getDefaultNode(entry.getValue()); if (defaultNode == null) { continue; } - boolean applyDefault = propertyNode == null || (propertyNode.isNull() && this.validationContext.getConfig() + boolean applyDefault = propertyNode == null || (propertyNode.isNull() && executionContext.getWalkConfig() .getApplyDefaultsStrategy().shouldApplyPropertyDefaultsIfNull()); if (applyDefault) { node.set(entry.getKey(), defaultNode); @@ -148,10 +150,10 @@ private void applyPropertyDefaults(ObjectNode node) { } } - private static JsonNode getDefaultNode(JsonSchema schema) { + private static JsonNode getDefaultNode(Schema schema) { JsonNode result = schema.getSchemaNode().get("default"); if (result == null) { - JsonSchemaRef schemaRef = JsonSchemaRefs.from(schema); + SchemaRef schemaRef = SchemaRefs.from(schema); if (schemaRef != null) { result = getDefaultNode(schemaRef.getSchema()); } @@ -159,13 +161,13 @@ private static JsonNode getDefaultNode(JsonSchema schema) { return result; } - private void walkSchema(ExecutionContext executionContext, Map.Entry entry, JsonNode node, - JsonNode rootNode, JsonNodePath instanceLocation, boolean shouldValidateSchema, WalkListenerRunner propertyWalkListenerRunner) { - JsonSchema propertySchema = entry.getValue(); + private void walkSchema(ExecutionContext executionContext, Map.Entry entry, JsonNode node, + JsonNode rootNode, NodePath instanceLocation, boolean shouldValidateSchema, WalkListenerRunner propertyWalkListenerRunner) { + Schema propertySchema = entry.getValue(); JsonNode propertyNode = (node == null ? null : node.get(entry.getKey())); - JsonNodePath path = instanceLocation.append(entry.getKey()); + NodePath path = instanceLocation.append(entry.getKey()); boolean executeWalk = propertyWalkListenerRunner.runPreWalkListeners(executionContext, - ValidatorTypeCode.PROPERTIES.getValue(), propertyNode, rootNode, path, + KeywordType.PROPERTIES.getValue(), propertyNode, rootNode, path, propertySchema, this); if (propertyNode == null && node != null) { // Attempt to get the property node again in case the propertyNode was updated @@ -175,18 +177,18 @@ private void walkSchema(ExecutionContext executionContext, Map.Entry getSchemas() { + public Map getSchemas() { return this.schemas; } @Override - public void preloadJsonSchema() { - preloadJsonSchemas(this.schemas.values()); + public void preloadSchema() { + preloadSchemas(this.schemas.values()); collectAnnotations(); // cache the flag } } diff --git a/src/main/java/com/networknt/schema/keyword/PropertyDependenciesValidator.java b/src/main/java/com/networknt/schema/keyword/PropertyDependenciesValidator.java new file mode 100644 index 000000000..4d13cdd42 --- /dev/null +++ b/src/main/java/com/networknt/schema/keyword/PropertyDependenciesValidator.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.networknt.schema.keyword; + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import com.fasterxml.jackson.databind.JsonNode; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaContext; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.path.NodePath; + +/** + * {@link KeywordValidator} for propertyDependencies. + */ +public class PropertyDependenciesValidator extends BaseKeywordValidator implements KeywordValidator { + /* + * Property Name -> Property Value -> Schema + */ + private final Map> propertyDependencies; + + public PropertyDependenciesValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, + Schema parentSchema, SchemaContext schemaContext) { + super(KeywordType.PROPERTY_DEPENDENCIES, schemaNode, schemaLocation, parentSchema, schemaContext, + evaluationPath); + Set> properties = schemaNode.properties(); + this.propertyDependencies = new LinkedHashMap<>(properties.size()); + for (Entry property : properties) { + String propertyName = property.getKey(); + SchemaLocation propertySchemaLocation = schemaLocation.append(propertyName); + NodePath propertyEvaluationPath = evaluationPath.append(propertyName); + + Set> propertyValues = property.getValue().properties(); + for (Entry propertyValue : propertyValues) { + Map valueSchemas = this.propertyDependencies.computeIfAbsent(propertyName, + key -> new LinkedHashMap<>()); + valueSchemas.put(propertyValue.getKey(), + schemaContext.newSchema(propertySchemaLocation.append(propertyValue.getKey()), + propertyEvaluationPath.append(propertyValue.getKey()), propertyValue.getValue(), + parentSchema)); + } + } + } + + @Override + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, + NodePath instanceLocation) { + validate(executionContext, node, rootNode, instanceLocation, false); + } + + protected void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, + NodePath instanceLocation, boolean walk) { + Set> properties = node.properties(); + for (Entry property : properties) { + String propertyName = property.getKey(); + String propertyValue = property.getValue().asText(); + if (propertyValue != null) { + Map propertySchemas = this.propertyDependencies.get(propertyName); + if (propertySchemas != null) { + Schema schema = propertySchemas.get(propertyValue); + if (schema != null) { + if (!walk) { + schema.validate(executionContext, node, rootNode, instanceLocation); + } else { + schema.walk(executionContext, node, rootNode, instanceLocation, true); + } + } + } + } + } + } + + @Override + public void walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation, + boolean shouldValidateSchema) { + if (shouldValidateSchema) { + validate(executionContext, node, rootNode, instanceLocation, true); + return; + } + + for (Map properties : this.propertyDependencies.values()) { + for (Schema schema : properties.values()) { + schema.walk(executionContext, node, rootNode, instanceLocation, false); + } + } + } + + @Override + public void preloadSchema() { + for (Map properties : propertyDependencies.values()) { + for (Schema schema : properties.values()) { + schema.initializeValidators(); + } + } + } +} diff --git a/src/main/java/com/networknt/schema/PropertyNamesValidator.java b/src/main/java/com/networknt/schema/keyword/PropertyNamesValidator.java similarity index 50% rename from src/main/java/com/networknt/schema/PropertyNamesValidator.java rename to src/main/java/com/networknt/schema/keyword/PropertyNamesValidator.java index 0fa90bed5..a3502cee8 100644 --- a/src/main/java/com/networknt/schema/PropertyNamesValidator.java +++ b/src/main/java/com/networknt/schema/keyword/PropertyNamesValidator.java @@ -13,46 +13,43 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.TextNode; +import com.networknt.schema.Error; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.SchemaContext; -public class PropertyNamesValidator extends BaseJsonValidator implements JsonValidator { - private static final Logger logger = LoggerFactory.getLogger(PropertyNamesValidator.class); - private final JsonSchema innerSchema; - public PropertyNamesValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.PROPERTYNAMES, validationContext); - innerSchema = validationContext.newSchema(schemaLocation, evaluationPath, schemaNode, parentSchema); +public class PropertyNamesValidator extends BaseKeywordValidator implements KeywordValidator { + private final Schema innerSchema; + public PropertyNamesValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, Schema parentSchema, SchemaContext schemaContext) { + super(KeywordType.PROPERTY_NAMES, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); + innerSchema = schemaContext.newSchema(schemaLocation, evaluationPath, schemaNode, parentSchema); } - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) { - debug(logger, executionContext, node, rootNode, instanceLocation); + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation) { + - List existingErrors = executionContext.getErrors(); - List schemaErrors = new ArrayList<>(); + List existingErrors = executionContext.getErrors(); + List schemaErrors = new ArrayList<>(); executionContext.setErrors(schemaErrors); for (Iterator it = node.fieldNames(); it.hasNext(); ) { final String pname = it.next(); final TextNode pnameText = TextNode.valueOf(pname); innerSchema.validate(executionContext, pnameText, node, instanceLocation.append(pname)); - for (final ValidationMessage schemaError : schemaErrors) { - final String path = schemaError.getInstanceLocation().toString(); - String msg = schemaError.getMessage(); - if (msg.startsWith(path)) { - msg = msg.substring(path.length()).replaceFirst("^:\\s*", ""); - } + for (final Error schemaError : schemaErrors) { existingErrors.add( - message().property(pname).instanceNode(node).instanceLocation(instanceLocation) + error().property(pname).instanceNode(node).instanceLocation(instanceLocation) .locale(executionContext.getExecutionConfig().getLocale()) - .failFast(executionContext.isFailFast()).arguments(pname, msg).build()); + .arguments(pname, schemaError.getMessage()).build()); } schemaErrors.clear(); } @@ -61,7 +58,7 @@ public void validate(ExecutionContext executionContext, JsonNode node, JsonNode @Override - public void preloadJsonSchema() { + public void preloadSchema() { innerSchema.initializeValidators(); } } diff --git a/src/main/java/com/networknt/schema/ReadOnlyValidator.java b/src/main/java/com/networknt/schema/keyword/ReadOnlyValidator.java similarity index 53% rename from src/main/java/com/networknt/schema/ReadOnlyValidator.java rename to src/main/java/com/networknt/schema/keyword/ReadOnlyValidator.java index f9416fe07..530711df3 100644 --- a/src/main/java/com/networknt/schema/ReadOnlyValidator.java +++ b/src/main/java/com/networknt/schema/keyword/ReadOnlyValidator.java @@ -14,35 +14,36 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.fasterxml.jackson.databind.JsonNode; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.SchemaContext; /** - * {@link JsonValidator} for readOnly. + * {@link KeywordValidator} for readOnly. */ -public class ReadOnlyValidator extends BaseJsonValidator { +public class ReadOnlyValidator extends BaseKeywordValidator { private static final Logger logger = LoggerFactory.getLogger(ReadOnlyValidator.class); - private final boolean readOnly; - - public ReadOnlyValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.READ_ONLY, validationContext); - - this.readOnly = validationContext.getConfig().isReadOnly(); + public ReadOnlyValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, Schema parentSchema, SchemaContext schemaContext) { + super(KeywordType.READ_ONLY, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); logger.debug("Loaded ReadOnlyValidator for property {} as {}", parentSchema, "read mode"); } @Override - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) { - debug(logger, executionContext, node, rootNode, instanceLocation); - if (this.readOnly) { - executionContext.addError(message().instanceNode(node).instanceLocation(instanceLocation) + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation) { + + if (Boolean.TRUE.equals(executionContext.getExecutionConfig().getReadOnly())) { + executionContext.addError(error().instanceNode(node).instanceLocation(instanceLocation) .locale(executionContext.getExecutionConfig().getLocale()) - .failFast(executionContext.isFailFast()).build()); + .build()); } return; } diff --git a/src/main/java/com/networknt/schema/RecursiveRefValidator.java b/src/main/java/com/networknt/schema/keyword/RecursiveRefValidator.java similarity index 59% rename from src/main/java/com/networknt/schema/RecursiveRefValidator.java rename to src/main/java/com/networknt/schema/keyword/RecursiveRefValidator.java index 31688aa2f..e864d3aef 100644 --- a/src/main/java/com/networknt/schema/RecursiveRefValidator.java +++ b/src/main/java/com/networknt/schema/keyword/RecursiveRefValidator.java @@ -14,51 +14,57 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import com.fasterxml.jackson.databind.JsonNode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.networknt.schema.Error; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.InvalidSchemaRefException; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaException; +import com.networknt.schema.SchemaRef; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.utils.ThreadSafeCachingSupplier; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.SchemaContext; import java.util.function.Supplier; /** - * {@link JsonValidator} that resolves $recursiveRef. + * {@link KeywordValidator} that resolves $recursiveRef. */ -public class RecursiveRefValidator extends BaseJsonValidator { - private static final Logger logger = LoggerFactory.getLogger(RecursiveRefValidator.class); +public class RecursiveRefValidator extends BaseKeywordValidator { + protected final SchemaRef schema; - protected final JsonSchemaRef schema; - - public RecursiveRefValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.RECURSIVE_REF, validationContext); + public RecursiveRefValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, Schema parentSchema, SchemaContext schemaContext) { + super(KeywordType.RECURSIVE_REF, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); String refValue = schemaNode.asText(); if (!"#".equals(refValue)) { - ValidationMessage validationMessage = message() - .type(ValidatorTypeCode.RECURSIVE_REF.getValue()).code("internal.invalidRecursiveRef") - .message("{0}: The value of a $recursiveRef must be '#' but is '{1}'").instanceLocation(schemaLocation.getFragment()) + Error error = error() + .keyword(KeywordType.RECURSIVE_REF.getValue()).messageKey("internal.invalidRecursiveRef") + .message("The value of a $recursiveRef must be '#' but is '{0}'").instanceLocation(schemaLocation.getFragment()) .instanceNode(this.schemaNode) .evaluationPath(evaluationPath).arguments(refValue).build(); - throw new JsonSchemaException(validationMessage); + throw new SchemaException(error); } - this.schema = getRefSchema(parentSchema, validationContext, refValue, evaluationPath); + this.schema = getRefSchema(parentSchema, schemaContext, refValue, evaluationPath); } - static JsonSchemaRef getRefSchema(JsonSchema parentSchema, ValidationContext validationContext, String refValue, - JsonNodePath evaluationPath) { - return new JsonSchemaRef(getSupplier(() -> getSchema(parentSchema, validationContext, refValue, evaluationPath), validationContext.getConfig().isCacheRefs())); + static SchemaRef getRefSchema(Schema parentSchema, SchemaContext schemaContext, String refValue, + NodePath evaluationPath) { + return new SchemaRef(getSupplier(() -> getSchema(parentSchema, schemaContext, refValue, evaluationPath), schemaContext.getSchemaRegistryConfig().isCacheRefs())); } static Supplier getSupplier(Supplier supplier, boolean cache) { - return cache ? new CachedSupplier<>(supplier) : supplier; + return cache ? new ThreadSafeCachingSupplier<>(supplier) : supplier; } - static JsonSchema getSchema(JsonSchema parentSchema, ValidationContext validationContext, String refValue, - JsonNodePath evaluationPath) { - JsonSchema refSchema = parentSchema.findSchemaResourceRoot(); // Get the document - JsonSchema current = refSchema; - JsonSchema check = null; + static Schema getSchema(Schema parentSchema, SchemaContext schemaContext, String refValue, + NodePath evaluationPath) { + Schema refSchema = parentSchema.findSchemaResourceRoot(); // Get the document + Schema current = refSchema; + Schema check = null; String base = null; String baseCheck = null; if (refSchema != null) @@ -85,37 +91,37 @@ static JsonSchema getSchema(JsonSchema parentSchema, ValidationContext validatio } @Override - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) { - debug(logger, executionContext, node, rootNode, instanceLocation); - JsonSchema refSchema = this.schema.getSchema(); + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation) { + + Schema refSchema = this.schema.getSchema(); if (refSchema == null) { - ValidationMessage validationMessage = message().type(ValidatorTypeCode.RECURSIVE_REF.getValue()) - .code("internal.unresolvedRef").message("{0}: Reference {1} cannot be resolved") + Error error = error().keyword(KeywordType.RECURSIVE_REF.getValue()) + .messageKey("internal.unresolvedRef").message("Reference {0} cannot be resolved") .instanceLocation(instanceLocation).evaluationPath(getEvaluationPath()) .arguments(schemaNode.asText()).build(); - throw new InvalidSchemaRefException(validationMessage); + throw new InvalidSchemaRefException(error); } refSchema.validate(executionContext, node, rootNode, instanceLocation); } @Override - public void walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation, boolean shouldValidateSchema) { - debug(logger, executionContext, node, rootNode, instanceLocation); + public void walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation, boolean shouldValidateSchema) { + // This is important because if we use same JsonSchemaFactory for creating multiple JSONSchema instances, // these schemas will be cached along with config. We have to replace the config for cached $ref references // with the latest config. Reset the config. - JsonSchema refSchema = this.schema.getSchema(); + Schema refSchema = this.schema.getSchema(); if (refSchema == null) { - ValidationMessage validationMessage = message().type(ValidatorTypeCode.RECURSIVE_REF.getValue()) - .code("internal.unresolvedRef").message("{0}: Reference {1} cannot be resolved") + Error error = error().keyword(KeywordType.RECURSIVE_REF.getValue()) + .messageKey("internal.unresolvedRef").message("Reference {0} cannot be resolved") .instanceLocation(instanceLocation).evaluationPath(getEvaluationPath()) .arguments(schemaNode.asText()).build(); - throw new InvalidSchemaRefException(validationMessage); + throw new InvalidSchemaRefException(error); } if (node == null) { // Check for circular dependency SchemaLocation schemaLocation = refSchema.getSchemaLocation(); - JsonSchema check = refSchema; + Schema check = refSchema; boolean circularDependency = false; while (check.getEvaluationParentSchema() != null) { check = check.getEvaluationParentSchema(); @@ -131,26 +137,26 @@ public void walk(ExecutionContext executionContext, JsonNode node, JsonNode root refSchema.walk(executionContext, node, rootNode, instanceLocation, shouldValidateSchema); } - public JsonSchemaRef getSchemaRef() { + public SchemaRef getSchemaRef() { return this.schema; } @Override - public void preloadJsonSchema() { - JsonSchema jsonSchema = null; + public void preloadSchema() { + Schema jsonSchema = null; try { jsonSchema = this.schema.getSchema(); - } catch (JsonSchemaException e) { + } catch (SchemaException e) { throw e; } catch (RuntimeException e) { - throw new JsonSchemaException(e); + throw new SchemaException(e); } // Check for circular dependency // Only one cycle is pre-loaded // The rest of the cycles will load at execution time depending on the input // data SchemaLocation schemaLocation = jsonSchema.getSchemaLocation(); - JsonSchema check = jsonSchema; + Schema check = jsonSchema; boolean circularDependency = false; int depth = 0; while (check.getEvaluationParentSchema() != null) { @@ -161,8 +167,8 @@ public void preloadJsonSchema() { break; } } - if (this.validationContext.getConfig().isCacheRefs() && !circularDependency - && depth < this.validationContext.getConfig().getPreloadJsonSchemaRefMaxNestingDepth()) { + if (this.schemaContext.getSchemaRegistryConfig().isCacheRefs() && !circularDependency + && depth < this.schemaContext.getSchemaRegistryConfig().getPreloadSchemaRefMaxNestingDepth()) { jsonSchema.initializeValidators(); } } diff --git a/src/main/java/com/networknt/schema/RefValidator.java b/src/main/java/com/networknt/schema/keyword/RefValidator.java similarity index 54% rename from src/main/java/com/networknt/schema/RefValidator.java rename to src/main/java/com/networknt/schema/keyword/RefValidator.java index c173f8140..105744cb8 100644 --- a/src/main/java/com/networknt/schema/RefValidator.java +++ b/src/main/java/com/networknt/schema/keyword/RefValidator.java @@ -14,32 +14,38 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import com.fasterxml.jackson.databind.JsonNode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.networknt.schema.Error; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.InvalidSchemaRefException; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaException; +import com.networknt.schema.SchemaRef; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.utils.ThreadSafeCachingSupplier; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.SchemaContext; import java.util.function.Supplier; /** - * {@link JsonValidator} that resolves $ref. + * {@link KeywordValidator} that resolves $ref. */ -public class RefValidator extends BaseJsonValidator { - private static final Logger logger = LoggerFactory.getLogger(RefValidator.class); - - protected final JsonSchemaRef schema; +public class RefValidator extends BaseKeywordValidator { + protected final SchemaRef schema; private static final String REF_CURRENT = "#"; - public RefValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.REF, validationContext); + public RefValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, Schema parentSchema, SchemaContext schemaContext) { + super(KeywordType.REF, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); String refValue = schemaNode.asText(); - this.schema = getRefSchema(parentSchema, validationContext, refValue, evaluationPath); + this.schema = getRefSchema(parentSchema, schemaContext, refValue, evaluationPath); } - static JsonSchemaRef getRefSchema(JsonSchema parentSchema, ValidationContext validationContext, String refValue, - JsonNodePath evaluationPath) { + static SchemaRef getRefSchema(Schema parentSchema, SchemaContext schemaContext, String refValue, + NodePath evaluationPath) { // The evaluationPath is used to derive the keywordLocation final String refValueOriginal = refValue; @@ -58,12 +64,12 @@ static JsonSchemaRef getRefSchema(JsonSchema parentSchema, ValidationContext val String schemaUriFinal = resolve(parentSchema, refUri); SchemaLocation schemaLocation = SchemaLocation.of(schemaUriFinal); // This should retrieve schemas regardless of the protocol that is in the uri. - return new JsonSchemaRef(getSupplier(() -> { - JsonSchema schemaResource = validationContext.getSchemaResources().get(schemaUriFinal); + return new SchemaRef(getSupplier(() -> { + Schema schemaResource = schemaContext.getSchemaResources().get(schemaUriFinal); if (schemaResource == null) { - schemaResource = validationContext.getJsonSchemaFactory().loadSchema(schemaLocation, validationContext.getConfig()); + schemaResource = schemaContext.getSchemaRegistry().loadSchema(schemaLocation); if (schemaResource != null) { - copySchemaResources(validationContext, schemaResource); + copySchemaResources(schemaContext, schemaResource); } } if (index < 0) { @@ -74,14 +80,14 @@ static JsonSchemaRef getRefSchema(JsonSchema parentSchema, ValidationContext val } else { String newRefValue = refValue.substring(index); String find = schemaLocation.getAbsoluteIri() + newRefValue; - JsonSchema findSchemaResource = validationContext.getSchemaResources().get(find); + Schema findSchemaResource = schemaContext.getSchemaResources().get(find); if (findSchemaResource == null) { - findSchemaResource = validationContext.getDynamicAnchors().get(find); + findSchemaResource = schemaContext.getDynamicAnchors().get(find); } if (findSchemaResource != null) { schemaResource = findSchemaResource; } else { - schemaResource = getJsonSchema(schemaResource, validationContext, newRefValue, refValueOriginal, + schemaResource = getSchema(schemaResource, schemaContext, newRefValue, refValueOriginal, evaluationPath); } if (schemaResource == null) { @@ -89,83 +95,83 @@ static JsonSchemaRef getRefSchema(JsonSchema parentSchema, ValidationContext val } return schemaResource.fromRef(parentSchema, evaluationPath); } - }, validationContext.getConfig().isCacheRefs())); + }, schemaContext.getSchemaRegistryConfig().isCacheRefs())); } else if (SchemaLocation.Fragment.isAnchorFragment(refValue)) { String absoluteIri = resolve(parentSchema, refValue); // Schema resource needs to update the parent and evaluation path - return new JsonSchemaRef(getSupplier(() -> { - JsonSchema schemaResource = validationContext.getSchemaResources().get(absoluteIri); + return new SchemaRef(getSupplier(() -> { + Schema schemaResource = schemaContext.getSchemaResources().get(absoluteIri); if (schemaResource == null) { - schemaResource = validationContext.getDynamicAnchors().get(absoluteIri); + schemaResource = schemaContext.getDynamicAnchors().get(absoluteIri); } if (schemaResource == null) { - schemaResource = getJsonSchema(parentSchema, validationContext, refValue, refValueOriginal, evaluationPath); + schemaResource = getSchema(parentSchema, schemaContext, refValue, refValueOriginal, evaluationPath); } if (schemaResource == null) { return null; } return schemaResource.fromRef(parentSchema, evaluationPath); - }, validationContext.getConfig().isCacheRefs())); + }, schemaContext.getSchemaRegistryConfig().isCacheRefs())); } if (refValue.equals(REF_CURRENT)) { - return new JsonSchemaRef( + return new SchemaRef( getSupplier(() -> parentSchema.findSchemaResourceRoot().fromRef(parentSchema, evaluationPath), - validationContext.getConfig().isCacheRefs())); + schemaContext.getSchemaRegistryConfig().isCacheRefs())); } - return new JsonSchemaRef(getSupplier( - () -> getJsonSchema(parentSchema, validationContext, refValue, refValueOriginal, evaluationPath) + return new SchemaRef(getSupplier( + () -> getSchema(parentSchema, schemaContext, refValue, refValueOriginal, evaluationPath) .fromRef(parentSchema, evaluationPath), - validationContext.getConfig().isCacheRefs())); + schemaContext.getSchemaRegistryConfig().isCacheRefs())); } static Supplier getSupplier(Supplier supplier, boolean cache) { - return cache ? new CachedSupplier<>(supplier) : supplier; + return cache ? new ThreadSafeCachingSupplier<>(supplier) : supplier; } - private static void copySchemaResources(ValidationContext validationContext, JsonSchema schemaResource) { - if (!schemaResource.getValidationContext().getSchemaResources().isEmpty()) { - validationContext.getSchemaResources() - .putAll(schemaResource.getValidationContext().getSchemaResources()); + private static void copySchemaResources(SchemaContext schemaContext, Schema schemaResource) { + if (!schemaResource.getSchemaContext().getSchemaResources().isEmpty()) { + schemaContext.getSchemaResources() + .putAll(schemaResource.getSchemaContext().getSchemaResources()); } - if (!schemaResource.getValidationContext().getSchemaReferences().isEmpty()) { - validationContext.getSchemaReferences() - .putAll(schemaResource.getValidationContext().getSchemaReferences()); + if (!schemaResource.getSchemaContext().getSchemaReferences().isEmpty()) { + schemaContext.getSchemaReferences() + .putAll(schemaResource.getSchemaContext().getSchemaReferences()); } - if (!schemaResource.getValidationContext().getDynamicAnchors().isEmpty()) { - validationContext.getDynamicAnchors() - .putAll(schemaResource.getValidationContext().getDynamicAnchors()); + if (!schemaResource.getSchemaContext().getDynamicAnchors().isEmpty()) { + schemaContext.getDynamicAnchors() + .putAll(schemaResource.getSchemaContext().getDynamicAnchors()); } } - private static String resolve(JsonSchema parentSchema, String refValue) { + private static String resolve(Schema parentSchema, String refValue) { // $ref prevents a sibling $id from changing the base uri - JsonSchema base = parentSchema; - if (parentSchema.getId() != null && parentSchema.parentSchema != null) { - base = parentSchema.parentSchema; + Schema base = parentSchema; + if (parentSchema.getId() != null && parentSchema.getParentSchema() != null) { + base = parentSchema.getParentSchema(); } return SchemaLocation.resolve(base.getSchemaLocation(), refValue); } - private static JsonSchema getJsonSchema(JsonSchema parent, - ValidationContext validationContext, + private static Schema getSchema(Schema parent, + SchemaContext schemaContext, String refValue, String refValueOriginal, - JsonNodePath evaluationPath) { + NodePath evaluationPath) { // This should be processing json pointer fragments only - JsonNodePath fragment = SchemaLocation.Fragment.of(refValue); + NodePath fragment = SchemaLocation.Fragment.of(refValue); String schemaReference = resolve(parent, refValueOriginal); // ConcurrentHashMap computeIfAbsent does not allow calls that result in a // recursive update to the map. // The getSubSchema potentially recurses to call back to getJsonSchema again - JsonSchema result = validationContext.getSchemaReferences().get(schemaReference); + Schema result = schemaContext.getSchemaReferences().get(schemaReference); if (result == null) { - synchronized (validationContext.getJsonSchemaFactory()) { // acquire lock on shared factory object to prevent deadlock - result = validationContext.getSchemaReferences().get(schemaReference); + synchronized (schemaContext.getSchemaRegistry()) { // acquire lock on shared factory object to prevent deadlock + result = schemaContext.getSchemaReferences().get(schemaReference); if (result == null) { result = parent.getSubSchema(fragment); if (result != null) { - validationContext.getSchemaReferences().put(schemaReference, result); + schemaContext.getSchemaReferences().put(schemaReference, result); } } } @@ -174,37 +180,37 @@ private static JsonSchema getJsonSchema(JsonSchema parent, } @Override - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) { - debug(logger, executionContext, node, rootNode, instanceLocation); - JsonSchema refSchema = this.schema.getSchema(); + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation) { + + Schema refSchema = this.schema.getSchema(); if (refSchema == null) { - ValidationMessage validationMessage = message().type(ValidatorTypeCode.REF.getValue()) - .code("internal.unresolvedRef").message("{0}: Reference {1} cannot be resolved") + Error error = error().keyword(KeywordType.REF.getValue()) + .messageKey("internal.unresolvedRef").message("Reference {0} cannot be resolved") .instanceLocation(instanceLocation).evaluationPath(getEvaluationPath()) .arguments(schemaNode.asText()).build(); - throw new InvalidSchemaRefException(validationMessage); + throw new InvalidSchemaRefException(error); } refSchema.validate(executionContext, node, rootNode, instanceLocation); } @Override - public void walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation, boolean shouldValidateSchema) { - debug(logger, executionContext, node, rootNode, instanceLocation); + public void walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation, boolean shouldValidateSchema) { + // This is important because if we use same JsonSchemaFactory for creating multiple JSONSchema instances, // these schemas will be cached along with config. We have to replace the config for cached $ref references // with the latest config. Reset the config. - JsonSchema refSchema = this.schema.getSchema(); + Schema refSchema = this.schema.getSchema(); if (refSchema == null) { - ValidationMessage validationMessage = message().type(ValidatorTypeCode.REF.getValue()) - .code("internal.unresolvedRef").message("{0}: Reference {1} cannot be resolved") + Error error = error().keyword(KeywordType.REF.getValue()) + .messageKey("internal.unresolvedRef").message("Reference {0} cannot be resolved") .instanceLocation(instanceLocation).evaluationPath(getEvaluationPath()) .arguments(schemaNode.asText()).build(); - throw new InvalidSchemaRefException(validationMessage); + throw new InvalidSchemaRefException(error); } if (node == null) { // Check for circular dependency SchemaLocation schemaLocation = refSchema.getSchemaLocation(); - JsonSchema check = refSchema; + Schema check = refSchema; boolean circularDependency = false; while (check.getEvaluationParentSchema() != null) { check = check.getEvaluationParentSchema(); @@ -220,26 +226,26 @@ public void walk(ExecutionContext executionContext, JsonNode node, JsonNode root refSchema.walk(executionContext, node, rootNode, instanceLocation, shouldValidateSchema); } - public JsonSchemaRef getSchemaRef() { + public SchemaRef getSchemaRef() { return this.schema; } @Override - public void preloadJsonSchema() { - JsonSchema jsonSchema = null; + public void preloadSchema() { + Schema jsonSchema = null; try { jsonSchema = this.schema.getSchema(); - } catch (JsonSchemaException e) { + } catch (SchemaException e) { throw e; } catch (RuntimeException e) { - throw new JsonSchemaException(e); + throw new SchemaException(e); } // Check for circular dependency // Only one cycle is pre-loaded // The rest of the cycles will load at execution time depending on the input // data SchemaLocation schemaLocation = jsonSchema.getSchemaLocation(); - JsonSchema check = jsonSchema; + Schema check = jsonSchema; boolean circularDependency = false; int depth = 0; while (check.getEvaluationParentSchema() != null) { @@ -250,8 +256,8 @@ public void preloadJsonSchema() { break; } } - if (this.validationContext.getConfig().isCacheRefs() && !circularDependency - && depth < this.validationContext.getConfig().getPreloadJsonSchemaRefMaxNestingDepth()) { + if (this.schemaContext.getSchemaRegistryConfig().isCacheRefs() && !circularDependency + && depth < this.schemaContext.getSchemaRegistryConfig().getPreloadSchemaRefMaxNestingDepth()) { jsonSchema.initializeValidators(); } } diff --git a/src/main/java/com/networknt/schema/RequiredValidator.java b/src/main/java/com/networknt/schema/keyword/RequiredValidator.java similarity index 68% rename from src/main/java/com/networknt/schema/RequiredValidator.java rename to src/main/java/com/networknt/schema/keyword/RequiredValidator.java index 41bfa3c5b..ca5c337b8 100644 --- a/src/main/java/com/networknt/schema/RequiredValidator.java +++ b/src/main/java/com/networknt/schema/keyword/RequiredValidator.java @@ -14,24 +14,25 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import com.fasterxml.jackson.databind.JsonNode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.SchemaContext; import java.util.*; /** - * {@link JsonValidator} for required. + * {@link KeywordValidator} for required. */ -public class RequiredValidator extends BaseJsonValidator implements JsonValidator { - private static final Logger logger = LoggerFactory.getLogger(RequiredValidator.class); - +public class RequiredValidator extends BaseKeywordValidator implements KeywordValidator { private final List fieldNames; - public RequiredValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.REQUIRED, validationContext); + public RequiredValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, Schema parentSchema, SchemaContext schemaContext) { + super(KeywordType.REQUIRED, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); if (schemaNode.isArray()) { this.fieldNames = new ArrayList<>(schemaNode.size()); for (JsonNode fieldNme : schemaNode) { @@ -42,8 +43,8 @@ public RequiredValidator(SchemaLocation schemaLocation, JsonNodePath evaluationP } } - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) { - debug(logger, executionContext, node, rootNode, instanceLocation); + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation) { + if (!node.isObject()) { return; @@ -53,8 +54,8 @@ public void validate(ExecutionContext executionContext, JsonNode node, JsonNode JsonNode propertyNode = node.get(fieldName); if (propertyNode == null) { - Boolean readOnly = this.validationContext.getConfig().getReadOnly(); - Boolean writeOnly = this.validationContext.getConfig().getWriteOnly(); + Boolean readOnly = executionContext.getExecutionConfig().getReadOnly(); + Boolean writeOnly = executionContext.getExecutionConfig().getWriteOnly(); if (Boolean.TRUE.equals(readOnly)) { JsonNode readOnlyNode = getFieldKeyword(fieldName, "readOnly"); if (readOnlyNode != null && readOnlyNode.booleanValue()) { @@ -71,9 +72,9 @@ public void validate(ExecutionContext executionContext, JsonNode node, JsonNode *

* @see Basic */ - executionContext.addError(message().instanceNode(node).property(fieldName).instanceLocation(instanceLocation) + executionContext.addError(error().instanceNode(node).property(fieldName).instanceLocation(instanceLocation) .locale(executionContext.getExecutionConfig().getLocale()) - .failFast(executionContext.isFailFast()).arguments(fieldName).build()); + .arguments(fieldName).build()); } } } diff --git a/src/main/java/com/networknt/schema/ThresholdMixin.java b/src/main/java/com/networknt/schema/keyword/ThresholdMixin.java similarity index 95% rename from src/main/java/com/networknt/schema/ThresholdMixin.java rename to src/main/java/com/networknt/schema/keyword/ThresholdMixin.java index 99399fb23..de67ea498 100644 --- a/src/main/java/com/networknt/schema/ThresholdMixin.java +++ b/src/main/java/com/networknt/schema/keyword/ThresholdMixin.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import com.fasterxml.jackson.databind.JsonNode; diff --git a/src/main/java/com/networknt/schema/TrueValidator.java b/src/main/java/com/networknt/schema/keyword/TrueValidator.java similarity index 52% rename from src/main/java/com/networknt/schema/TrueValidator.java rename to src/main/java/com/networknt/schema/keyword/TrueValidator.java index 0c02cbb85..71347de9d 100644 --- a/src/main/java/com/networknt/schema/TrueValidator.java +++ b/src/main/java/com/networknt/schema/keyword/TrueValidator.java @@ -13,24 +13,25 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import com.fasterxml.jackson.databind.JsonNode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.SchemaContext; /** - * {@link JsonValidator} for true. + * {@link KeywordValidator} for true. */ -public class TrueValidator extends BaseJsonValidator implements JsonValidator { - private static final Logger logger = LoggerFactory.getLogger(TrueValidator.class); - - public TrueValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, final JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.TRUE, validationContext); +public class TrueValidator extends BaseKeywordValidator implements KeywordValidator { + public TrueValidator(SchemaLocation schemaLocation, NodePath evaluationPath, final JsonNode schemaNode, Schema parentSchema, SchemaContext schemaContext) { + super(KeywordType.TRUE, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); } - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) { - debug(logger, executionContext, node, rootNode, instanceLocation); - // For the true validator, it is always valid which means there is no ValidationMessage. + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation) { + + // For the true validator, it is always valid which means there is no Error. } } diff --git a/src/main/java/com/networknt/schema/TypeValidator.java b/src/main/java/com/networknt/schema/keyword/TypeValidator.java similarity index 60% rename from src/main/java/com/networknt/schema/TypeValidator.java rename to src/main/java/com/networknt/schema/keyword/TypeValidator.java index bbe0b54d6..0c67413c6 100644 --- a/src/main/java/com/networknt/schema/TypeValidator.java +++ b/src/main/java/com/networknt/schema/keyword/TypeValidator.java @@ -14,27 +14,30 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import com.fasterxml.jackson.databind.JsonNode; -import com.networknt.schema.utils.JsonNodeUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.SchemaContext; +import com.networknt.schema.utils.JsonNodeTypes; +import com.networknt.schema.utils.JsonType; +import com.networknt.schema.utils.TypeFactory; /** - * {@link JsonValidator} for type. + * {@link KeywordValidator} for type. */ -public class TypeValidator extends BaseJsonValidator { - private static final Logger logger = LoggerFactory.getLogger(TypeValidator.class); - +public class TypeValidator extends BaseKeywordValidator { private final JsonType schemaType; private final UnionTypeValidator unionTypeValidator; - public TypeValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.TYPE, validationContext); + public TypeValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, Schema parentSchema, SchemaContext schemaContext) { + super(KeywordType.TYPE, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); this.schemaType = TypeFactory.getSchemaNodeType(schemaNode); if (this.schemaType == JsonType.UNION) { - this.unionTypeValidator = new UnionTypeValidator(schemaLocation, evaluationPath, schemaNode, parentSchema, validationContext); + this.unionTypeValidator = new UnionTypeValidator(schemaLocation, evaluationPath, schemaNode, parentSchema, schemaContext); } else { this.unionTypeValidator = null; } @@ -45,12 +48,12 @@ public JsonType getSchemaType() { } public boolean equalsToSchemaType(JsonNode node) { - return JsonNodeUtil.equalsToSchemaType(node, this.schemaType, this.parentSchema, this.validationContext); + return JsonNodeTypes.equalsToSchemaType(node, this.schemaType, this.parentSchema, this.schemaContext); } @Override - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) { - debug(logger, executionContext, node, rootNode, instanceLocation); + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation) { + if (this.schemaType == JsonType.UNION) { this.unionTypeValidator.validate(executionContext, node, rootNode, instanceLocation); @@ -58,10 +61,9 @@ public void validate(ExecutionContext executionContext, JsonNode node, JsonNode } if (!equalsToSchemaType(node)) { - JsonType nodeType = TypeFactory.getValueNodeType(node, this.validationContext.getConfig()); - executionContext.addError(message().instanceNode(node).instanceLocation(instanceLocation) + JsonType nodeType = TypeFactory.getValueNodeType(node, this.schemaContext.getSchemaRegistryConfig()); + executionContext.addError(error().instanceNode(node).instanceLocation(instanceLocation) .locale(executionContext.getExecutionConfig().getLocale()) - .failFast(executionContext.isFailFast()) .arguments(nodeType.toString(), this.schemaType.toString()).build()); } } diff --git a/src/main/java/com/networknt/schema/UnevaluatedItemsValidator.java b/src/main/java/com/networknt/schema/keyword/UnevaluatedItemsValidator.java similarity index 75% rename from src/main/java/com/networknt/schema/UnevaluatedItemsValidator.java rename to src/main/java/com/networknt/schema/keyword/UnevaluatedItemsValidator.java index fc08adc37..f596ad7f9 100644 --- a/src/main/java/com/networknt/schema/UnevaluatedItemsValidator.java +++ b/src/main/java/com/networknt/schema/keyword/UnevaluatedItemsValidator.java @@ -14,51 +14,49 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import com.fasterxml.jackson.databind.JsonNode; -import com.networknt.schema.SpecVersion.VersionFlag; -import com.networknt.schema.annotation.JsonNodeAnnotation; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.SchemaContext; +import com.networknt.schema.annotation.Annotation; +import com.networknt.schema.path.NodePath; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import static com.networknt.schema.SpecificationVersionRange.MIN_DRAFT_2020_12; import java.util.*; import java.util.function.Predicate; import java.util.stream.Collectors; -import static com.networknt.schema.VersionCode.MinV202012; - /** - * {@link JsonValidator} for unevaluatedItems. + * {@link KeywordValidator} for unevaluatedItems. */ -public class UnevaluatedItemsValidator extends BaseJsonValidator { - private static final Logger logger = LoggerFactory.getLogger(UnevaluatedItemsValidator.class); - - private final JsonSchema schema; +public class UnevaluatedItemsValidator extends BaseKeywordValidator { + private final Schema schema; private final boolean isMinV202012; - private static final VersionFlag DEFAULT_VERSION = VersionFlag.V201909; - public UnevaluatedItemsValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, - JsonSchema parentSchema, ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.UNEVALUATED_ITEMS, - validationContext); - isMinV202012 = MinV202012.getVersions().contains(validationContext.activeDialect().orElse(DEFAULT_VERSION)); + public UnevaluatedItemsValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, + Schema parentSchema, SchemaContext schemaContext) { + super(KeywordType.UNEVALUATED_ITEMS, schemaNode, schemaLocation, parentSchema, schemaContext, + evaluationPath); + isMinV202012 = MIN_DRAFT_2020_12.getVersions().contains(schemaContext.getDialect().getSpecificationVersion()); if (schemaNode.isObject() || schemaNode.isBoolean()) { - this.schema = validationContext.newSchema(schemaLocation, evaluationPath, schemaNode, parentSchema); + this.schema = schemaContext.newSchema(schemaLocation, evaluationPath, schemaNode, parentSchema); } else { throw new IllegalArgumentException("The value of 'unevaluatedItems' MUST be a valid JSON Schema."); } } @Override - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) { + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation) { if (!node.isArray()) { return; } - debug(logger, executionContext, node, rootNode, instanceLocation); + /* * Keywords renamed in 2020-12 * @@ -75,12 +73,12 @@ public void validate(ExecutionContext executionContext, JsonNode node, JsonNode boolean evaluated = false; // Get all the valid adjacent annotations - Predicate validEvaluationPathFilter = a -> executionContext.getResults().isValid(instanceLocation, a.getEvaluationPath()); + Predicate validEvaluationPathFilter = a -> executionContext.getInstanceResults().isValid(instanceLocation, a.getEvaluationPath()); - Predicate adjacentEvaluationPathFilter = a -> a.getEvaluationPath() + Predicate adjacentEvaluationPathFilter = a -> a.getEvaluationPath() .startsWith(this.evaluationPath.getParent()); - List instanceLocationAnnotations = executionContext.getAnnotations().asMap() + List instanceLocationAnnotations = executionContext.getAnnotations().asMap() .getOrDefault(instanceLocation, Collections.emptyList()); // If schema is "unevaluatedItems: true" this is valid @@ -93,7 +91,7 @@ public void validate(ExecutionContext executionContext, JsonNode node, JsonNode } } else { // Get all the "items" for the instanceLocation - List items = instanceLocationAnnotations.stream() + List items = instanceLocationAnnotations.stream() .filter(a -> itemsKeyword.equals(a.getKeyword())).filter(adjacentEvaluationPathFilter) .filter(validEvaluationPathFilter).collect(Collectors.toList()); if (items.isEmpty()) { @@ -104,7 +102,7 @@ public void validate(ExecutionContext executionContext, JsonNode node, JsonNode // same instance location are combined by setting the combined result to true if // any of the values are true, and otherwise retaining the largest numerical // value. - for (JsonNodeAnnotation annotation : items) { + for (Annotation annotation : items) { if (annotation.getValue() instanceof Number) { Number value = annotation.getValue(); int existing = value.intValue(); @@ -125,10 +123,10 @@ public void validate(ExecutionContext executionContext, JsonNode node, JsonNode // from any subschema applied to the same instance location produces an // annotation value of true, then the combined result from these keywords is // also true. - List additionalItems = instanceLocationAnnotations.stream() + List additionalItems = instanceLocationAnnotations.stream() .filter(a -> additionalItemsKeyword.equals(a.getKeyword())).filter(adjacentEvaluationPathFilter) .filter(validEvaluationPathFilter).collect(Collectors.toList()); - for (JsonNodeAnnotation annotation : additionalItems) { + for (Annotation annotation : additionalItems) { if (annotation.getValue() instanceof Boolean && Boolean.TRUE.equals(annotation.getValue())) { // The annotation "additionalItems: true" valid = true; @@ -138,10 +136,10 @@ public void validate(ExecutionContext executionContext, JsonNode node, JsonNode if (!valid) { // Unevaluated // Check if there are any "unevaluatedItems" annotations - List unevaluatedItems = instanceLocationAnnotations.stream() + List unevaluatedItems = instanceLocationAnnotations.stream() .filter(a -> "unevaluatedItems".equals(a.getKeyword())).filter(adjacentEvaluationPathFilter) .filter(validEvaluationPathFilter).collect(Collectors.toList()); - for (JsonNodeAnnotation annotation : unevaluatedItems) { + for (Annotation annotation : unevaluatedItems) { if (annotation.getValue() instanceof Boolean && Boolean.TRUE.equals(annotation.getValue())) { // The annotation "unevaluatedItems: true" valid = true; @@ -152,13 +150,13 @@ public void validate(ExecutionContext executionContext, JsonNode node, JsonNode if (!valid) { int currentErrors = executionContext.getErrors().size(); // Get all the "contains" for the instanceLocation - List contains = instanceLocationAnnotations.stream() + List contains = instanceLocationAnnotations.stream() .filter(a -> "contains".equals(a.getKeyword())).filter(adjacentEvaluationPathFilter) .filter(validEvaluationPathFilter).collect(Collectors.toList()); Set containsEvaluated = new HashSet<>(); boolean containsEvaluatedAll = false; - for (JsonNodeAnnotation a : contains) { + for (Annotation a : contains) { if (a.getValue() instanceof List) { List values = a.getValue(); containsEvaluated.addAll(values); @@ -174,9 +172,9 @@ public void validate(ExecutionContext executionContext, JsonNode node, JsonNode if (!containsEvaluated.contains(x)) { if (this.schemaNode.isBoolean() && this.schemaNode.booleanValue() == false) { // All fails as "unevaluatedItems: false" - executionContext.addError(message().instanceNode(node).instanceLocation(instanceLocation).arguments(x) + executionContext.addError(error().instanceNode(node).instanceLocation(instanceLocation).arguments(x) .locale(executionContext.getExecutionConfig().getLocale()) - .failFast(executionContext.isFailFast()).build()); + .build()); } else { // Schema errors will be reported as is this.schema.validate(executionContext, node.get(x), node, instanceLocation.append(x)); @@ -197,7 +195,7 @@ public void validate(ExecutionContext executionContext, JsonNode node, JsonNode // also true. if (evaluated) { executionContext.getAnnotations() - .put(JsonNodeAnnotation.builder().instanceLocation(instanceLocation) + .put(Annotation.builder().instanceLocation(instanceLocation) .evaluationPath(this.evaluationPath).schemaLocation(this.schemaLocation) .keyword("unevaluatedItems").value(true).build()); } diff --git a/src/main/java/com/networknt/schema/UnevaluatedPropertiesValidator.java b/src/main/java/com/networknt/schema/keyword/UnevaluatedPropertiesValidator.java similarity index 66% rename from src/main/java/com/networknt/schema/UnevaluatedPropertiesValidator.java rename to src/main/java/com/networknt/schema/keyword/UnevaluatedPropertiesValidator.java index db09c16e7..fbdfa4dee 100644 --- a/src/main/java/com/networknt/schema/UnevaluatedPropertiesValidator.java +++ b/src/main/java/com/networknt/schema/keyword/UnevaluatedPropertiesValidator.java @@ -14,59 +14,63 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; -import com.fasterxml.jackson.databind.JsonNode; -import com.networknt.schema.annotation.JsonNodeAnnotation; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.*; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; import java.util.function.Predicate; import java.util.stream.Collectors; +import com.fasterxml.jackson.databind.JsonNode; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.SchemaContext; +import com.networknt.schema.annotation.Annotation; +import com.networknt.schema.path.NodePath; + /** - * {@link JsonValidator} for unevaluatedProperties. + * {@link KeywordValidator} for unevaluatedProperties. */ -public class UnevaluatedPropertiesValidator extends BaseJsonValidator { - private static final Logger logger = LoggerFactory.getLogger(UnevaluatedPropertiesValidator.class); - - private final JsonSchema schema; +public class UnevaluatedPropertiesValidator extends BaseKeywordValidator { + private final Schema schema; - public UnevaluatedPropertiesValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.UNEVALUATED_PROPERTIES, validationContext); + public UnevaluatedPropertiesValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, Schema parentSchema, SchemaContext schemaContext) { + super(KeywordType.UNEVALUATED_PROPERTIES, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); if (schemaNode.isObject() || schemaNode.isBoolean()) { - this.schema = validationContext.newSchema(schemaLocation, evaluationPath, schemaNode, parentSchema); + this.schema = schemaContext.newSchema(schemaLocation, evaluationPath, schemaNode, parentSchema); } else { throw new IllegalArgumentException("The value of 'unevaluatedProperties' MUST be a valid JSON Schema."); } } @Override - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) { + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation) { if (!node.isObject()) { return; } - debug(logger, executionContext, node, rootNode, instanceLocation); + // Get all the valid adjacent annotations - Predicate validEvaluationPathFilter = a -> executionContext.getResults().isValid(instanceLocation, a.getEvaluationPath()); + Predicate validEvaluationPathFilter = a -> executionContext.getInstanceResults().isValid(instanceLocation, a.getEvaluationPath()); - Predicate adjacentEvaluationPathFilter = a -> a.getEvaluationPath() + Predicate adjacentEvaluationPathFilter = a -> a.getEvaluationPath() .startsWith(this.evaluationPath.getParent()); - List instanceLocationAnnotations = executionContext.getAnnotations().asMap() + List instanceLocationAnnotations = executionContext.getAnnotations().asMap() .getOrDefault(instanceLocation, Collections.emptyList()); Set evaluatedProperties = new LinkedHashSet<>(); // The properties that unevaluatedProperties schema Set existingEvaluatedProperties = new LinkedHashSet<>(); // Get all the "properties" for the instanceLocation - List properties = instanceLocationAnnotations.stream() + List properties = instanceLocationAnnotations.stream() .filter(a -> "properties".equals(a.getKeyword())).filter(adjacentEvaluationPathFilter) .filter(validEvaluationPathFilter).collect(Collectors.toList()); - for (JsonNodeAnnotation annotation : properties) { + for (Annotation annotation : properties) { if (annotation.getValue() instanceof Set) { Set p = annotation.getValue(); existingEvaluatedProperties.addAll(p); @@ -74,10 +78,10 @@ public void validate(ExecutionContext executionContext, JsonNode node, JsonNode } // Get all the "patternProperties" for the instanceLocation - List patternProperties = instanceLocationAnnotations.stream() + List patternProperties = instanceLocationAnnotations.stream() .filter(a -> "patternProperties".equals(a.getKeyword())).filter(adjacentEvaluationPathFilter) .filter(validEvaluationPathFilter).collect(Collectors.toList()); - for (JsonNodeAnnotation annotation : patternProperties) { + for (Annotation annotation : patternProperties) { if (annotation.getValue() instanceof Set) { Set p = annotation.getValue(); existingEvaluatedProperties.addAll(p); @@ -85,10 +89,10 @@ public void validate(ExecutionContext executionContext, JsonNode node, JsonNode } // Get all the "patternProperties" for the instanceLocation - List additionalProperties = instanceLocationAnnotations.stream() + List additionalProperties = instanceLocationAnnotations.stream() .filter(a -> "additionalProperties".equals(a.getKeyword())).filter(adjacentEvaluationPathFilter) .filter(validEvaluationPathFilter).collect(Collectors.toList()); - for (JsonNodeAnnotation annotation : additionalProperties) { + for (Annotation annotation : additionalProperties) { if (annotation.getValue() instanceof Set) { Set p = annotation.getValue(); existingEvaluatedProperties.addAll(p); @@ -96,10 +100,10 @@ public void validate(ExecutionContext executionContext, JsonNode node, JsonNode } // Get all the "unevaluatedProperties" for the instanceLocation - List unevaluatedProperties = instanceLocationAnnotations.stream() + List unevaluatedProperties = instanceLocationAnnotations.stream() .filter(a -> "unevaluatedProperties".equals(a.getKeyword())).filter(adjacentEvaluationPathFilter) .filter(validEvaluationPathFilter).collect(Collectors.toList()); - for (JsonNodeAnnotation annotation : unevaluatedProperties) { + for (Annotation annotation : unevaluatedProperties) { if (annotation.getValue() instanceof Set) { Set p = annotation.getValue(); existingEvaluatedProperties.addAll(p); @@ -116,9 +120,9 @@ public void validate(ExecutionContext executionContext, JsonNode node, JsonNode evaluatedProperties.add(fieldName); if (this.schemaNode.isBoolean() && this.schemaNode.booleanValue() == false) { // All fails as "unevaluatedProperties: false" - executionContext.addError(message().instanceNode(node).instanceLocation(instanceLocation).property(fieldName) + executionContext.addError(error().instanceNode(node).instanceLocation(instanceLocation).property(fieldName) .arguments(fieldName).locale(executionContext.getExecutionConfig().getLocale()) - .failFast(executionContext.isFailFast()).build()); + .build()); } else { // Schema errors will be reported as is this.schema.validate(executionContext, node.get(fieldName), node, @@ -130,7 +134,7 @@ public void validate(ExecutionContext executionContext, JsonNode node, JsonNode executionContext.setFailFast(failFast); // restore flag } executionContext.getAnnotations() - .put(JsonNodeAnnotation.builder().instanceLocation(instanceLocation).evaluationPath(this.evaluationPath) + .put(Annotation.builder().instanceLocation(instanceLocation).evaluationPath(this.evaluationPath) .schemaLocation(this.schemaLocation).keyword(getKeyword()).value(evaluatedProperties).build()); return; diff --git a/src/main/java/com/networknt/schema/UnionTypeValidator.java b/src/main/java/com/networknt/schema/keyword/UnionTypeValidator.java similarity index 53% rename from src/main/java/com/networknt/schema/UnionTypeValidator.java rename to src/main/java/com/networknt/schema/keyword/UnionTypeValidator.java index 2a271b258..c42b3018b 100644 --- a/src/main/java/com/networknt/schema/UnionTypeValidator.java +++ b/src/main/java/com/networknt/schema/keyword/UnionTypeValidator.java @@ -14,33 +14,39 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import com.fasterxml.jackson.databind.JsonNode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.networknt.schema.Error; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaException; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.SchemaContext; +import com.networknt.schema.Validator; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.utils.JsonType; +import com.networknt.schema.utils.TypeFactory; import java.util.ArrayList; import java.util.List; /** - * {@link JsonValidator} for type union. + * {@link KeywordValidator} for type union. */ -public class UnionTypeValidator extends BaseJsonValidator implements JsonValidator { - private static final Logger logger = LoggerFactory.getLogger(UnionTypeValidator.class); - - private final List schemas; +public class UnionTypeValidator extends BaseKeywordValidator implements KeywordValidator { + private final List schemas; private final String error; - public UnionTypeValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.TYPE, validationContext); + public UnionTypeValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, Schema parentSchema, SchemaContext schemaContext) { + super(KeywordType.TYPE, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); StringBuilder errorBuilder = new StringBuilder(); String sep = ""; errorBuilder.append('['); if (!schemaNode.isArray()) { - throw new JsonSchemaException("Expected array for type property on Union Type Definition."); + throw new SchemaException("Expected array for type property on Union Type Definition."); } int i = 0; @@ -51,11 +57,11 @@ public UnionTypeValidator(SchemaLocation schemaLocation, JsonNodePath evaluation sep = ", "; if (n.isObject()) { - schemas.add(validationContext.newSchema(schemaLocation.append(ValidatorTypeCode.TYPE.getValue()), - evaluationPath.append(ValidatorTypeCode.TRUE.getValue()), n, parentSchema)); + schemas.add(schemaContext.newSchema(schemaLocation.append(KeywordType.TYPE.getValue()), + evaluationPath.append(KeywordType.TRUE.getValue()), n, parentSchema)); } else { schemas.add(new TypeValidator(schemaLocation.append(i), evaluationPath.append(i), n, parentSchema, - validationContext)); + schemaContext)); } i++; } @@ -65,21 +71,21 @@ public UnionTypeValidator(SchemaLocation schemaLocation, JsonNodePath evaluation error = errorBuilder.toString(); } - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) { - debug(logger, executionContext, node, rootNode, instanceLocation); + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation) { + - JsonType nodeType = TypeFactory.getValueNodeType(node, validationContext.getConfig()); + JsonType nodeType = TypeFactory.getValueNodeType(node, schemaContext.getSchemaRegistryConfig()); boolean valid = false; // Save flag as nested schema evaluation shouldn't trigger fail fast boolean failFast = executionContext.isFailFast(); - List existingErrors = executionContext.getErrors(); + List existingErrors = executionContext.getErrors(); try { - List test = new ArrayList<>(); + List test = new ArrayList<>(); executionContext.setFailFast(false); executionContext.setErrors(test); - for (JsonSchemaValidator schema : schemas) { + for (Validator schema : schemas) { schema.validate(executionContext, node, rootNode, instanceLocation); if (test.isEmpty()) { valid = true; @@ -95,21 +101,21 @@ public void validate(ExecutionContext executionContext, JsonNode node, JsonNode } if (!valid) { - executionContext.addError(message().instanceNode(node).instanceLocation(instanceLocation) - .type("type") + executionContext.addError(error().instanceNode(node).instanceLocation(instanceLocation) + .keyword("type") .locale(executionContext.getExecutionConfig().getLocale()) - .failFast(executionContext.isFailFast()).arguments(nodeType.toString(), error) + .arguments(nodeType.toString(), error) .build()); } } @Override - public void preloadJsonSchema() { - for (final JsonSchemaValidator validator : schemas) { - if (validator instanceof JsonValidator) { - ((JsonValidator) validator).preloadJsonSchema(); - } else if (validator instanceof JsonSchema) { - ((JsonSchema) validator).initializeValidators(); + public void preloadSchema() { + for (final Validator validator : schemas) { + if (validator instanceof KeywordValidator) { + ((KeywordValidator) validator).preloadSchema(); + } else if (validator instanceof Schema) { + ((Schema) validator).initializeValidators(); } } } diff --git a/src/main/java/com/networknt/schema/UniqueItemsValidator.java b/src/main/java/com/networknt/schema/keyword/UniqueItemsValidator.java similarity index 55% rename from src/main/java/com/networknt/schema/UniqueItemsValidator.java rename to src/main/java/com/networknt/schema/keyword/UniqueItemsValidator.java index 37486e4db..5ee628164 100644 --- a/src/main/java/com/networknt/schema/UniqueItemsValidator.java +++ b/src/main/java/com/networknt/schema/keyword/UniqueItemsValidator.java @@ -14,25 +14,26 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import com.fasterxml.jackson.databind.JsonNode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.SchemaContext; import java.util.HashSet; import java.util.Set; /** - * {@link JsonValidator} for uniqueItems. + * {@link KeywordValidator} for uniqueItems. */ -public class UniqueItemsValidator extends BaseJsonValidator implements JsonValidator { - private static final Logger logger = LoggerFactory.getLogger(UniqueItemsValidator.class); - +public class UniqueItemsValidator extends BaseKeywordValidator implements KeywordValidator { private final boolean unique; - public UniqueItemsValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ValidatorTypeCode.UNIQUE_ITEMS, validationContext); + public UniqueItemsValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, Schema parentSchema, SchemaContext schemaContext) { + super(KeywordType.UNIQUE_ITEMS, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); if (schemaNode.isBoolean()) { unique = schemaNode.booleanValue(); } else { @@ -40,16 +41,16 @@ public UniqueItemsValidator(SchemaLocation schemaLocation, JsonNodePath evaluati } } - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) { - debug(logger, executionContext, node, rootNode, instanceLocation); + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation) { + if (unique) { Set set = new HashSet<>(); for (JsonNode n : node) { if (!set.add(n)) { - executionContext.addError(message().instanceNode(node).instanceLocation(instanceLocation) + executionContext.addError(error().instanceNode(node).instanceLocation(instanceLocation) .locale(executionContext.getExecutionConfig().getLocale()) - .failFast(executionContext.isFailFast()).build()); + .build()); } } } diff --git a/src/main/java/com/networknt/schema/UnknownKeywordFactory.java b/src/main/java/com/networknt/schema/keyword/UnknownKeywordFactory.java similarity index 89% rename from src/main/java/com/networknt/schema/UnknownKeywordFactory.java rename to src/main/java/com/networknt/schema/keyword/UnknownKeywordFactory.java index 688330d18..5df3d89b3 100644 --- a/src/main/java/com/networknt/schema/UnknownKeywordFactory.java +++ b/src/main/java/com/networknt/schema/keyword/UnknownKeywordFactory.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -21,6 +21,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.networknt.schema.SchemaContext; + /** * Unknown keyword factory. *

@@ -32,7 +34,7 @@ public class UnknownKeywordFactory implements KeywordFactory { private final Map keywords = new ConcurrentHashMap<>(); @Override - public Keyword getKeyword(String value, ValidationContext validationContext) { + public Keyword getKeyword(String value, SchemaContext schemaContext) { return this.keywords.computeIfAbsent(value, keyword -> { logger.warn( "Unknown keyword {} - you should define your own Meta Schema. If the keyword is irrelevant for validation, just use a NonValidationKeyword or if it should generate annotations AnnotationKeyword", diff --git a/src/main/java/com/networknt/schema/keyword/WriteOnlyValidator.java b/src/main/java/com/networknt/schema/keyword/WriteOnlyValidator.java new file mode 100644 index 000000000..e7bc5db9c --- /dev/null +++ b/src/main/java/com/networknt/schema/keyword/WriteOnlyValidator.java @@ -0,0 +1,34 @@ +package com.networknt.schema.keyword; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.databind.JsonNode; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaLocation; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.SchemaContext; + +/** + * {@link KeywordValidator} for writeOnly. + */ +public class WriteOnlyValidator extends BaseKeywordValidator { + private static final Logger logger = LoggerFactory.getLogger(WriteOnlyValidator.class); + + public WriteOnlyValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, Schema parentSchema, SchemaContext schemaContext) { + super(KeywordType.WRITE_ONLY, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); + logger.debug("Loaded WriteOnlyValidator for property {} as {}", parentSchema, "write mode"); + } + + @Override + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation) { + + if (Boolean.TRUE.equals(executionContext.getExecutionConfig().getWriteOnly())) { + executionContext.addError(error().instanceNode(node).instanceLocation(instanceLocation) + .locale(executionContext.getExecutionConfig().getLocale()) + .build()); + } + } + +} diff --git a/src/main/java/com/networknt/schema/oas/OpenApi30.java b/src/main/java/com/networknt/schema/oas/OpenApi30.java deleted file mode 100644 index 7c6e4e24f..000000000 --- a/src/main/java/com/networknt/schema/oas/OpenApi30.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.networknt.schema.oas; - -import java.util.Arrays; - -import com.networknt.schema.AnnotationKeyword; -import com.networknt.schema.Formats; -import com.networknt.schema.JsonMetaSchema; -import com.networknt.schema.NonValidationKeyword; -import com.networknt.schema.SchemaId; -import com.networknt.schema.SpecVersion; -import com.networknt.schema.ValidatorTypeCode; - -/** - * OpenAPI 3.0. - */ -public class OpenApi30 { - private static final String IRI = SchemaId.OPENAPI_3_0; - private static final String ID = "id"; - - private static class Holder { - private static final JsonMetaSchema INSTANCE; - static { - INSTANCE = JsonMetaSchema.builder(IRI) - .specification(SpecVersion.VersionFlag.V4) - .idKeyword(ID) - .formats(Formats.DEFAULT) - .keywords(Arrays.asList( - new AnnotationKeyword("title"), - ValidatorTypeCode.PATTERN, - ValidatorTypeCode.REQUIRED, - ValidatorTypeCode.ENUM, - ValidatorTypeCode.MINIMUM, - ValidatorTypeCode.MAXIMUM, - ValidatorTypeCode.MULTIPLE_OF, - ValidatorTypeCode.MIN_LENGTH, - ValidatorTypeCode.MAX_LENGTH, - ValidatorTypeCode.MIN_ITEMS, - ValidatorTypeCode.MAX_ITEMS, - ValidatorTypeCode.UNIQUE_ITEMS, - ValidatorTypeCode.MIN_PROPERTIES, - ValidatorTypeCode.MAX_PROPERTIES, - - ValidatorTypeCode.TYPE, - ValidatorTypeCode.FORMAT, - new AnnotationKeyword("description"), - ValidatorTypeCode.ITEMS, - ValidatorTypeCode.PROPERTIES, - ValidatorTypeCode.ADDITIONAL_PROPERTIES, - new AnnotationKeyword("default"), - ValidatorTypeCode.ALL_OF, - ValidatorTypeCode.ONE_OF, - ValidatorTypeCode.ANY_OF, - ValidatorTypeCode.NOT, - - new AnnotationKeyword("deprecated"), - ValidatorTypeCode.DISCRIMINATOR, - new AnnotationKeyword("example"), - new AnnotationKeyword("externalDocs"), - new NonValidationKeyword("nullable"), - ValidatorTypeCode.READ_ONLY, - ValidatorTypeCode.WRITE_ONLY, - new AnnotationKeyword("xml"), - - ValidatorTypeCode.REF - )) - .build(); - } - } - - public static JsonMetaSchema getInstance() { - return Holder.INSTANCE; - } -} diff --git a/src/main/java/com/networknt/schema/output/HierarchicalOutputUnitFormatter.java b/src/main/java/com/networknt/schema/output/HierarchicalOutputUnitFormatter.java index eea8d67d6..736d79882 100644 --- a/src/main/java/com/networknt/schema/output/HierarchicalOutputUnitFormatter.java +++ b/src/main/java/com/networknt/schema/output/HierarchicalOutputUnitFormatter.java @@ -27,30 +27,30 @@ import java.util.Set; import com.networknt.schema.ExecutionContext; -import com.networknt.schema.JsonNodePath; -import com.networknt.schema.JsonSchema; -import com.networknt.schema.ValidationContext; -import com.networknt.schema.ValidationMessage; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaContext; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.Error; /** * HierarchicalOutputUnitFormatter. */ public class HierarchicalOutputUnitFormatter { - public static OutputUnit format(OutputUnit root, OutputUnitData data, JsonNodePath rootPath) { + public static OutputUnit format(OutputUnit root, OutputUnitData data, NodePath rootPath) { Map valid = data.getValid(); Map> errors = data.getErrors(); Map> annotations = data.getAnnotations(); Map> droppedAnnotations = data.getDroppedAnnotations(); // Evaluation path to output unit - Map> index = new LinkedHashMap<>(); - Map r = new LinkedHashMap<>(); + Map> index = new LinkedHashMap<>(); + Map r = new LinkedHashMap<>(); r.put(rootPath, root); index.put(rootPath, r); // Get all the evaluation paths with data // This is a map of evaluation path to instance location - Map> keys = new LinkedHashMap<>(); + Map> keys = new LinkedHashMap<>(); errors.keySet().stream().forEach(k -> keys.computeIfAbsent(k.getEvaluationPath(), a -> new LinkedHashSet<>()) .add(k.getInstanceLocation())); annotations.keySet().stream().forEach(k -> keys @@ -108,19 +108,19 @@ public static OutputUnit format(OutputUnit root, OutputUnitData data, JsonNodePa return root; } - public static OutputUnit format(JsonSchema jsonSchema, List validationMessages, - ExecutionContext executionContext, ValidationContext validationContext, - Function assertionMapper) { + public static OutputUnit format(Schema jsonSchema, List errors, + ExecutionContext executionContext, SchemaContext schemaContext, + Function errorMapper) { OutputUnit root = new OutputUnit(); - root.setValid(validationMessages.isEmpty()); + root.setValid(errors.isEmpty()); - root.setInstanceLocation(validationContext.getConfig().getPathType().getRoot()); - root.setEvaluationPath(validationContext.getConfig().getPathType().getRoot()); + root.setInstanceLocation(schemaContext.getSchemaRegistryConfig().getPathType().getRoot()); + root.setEvaluationPath(schemaContext.getSchemaRegistryConfig().getPathType().getRoot()); root.setSchemaLocation(jsonSchema.getSchemaLocation().toString()); - OutputUnitData data = OutputUnitData.from(validationMessages, executionContext, assertionMapper); + OutputUnitData data = OutputUnitData.from(errors, executionContext, errorMapper); - return format(root, data, new JsonNodePath(validationContext.getConfig().getPathType())); + return format(root, data, new NodePath(schemaContext.getSchemaRegistryConfig().getPathType())); } /** @@ -132,14 +132,14 @@ public static OutputUnit format(JsonSchema jsonSchema, List v * @param keys that contain all the evaluation paths with instance data * @param root the root output unit */ - protected static void buildIndex(OutputUnitKey key, Map> index, - Map> keys, OutputUnit root) { + protected static void buildIndex(OutputUnitKey key, Map> index, + Map> keys, OutputUnit root) { if (index.containsKey(key.getEvaluationPath())) { return; } // Ensure the path is created - JsonNodePath path = key.getEvaluationPath(); - Deque stack = new ArrayDeque<>(); + NodePath path = key.getEvaluationPath(); + Deque stack = new ArrayDeque<>(); while (path != null && path.getElement(-1) != null) { stack.push(path); path = path.getParent(); @@ -147,10 +147,10 @@ protected static void buildIndex(OutputUnitKey key, Map result = index.get(current); + Map result = index.get(current); if (result != null) { - for (Entry entry : result.entrySet()) { + for (Entry entry : result.entrySet()) { if (key.getInstanceLocation().startsWith(entry.getKey())) { parent = entry.getValue(); break; diff --git a/src/main/java/com/networknt/schema/output/ListOutputUnitFormatter.java b/src/main/java/com/networknt/schema/output/ListOutputUnitFormatter.java index 44bb20260..e8fef126a 100644 --- a/src/main/java/com/networknt/schema/output/ListOutputUnitFormatter.java +++ b/src/main/java/com/networknt/schema/output/ListOutputUnitFormatter.java @@ -23,8 +23,8 @@ import java.util.function.Function; import com.networknt.schema.ExecutionContext; -import com.networknt.schema.ValidationContext; -import com.networknt.schema.ValidationMessage; +import com.networknt.schema.SchemaContext; +import com.networknt.schema.Error; /** * ListOutputUnitFormatter. @@ -90,10 +90,10 @@ public static OutputUnit format(OutputUnit root, OutputUnitData data) { return root; } - public static OutputUnit format(List validationMessages, ExecutionContext executionContext, - ValidationContext validationContext, Function assertionMapper) { + public static OutputUnit format(List errors, ExecutionContext executionContext, + SchemaContext schemaContext, Function errorMapper) { OutputUnit root = new OutputUnit(); - root.setValid(validationMessages.isEmpty()); - return format(root, OutputUnitData.from(validationMessages, executionContext, assertionMapper)); + root.setValid(errors.isEmpty()); + return format(root, OutputUnitData.from(errors, executionContext, errorMapper)); } } diff --git a/src/main/java/com/networknt/schema/output/OutputUnitData.java b/src/main/java/com/networknt/schema/output/OutputUnitData.java index 0f195f6e6..a2464e9cb 100644 --- a/src/main/java/com/networknt/schema/output/OutputUnitData.java +++ b/src/main/java/com/networknt/schema/output/OutputUnitData.java @@ -23,8 +23,8 @@ import com.networknt.schema.ExecutionContext; import com.networknt.schema.SchemaLocation; -import com.networknt.schema.ValidationMessage; -import com.networknt.schema.annotation.JsonNodeAnnotation; +import com.networknt.schema.Error; +import com.networknt.schema.annotation.Annotation; /** * Output Unit Data. @@ -51,29 +51,13 @@ public Map> getDroppedAnnotations() { return droppedAnnotations; } - public static String formatAssertion(ValidationMessage validationMessage) { - return formatMessage(validationMessage.getMessage()); - } - - public static String formatMessage(String message) { - int index = message.indexOf(':'); - if (index != -1) { - int length = message.length(); - while (index + 1 < length) { - if (message.charAt(index + 1) == ' ') { - index++; - } else { - break; - } - } - return message.substring(index + 1); - } - return message; + public static String formatError(Error error) { + return error.getMessage(); } @SuppressWarnings("unchecked") - public static OutputUnitData from(List validationMessages, ExecutionContext executionContext, - Function assertionMapper) { + public static OutputUnitData from(List validationErrors, ExecutionContext executionContext, + Function errorMapper) { OutputUnitData data = new OutputUnitData(); Map valid = data.valid; @@ -81,31 +65,31 @@ public static OutputUnitData from(List validationMessages, Ex Map> annotations = data.annotations; Map> droppedAnnotations = data.droppedAnnotations; - for (ValidationMessage assertion : validationMessages) { - SchemaLocation assertionSchemaLocation = new SchemaLocation(assertion.getSchemaLocation().getAbsoluteIri(), - assertion.getSchemaLocation().getFragment().getParent()); - OutputUnitKey key = new OutputUnitKey(assertion.getEvaluationPath().getParent(), - assertionSchemaLocation, assertion.getInstanceLocation()); + for (Error error : validationErrors) { + SchemaLocation assertionSchemaLocation = new SchemaLocation(error.getSchemaLocation().getAbsoluteIri(), + error.getSchemaLocation().getFragment().getParent()); + OutputUnitKey key = new OutputUnitKey(error.getEvaluationPath().getParent(), + assertionSchemaLocation, error.getInstanceLocation()); valid.put(key, false); Map errorMap = errors.computeIfAbsent(key, k -> new LinkedHashMap<>()); - Object value = errorMap.get(assertion.getType()); + Object value = errorMap.get(error.getKeyword()); if (value == null) { - errorMap.put(assertion.getType(), assertionMapper.apply(assertion)); + errorMap.put(error.getKeyword(), errorMapper.apply(error)); } else { // Existing error, make it into a list if (value instanceof List) { - ((List) value).add(assertionMapper.apply(assertion)); + ((List) value).add(errorMapper.apply(error)); } else { List values = new ArrayList<>(); values.add(value.toString()); - values.add(assertionMapper.apply(assertion)); - errorMap.put(assertion.getType(), values); + values.add(errorMapper.apply(error)); + errorMap.put(error.getKeyword(), values); } } } - for (List annotationsResult : executionContext.getAnnotations().asMap().values()) { - for (JsonNodeAnnotation annotation : annotationsResult) { + for (List annotationsResult : executionContext.getAnnotations().asMap().values()) { + for (Annotation annotation : annotationsResult) { // As some annotations are required for computation, filter those that are not // required for reporting if (executionContext.getExecutionConfig().getAnnotationCollectionFilter() @@ -116,7 +100,7 @@ public static OutputUnitData from(List validationMessages, Ex OutputUnitKey key = new OutputUnitKey(annotation.getEvaluationPath().getParent(), annotationSchemaLocation, annotation.getInstanceLocation()); - boolean validResult = executionContext.getResults().isValid(annotation.getInstanceLocation(), + boolean validResult = executionContext.getInstanceResults().isValid(annotation.getInstanceLocation(), annotation.getEvaluationPath()); valid.put(key, validResult); if (validResult) { diff --git a/src/main/java/com/networknt/schema/output/OutputUnitKey.java b/src/main/java/com/networknt/schema/output/OutputUnitKey.java index 760f75871..b5b23ebc5 100644 --- a/src/main/java/com/networknt/schema/output/OutputUnitKey.java +++ b/src/main/java/com/networknt/schema/output/OutputUnitKey.java @@ -20,8 +20,8 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; -import com.networknt.schema.JsonNodePath; import com.networknt.schema.SchemaLocation; +import com.networknt.schema.path.NodePath; import com.networknt.schema.serialization.JsonMapperFactory; /** @@ -29,20 +29,20 @@ */ public class OutputUnitKey { @JsonSerialize(using = ToStringSerializer.class) - final JsonNodePath evaluationPath; + final NodePath evaluationPath; @JsonSerialize(using = ToStringSerializer.class) final SchemaLocation schemaLocation; @JsonSerialize(using = ToStringSerializer.class) - final JsonNodePath instanceLocation; + final NodePath instanceLocation; - public OutputUnitKey(JsonNodePath evaluationPath, SchemaLocation schemaLocation, JsonNodePath instanceLocation) { + public OutputUnitKey(NodePath evaluationPath, SchemaLocation schemaLocation, NodePath instanceLocation) { super(); this.evaluationPath = evaluationPath; this.schemaLocation = schemaLocation; this.instanceLocation = instanceLocation; } - public JsonNodePath getEvaluationPath() { + public NodePath getEvaluationPath() { return evaluationPath; } @@ -50,7 +50,7 @@ public SchemaLocation getSchemaLocation() { return schemaLocation; } - public JsonNodePath getInstanceLocation() { + public NodePath getInstanceLocation() { return instanceLocation; } diff --git a/src/main/java/com/networknt/schema/JsonNodePath.java b/src/main/java/com/networknt/schema/path/NodePath.java similarity index 73% rename from src/main/java/com/networknt/schema/JsonNodePath.java rename to src/main/java/com/networknt/schema/path/NodePath.java index a0ca579da..8e4cd118d 100644 --- a/src/main/java/com/networknt/schema/JsonNodePath.java +++ b/src/main/java/com/networknt/schema/path/NodePath.java @@ -13,16 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.path; +import java.util.ArrayDeque; import java.util.Objects; /** * Represents a path to a JSON node. */ -public class JsonNodePath implements Comparable { +public class NodePath implements Comparable { private final PathType type; - private final JsonNodePath parent; + private final NodePath parent; private final String pathSegment; private final int pathSegmentIndex; @@ -30,21 +31,21 @@ public class JsonNodePath implements Comparable { private volatile String value = null; // computed lazily private int hash = 0; // computed lazily - public JsonNodePath(PathType type) { + public NodePath(PathType type) { this.type = type; this.parent = null; this.pathSegment = null; this.pathSegmentIndex = -1; } - private JsonNodePath(JsonNodePath parent, String pathSegment) { + private NodePath(NodePath parent, String pathSegment) { this.parent = parent; this.type = parent.type; this.pathSegment = pathSegment; this.pathSegmentIndex = -1; } - private JsonNodePath(JsonNodePath parent, int pathSegmentIndex) { + private NodePath(NodePath parent, int pathSegmentIndex) { this.parent = parent; this.type = parent.type; this.pathSegment = null; @@ -56,7 +57,7 @@ private JsonNodePath(JsonNodePath parent, int pathSegmentIndex) { * * @return the parent */ - public JsonNodePath getParent() { + public NodePath getParent() { return this.parent; } @@ -66,8 +67,8 @@ public JsonNodePath getParent() { * @param token the child token * @return the path */ - public JsonNodePath append(String token) { - return new JsonNodePath(this, token); + public NodePath append(String token) { + return new NodePath(this, token); } /** @@ -76,8 +77,8 @@ public JsonNodePath append(String token) { * @param index the index * @return the path */ - public JsonNodePath append(int index) { - return new JsonNodePath(this, index); + public NodePath append(int index) { + return new NodePath(this, index); } /** @@ -133,7 +134,7 @@ public Object getElement(int index) { if (count < 0) { throw new IllegalArgumentException(""); } - JsonNodePath current = this; + NodePath current = this; for (int x = 0; x < count; x++) { current = current.parent; } @@ -157,7 +158,7 @@ public int getNameCount() { * @param other the other path * @return true if the path starts with the other path */ - public boolean startsWith(JsonNodePath other) { + public boolean startsWith(NodePath other) { int count = getNameCount(); int otherCount = other.getNameCount(); @@ -166,7 +167,7 @@ public boolean startsWith(JsonNodePath other) { } else if (otherCount == count) { return this.equals(other); } else { - JsonNodePath compare = this; + NodePath compare = this; int x = count - otherCount; while (x > 0) { compare = compare.getParent(); @@ -189,7 +190,7 @@ public boolean contains(String segment) { if (result) { return true; } - JsonNodePath path = this.getParent(); + NodePath path = this.getParent(); while (path != null) { if (segment.equals(path.pathSegment)) { return true; @@ -202,14 +203,40 @@ public boolean contains(String segment) { @Override public String toString() { if (this.value == null) { - String parentValue = this.parent == null ? type.getRoot() : this.parent.toString(); + if (pathSegmentIndex == -1 && this.pathSegment == null) { + this.value = type.getRoot(); + return this.value; + } + + ArrayDeque pathSegments = new ArrayDeque(); if (pathSegmentIndex != -1) { - this.value = this.type.append(parentValue, pathSegmentIndex); - } else if (pathSegment != null) { - this.value = this.type.append(parentValue, pathSegment); - } else { - this.value = parentValue; + pathSegments.push(this.pathSegmentIndex); + } else if (this.pathSegment != null) { + pathSegments.push(this.pathSegment); + } + NodePath parent = getParent(); + while (parent != null) { + if (parent.pathSegmentIndex != -1) { + pathSegments.push(parent.pathSegmentIndex); + } else if (parent.pathSegment != null) { + pathSegments.push(parent.pathSegment); + } + parent = parent.getParent(); + } + + StringBuilder builder = new StringBuilder(); + String root = type.getRoot(); + if (root != null) { + builder.append(root); + } + for (Object pathSegment : pathSegments) { + if (pathSegment instanceof Number) { + type.append(builder, ((Number) pathSegment).intValue()); + } else { + type.append(builder, pathSegment.toString()); + } } + this.value = builder.toString(); } return this.value; } @@ -232,13 +259,13 @@ public boolean equals(Object obj) { return false; if (getClass() != obj.getClass()) return false; - JsonNodePath other = (JsonNodePath) obj; + NodePath other = (NodePath) obj; return Objects.equals(pathSegment, other.pathSegment) && pathSegmentIndex == other.pathSegmentIndex && type == other.type && Objects.equals(parent, other.parent); } @Override - public int compareTo(JsonNodePath other) { + public int compareTo(NodePath other) { if (this.parent != null && other.parent == null) { return 1; } else if (this.parent == null && other.parent != null) { diff --git a/src/main/java/com/networknt/schema/PathType.java b/src/main/java/com/networknt/schema/path/PathType.java similarity index 84% rename from src/main/java/com/networknt/schema/PathType.java rename to src/main/java/com/networknt/schema/path/PathType.java index 869ee4f21..f1c637f48 100644 --- a/src/main/java/com/networknt/schema/PathType.java +++ b/src/main/java/com/networknt/schema/path/PathType.java @@ -1,6 +1,6 @@ -package com.networknt.schema; +package com.networknt.schema.path; -import java.util.function.BiFunction; +import java.util.function.BiConsumer; import java.util.function.IntPredicate; /** @@ -11,18 +11,19 @@ public enum PathType { /** * The legacy approach, loosely based on JSONPath (but not guaranteed to give valid JSONPath expressions). */ - LEGACY("$", (currentPath, token) -> currentPath + "." + replaceCommonSpecialCharactersIfPresent(token), - (currentPath, index) -> currentPath + "[" + index + "]"), + LEGACY("$", (currentPath, token) -> { + currentPath.append(".").append(replaceCommonSpecialCharactersIfPresent(token)); + }, (currentPath, index) -> { + currentPath.append("[").append(index).append("]"); + }), /** * Paths as JSONPath expressions. */ JSON_PATH("$", (currentPath, token) -> { - if (token.isEmpty()) { throw new IllegalArgumentException("A JSONPath selector cannot be empty"); } - /* * Accepted characters for shorthand paths: * - 'a' through 'z' @@ -32,16 +33,18 @@ public enum PathType { * - any non-ASCII Unicode character */ if (JSONPath.isShorthand(token)) { - return currentPath + "." + token; + currentPath.append(".").append(token); + return; } // Replace single quote (used to wrap property names when not shorthand form). if (token.indexOf('\'') != -1) token = token.replace("'", "\\'"); // Replace other special characters. token = replaceCommonSpecialCharactersIfPresent(token); - - return currentPath + "['" + token + "']"; - }, (currentPath, index) -> currentPath + "[" + index + "]"), + currentPath.append("['").append(token).append("']"); + }, (currentPath, index) -> { + currentPath.append("[").append(index).append("]"); + }), /** * Paths as JSONPointer expressions. @@ -54,21 +57,31 @@ public enum PathType { if (token.indexOf('/') != -1) token = token.replace("/", "~1"); // Replace other special characters. token = replaceCommonSpecialCharactersIfPresent(token); - return currentPath + "/" + token; - }, (currentPath, index) -> currentPath + "/" + index), + currentPath.append("/").append(token); + }, (currentPath, index) -> { + currentPath.append("/").append(index); + }), /** * Paths as a URI reference. */ - URI_REFERENCE("", (currentPath, token) -> !currentPath.isEmpty() ? currentPath + "/" + token : token, (currentPath, index) -> currentPath + "/" + index); + URI_REFERENCE("", (currentPath, token) -> { + if (!(currentPath.length() == 0)) { + currentPath.append("/").append(token); + } else { + currentPath.append(token); + } + }, (currentPath, index) -> { + currentPath.append("/").append(index); + }); /** * The default path generation approach to use. */ public static final PathType DEFAULT = LEGACY; private final String rootToken; - private final BiFunction appendTokenFn; - private final BiFunction appendIndexFn; + private final BiConsumer appendTokenFn; + private final BiConsumer appendIndexFn; /** * Constructor. @@ -77,7 +90,7 @@ public enum PathType { * @param appendTokenFn A function used to define the path fragment used to append a token (e.g. property) to an existing path. * @param appendIndexFn A function used to append an index (for arrays) to an existing path. */ - PathType(String rootToken, BiFunction appendTokenFn, BiFunction appendIndexFn) { + PathType(String rootToken, BiConsumer appendTokenFn, BiConsumer appendIndexFn) { this.rootToken = rootToken; this.appendTokenFn = appendTokenFn; this.appendIndexFn = appendIndexFn; @@ -103,10 +116,9 @@ private static String replaceCommonSpecialCharactersIfPresent(String token) { * * @param currentPath The path to append to. * @param child The child token. - * @return The resulting complete path. */ - public String append(String currentPath, String child) { - return this.appendTokenFn.apply(currentPath, child); + public void append(StringBuilder currentPath, String child) { + this.appendTokenFn.accept(currentPath, child); } /** @@ -114,10 +126,9 @@ public String append(String currentPath, String child) { * * @param currentPath The path to append to. * @param index The index to append. - * @return The resulting complete path. */ - public String append(String currentPath, int index) { - return this.appendIndexFn.apply(currentPath, index); + public void append(StringBuilder currentPath, int index) { + this.appendIndexFn.accept(currentPath, index); } /** diff --git a/src/main/java/com/networknt/schema/regex/AllowRegularExpressionFactory.java b/src/main/java/com/networknt/schema/regex/AllowRegularExpressionFactory.java index b4bc84e7e..333273e33 100644 --- a/src/main/java/com/networknt/schema/regex/AllowRegularExpressionFactory.java +++ b/src/main/java/com/networknt/schema/regex/AllowRegularExpressionFactory.java @@ -18,7 +18,7 @@ import java.util.function.Predicate; import com.networknt.schema.InvalidSchemaException; -import com.networknt.schema.ValidationMessage; +import com.networknt.schema.Error; /** * {@link RegularExpressionFactory} that allows regular expressions to be used. @@ -38,7 +38,7 @@ public RegularExpression getRegularExpression(String regex) { // Allowed to delegate return this.delegate.getRegularExpression(regex); } - throw new InvalidSchemaException(ValidationMessage.builder() - .message("Regular expression ''{1}'' is not allowed to be used.").arguments(regex).build()); + throw new InvalidSchemaException(Error.builder() + .message("Regular expression ''{0}'' is not allowed to be used.").arguments(regex).build()); } } diff --git a/src/main/java/com/networknt/schema/regex/RegularExpression.java b/src/main/java/com/networknt/schema/regex/RegularExpression.java index 8a3140bed..e3cb6950e 100644 --- a/src/main/java/com/networknt/schema/regex/RegularExpression.java +++ b/src/main/java/com/networknt/schema/regex/RegularExpression.java @@ -1,6 +1,6 @@ package com.networknt.schema.regex; -import com.networknt.schema.ValidationContext; +import com.networknt.schema.SchemaContext; /** * Regular expression. @@ -9,9 +9,9 @@ public interface RegularExpression { boolean matches(String value); - static RegularExpression compile(String regex, ValidationContext validationContext) { + static RegularExpression compile(String regex, SchemaContext schemaContext) { if (null == regex) return s -> true; - return validationContext.getConfig().getRegularExpressionFactory().getRegularExpression(regex); + return schemaContext.getSchemaRegistryConfig().getRegularExpressionFactory().getRegularExpression(regex); } } \ No newline at end of file diff --git a/src/main/java/com/networknt/schema/resource/AllowSchemaLoader.java b/src/main/java/com/networknt/schema/resource/AllowSchemaLoader.java deleted file mode 100644 index a996585a7..000000000 --- a/src/main/java/com/networknt/schema/resource/AllowSchemaLoader.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.networknt.schema.resource; - -import java.util.function.Predicate; - -import com.networknt.schema.AbsoluteIri; -import com.networknt.schema.InvalidSchemaException; -import com.networknt.schema.ValidationMessage; - -/** - * {@link SchemaLoader} that allows loading external resources. - */ -public class AllowSchemaLoader implements SchemaLoader { - private final Predicate allowed; - - /** - * Constructor. - * - * @param allowed the predicate to determine which external resource is allowed - * to be loaded - */ - public AllowSchemaLoader(Predicate allowed) { - this.allowed = allowed; - } - - @Override - public InputStreamSource getSchema(AbsoluteIri absoluteIri) { - if (this.allowed.test(absoluteIri)) { - // Allow to delegate to the next schema loader - return null; - } - throw new InvalidSchemaException(ValidationMessage.builder() - .message("Schema from ''{1}'' is not allowed to be loaded.").arguments(absoluteIri).build()); - } -} diff --git a/src/main/java/com/networknt/schema/resource/ClasspathSchemaLoader.java b/src/main/java/com/networknt/schema/resource/ClasspathResourceLoader.java similarity index 76% rename from src/main/java/com/networknt/schema/resource/ClasspathSchemaLoader.java rename to src/main/java/com/networknt/schema/resource/ClasspathResourceLoader.java index 9cb41b94c..1c283a444 100644 --- a/src/main/java/com/networknt/schema/resource/ClasspathSchemaLoader.java +++ b/src/main/java/com/networknt/schema/resource/ClasspathResourceLoader.java @@ -24,14 +24,22 @@ /** * Loads from classpath. */ -public class ClasspathSchemaLoader implements SchemaLoader { +public class ClasspathResourceLoader implements ResourceLoader { + private static class Holder { + private static final ClasspathResourceLoader INSTANCE = new ClasspathResourceLoader(); + } + + public static ClasspathResourceLoader getInstance() { + return Holder.INSTANCE; + } + private final Supplier classLoaderSource; /** * Constructor. */ - public ClasspathSchemaLoader() { - this(ClasspathSchemaLoader::getClassLoader); + public ClasspathResourceLoader() { + this(ClasspathResourceLoader::getClassLoader); } /** @@ -39,12 +47,12 @@ public ClasspathSchemaLoader() { * * @param classLoaderSource the class loader source */ - public ClasspathSchemaLoader(Supplier classLoaderSource) { + public ClasspathResourceLoader(Supplier classLoaderSource) { this.classLoaderSource = classLoaderSource; } @Override - public InputStreamSource getSchema(AbsoluteIri absoluteIri) { + public InputStreamSource getResource(AbsoluteIri absoluteIri) { String iri = absoluteIri != null ? absoluteIri.toString() : ""; String name = null; if (iri.startsWith("classpath:")) { @@ -75,7 +83,7 @@ public InputStreamSource getSchema(AbsoluteIri absoluteIri) { protected static ClassLoader getClassLoader() { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); if (classLoader == null) { - classLoader = SchemaLoader.class.getClassLoader(); + classLoader = ResourceLoader.class.getClassLoader(); } return classLoader; } diff --git a/src/main/java/com/networknt/schema/resource/DefaultSchemaLoader.java b/src/main/java/com/networknt/schema/resource/DefaultSchemaLoader.java deleted file mode 100644 index a090719b8..000000000 --- a/src/main/java/com/networknt/schema/resource/DefaultSchemaLoader.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.networknt.schema.resource; - -import java.util.ArrayList; -import java.util.List; - -import com.networknt.schema.AbsoluteIri; - -/** - * Default {@link SchemaLoader}. - */ -public class DefaultSchemaLoader implements SchemaLoader { - private static final List DEFAULT; - private static final MetaSchemaMapper META_SCHEMA_MAPPER = new MetaSchemaMapper(); - - static { - List result = new ArrayList<>(); - result.add(new ClasspathSchemaLoader()); - result.add(new UriSchemaLoader()); - DEFAULT = result; - } - - private final List schemaLoaders; - private final List schemaMappers; - - public DefaultSchemaLoader(List schemaLoaders, List schemaMappers) { - this.schemaLoaders = schemaLoaders; - this.schemaMappers = schemaMappers; - } - - @Override - public InputStreamSource getSchema(AbsoluteIri absoluteIri) { - AbsoluteIri mappedResult = absoluteIri; - for (SchemaMapper mapper : schemaMappers) { - AbsoluteIri mapped = mapper.map(mappedResult); - if (mapped != null) { - mappedResult = mapped; - } - } - AbsoluteIri mapped = META_SCHEMA_MAPPER.map(absoluteIri); - if (mapped != null) { - mappedResult = mapped; - } - for (SchemaLoader loader : schemaLoaders) { - InputStreamSource result = loader.getSchema(mappedResult); - if (result != null) { - return result; - } - } - for (SchemaLoader loader : DEFAULT) { - InputStreamSource result = loader.getSchema(mappedResult); - if (result != null) { - return result; - } - } - return null; - } - -} diff --git a/src/main/java/com/networknt/schema/resource/DisallowSchemaLoader.java b/src/main/java/com/networknt/schema/resource/DisallowSchemaLoader.java deleted file mode 100644 index a63375dfa..000000000 --- a/src/main/java/com/networknt/schema/resource/DisallowSchemaLoader.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.networknt.schema.resource; - -import com.networknt.schema.AbsoluteIri; -import com.networknt.schema.InvalidSchemaException; -import com.networknt.schema.ValidationMessage; - -/** - * {@link SchemaLoader} that disallows loading external resources. - */ -public class DisallowSchemaLoader implements SchemaLoader { - private static final DisallowSchemaLoader INSTANCE = new DisallowSchemaLoader(); - - /** - * Disallows loading schemas from external resources. - * - * @return the disallow schema loader - */ - public static DisallowSchemaLoader getInstance() { - return INSTANCE; - } - - /** - * Constructor. - */ - private DisallowSchemaLoader() { - } - - @Override - public InputStreamSource getSchema(AbsoluteIri absoluteIri) { - throw new InvalidSchemaException(ValidationMessage.builder() - .message("Schema from ''{1}'' is not allowed to be loaded.").arguments(absoluteIri).build()); - } -} diff --git a/src/main/java/com/networknt/schema/resource/UriSchemaLoader.java b/src/main/java/com/networknt/schema/resource/IriResourceLoader.java similarity index 86% rename from src/main/java/com/networknt/schema/resource/UriSchemaLoader.java rename to src/main/java/com/networknt/schema/resource/IriResourceLoader.java index 082535357..456c61dfe 100644 --- a/src/main/java/com/networknt/schema/resource/UriSchemaLoader.java +++ b/src/main/java/com/networknt/schema/resource/IriResourceLoader.java @@ -27,11 +27,19 @@ import com.networknt.schema.utils.AbsoluteIris; /** - * Loads from uri. + * Loads from iri. */ -public class UriSchemaLoader implements SchemaLoader { +public class IriResourceLoader implements ResourceLoader { + private static class Holder { + private static final IriResourceLoader INSTANCE = new IriResourceLoader(); + } + + public static IriResourceLoader getInstance() { + return Holder.INSTANCE; + } + @Override - public InputStreamSource getSchema(AbsoluteIri absoluteIri) { + public InputStreamSource getResource(AbsoluteIri absoluteIri) { URI uri = toURI(absoluteIri); URL url = toURL(uri); return () -> { @@ -97,7 +105,7 @@ protected InputStream openConnectionCheckRedirects(URLConnection c) throws IOExc // and should be limited to 5 redirections at most. if (target == null || !(target.getProtocol().equals("http") || target.getProtocol().equals("https")) || redirects >= 5) { - throw new SecurityException("illegal URL redirect"); + throw new SecurityException("Maximum number of redirects exceeded"); } redir = true; c = target.openConnection(); diff --git a/src/main/java/com/networknt/schema/resource/MapSchemaLoader.java b/src/main/java/com/networknt/schema/resource/MapResourceLoader.java similarity index 63% rename from src/main/java/com/networknt/schema/resource/MapSchemaLoader.java rename to src/main/java/com/networknt/schema/resource/MapResourceLoader.java index 6d4b32f53..24912f3f9 100644 --- a/src/main/java/com/networknt/schema/resource/MapSchemaLoader.java +++ b/src/main/java/com/networknt/schema/resource/MapResourceLoader.java @@ -8,42 +8,42 @@ import com.networknt.schema.AbsoluteIri; /** - * Map implementation of {@link SchemaLoader}. + * Map implementation of {@link ResourceLoader}. */ -public class MapSchemaLoader implements SchemaLoader { +public class MapResourceLoader implements ResourceLoader { private final Function mappings; /** - * Sets the schema data by absolute IRI. + * Sets the resource data by absolute IRI. * * @param mappings the mappings */ - public MapSchemaLoader(Map mappings) { + public MapResourceLoader(Map mappings) { this(mappings::get); } /** - * Sets the schema data by absolute IRI function. + * Sets the resource data by absolute IRI function. * * @param mappings the mappings */ - public MapSchemaLoader(Function mappings) { + public MapResourceLoader(Function mappings) { this.mappings = mappings; } /** - * Sets the schema data by using two mapping functions. + * Sets the resource data by using two mapping functions. *

* Firstly to map the IRI to an object. If the object is null no mapping is * performed. *

- * Next to map the object to the schema data. + * Next to map the object to the resource data. * * @param the type of the object * @param mapIriToObject the mapping of IRI to object - * @param mapObjectToData the mappingof object to schema data + * @param mapObjectToData the mappingof object to resource data */ - public MapSchemaLoader(Function mapIriToObject, Function mapObjectToData) { + public MapResourceLoader(Function mapIriToObject, Function mapObjectToData) { this.mappings = iri -> { T result = mapIriToObject.apply(iri); if (result != null) { @@ -54,7 +54,7 @@ public MapSchemaLoader(Function mapIriToObject, Function mappings; - public MapSchemaMapper(Map mappings) { + public MapSchemaIdResolver(Map mappings) { this(mappings::get); } - public MapSchemaMapper(Function mappings) { + public MapSchemaIdResolver(Function mappings) { this.mappings = mappings; } @@ -26,7 +26,7 @@ public MapSchemaMapper(Function mappings) { * @param test the predicate * @param mappings the mapping */ - public MapSchemaMapper(Predicate test, Function mappings) { + public MapSchemaIdResolver(Predicate test, Function mappings) { this.mappings = iri -> { if (test.test(iri)) { return mappings.apply(iri); @@ -36,7 +36,7 @@ public MapSchemaMapper(Predicate test, Function mappings } @Override - public AbsoluteIri map(AbsoluteIri absoluteIRI) { + public AbsoluteIri resolve(AbsoluteIri absoluteIRI) { String mapped = this.mappings.apply(absoluteIRI.toString()); if (mapped != null) { return AbsoluteIri.of(mapped); diff --git a/src/main/java/com/networknt/schema/resource/MetaSchemaMapper.java b/src/main/java/com/networknt/schema/resource/MetaSchemaIdResolver.java similarity index 82% rename from src/main/java/com/networknt/schema/resource/MetaSchemaMapper.java rename to src/main/java/com/networknt/schema/resource/MetaSchemaIdResolver.java index 7881eced6..f26d18ae5 100644 --- a/src/main/java/com/networknt/schema/resource/MetaSchemaMapper.java +++ b/src/main/java/com/networknt/schema/resource/MetaSchemaIdResolver.java @@ -20,14 +20,22 @@ /** * Maps the JSON Schema meta schema to the class path location. */ -public class MetaSchemaMapper implements SchemaMapper { +public class MetaSchemaIdResolver implements SchemaIdResolver { + private static class Holder { + private static MetaSchemaIdResolver INSTANCE = new MetaSchemaIdResolver(); + } + + public static MetaSchemaIdResolver getInstance() { + return Holder.INSTANCE; + } + private static final char ANCHOR = '#'; private static final String CLASSPATH_PREFIX = "classpath:"; private static final String HTTP_JSON_SCHEMA_ORG_PREFIX = "http://json-schema.org/"; private static final String HTTPS_JSON_SCHEMA_ORG_PREFIX = "https://json-schema.org/"; @Override - public AbsoluteIri map(AbsoluteIri absoluteIRI) { + public AbsoluteIri resolve(AbsoluteIri absoluteIRI) { String absoluteIRIString = absoluteIRI != null ? absoluteIRI.toString() : null; if (absoluteIRIString != null) { if (absoluteIRIString.startsWith(HTTPS_JSON_SCHEMA_ORG_PREFIX)) { diff --git a/src/main/java/com/networknt/schema/resource/PrefixSchemaMapper.java b/src/main/java/com/networknt/schema/resource/PrefixSchemaIdResolver.java similarity index 66% rename from src/main/java/com/networknt/schema/resource/PrefixSchemaMapper.java rename to src/main/java/com/networknt/schema/resource/PrefixSchemaIdResolver.java index 46f4f805b..13caa7664 100644 --- a/src/main/java/com/networknt/schema/resource/PrefixSchemaMapper.java +++ b/src/main/java/com/networknt/schema/resource/PrefixSchemaIdResolver.java @@ -3,19 +3,19 @@ import com.networknt.schema.AbsoluteIri; /** - * Prefix implementation of {@link SchemaMapper}. + * Prefix implementation of {@link SchemaIdResolver}. */ -public class PrefixSchemaMapper implements SchemaMapper { +public class PrefixSchemaIdResolver implements SchemaIdResolver { private final String source; private final String replacement; - public PrefixSchemaMapper(String source, String replacement) { + public PrefixSchemaIdResolver(String source, String replacement) { this.source = source; this.replacement = replacement; } @Override - public AbsoluteIri map(AbsoluteIri absoluteIRI) { + public AbsoluteIri resolve(AbsoluteIri absoluteIRI) { String absoluteIRIString = absoluteIRI != null ? absoluteIRI.toString() : null; if (absoluteIRIString != null && absoluteIRIString.startsWith(source)) { return AbsoluteIri.of(replacement + absoluteIRIString.substring(source.length())); diff --git a/src/main/java/com/networknt/schema/resource/SchemaMapper.java b/src/main/java/com/networknt/schema/resource/ResourceLoader.java similarity index 66% rename from src/main/java/com/networknt/schema/resource/SchemaMapper.java rename to src/main/java/com/networknt/schema/resource/ResourceLoader.java index be6813a16..aff14b9f5 100644 --- a/src/main/java/com/networknt/schema/resource/SchemaMapper.java +++ b/src/main/java/com/networknt/schema/resource/ResourceLoader.java @@ -18,16 +18,15 @@ import com.networknt.schema.AbsoluteIri; /** - * Schema Mapper used to map an ID indicated by an absolute IRI to a retrieval - * IRI. + * Resource Loader used to load data using a retrieval IRI. */ @FunctionalInterface -public interface SchemaMapper { +public interface ResourceLoader { /** - * Maps an ID indicated by an absolute IRI to a retrieval IRI. + * Loads data given the retrieval IRI. * - * @param absoluteIRI the ID - * @return the retrieval IRI or null if this mapper doesn't support the mapping + * @param location the retrieval IRI + * @return the input stream source */ - AbsoluteIri map(AbsoluteIri absoluteIRI); + InputStreamSource getResource(AbsoluteIri location); } diff --git a/src/main/java/com/networknt/schema/resource/SchemaLoaders.java b/src/main/java/com/networknt/schema/resource/ResourceLoaders.java similarity index 59% rename from src/main/java/com/networknt/schema/resource/SchemaLoaders.java rename to src/main/java/com/networknt/schema/resource/ResourceLoaders.java index 8a18a8871..85525b53f 100644 --- a/src/main/java/com/networknt/schema/resource/SchemaLoaders.java +++ b/src/main/java/com/networknt/schema/resource/ResourceLoaders.java @@ -23,20 +23,20 @@ import java.util.function.Function; /** - * Schema Loaders used to load a schema given the retrieval IRI. + * Resource Loaders used to load a resource given the retrieval IRI. */ -public class SchemaLoaders extends ArrayList { +public class ResourceLoaders extends ArrayList { private static final long serialVersionUID = 1L; - public SchemaLoaders() { + public ResourceLoaders() { super(); } - public SchemaLoaders(Collection c) { + public ResourceLoaders(Collection c) { super(c); } - public SchemaLoaders(int initialCapacity) { + public ResourceLoaders(int initialCapacity) { super(initialCapacity); } @@ -45,7 +45,7 @@ public static Builder builder() { } public static class Builder { - private final SchemaLoaders values = new SchemaLoaders(); + private final ResourceLoaders values = new ResourceLoaders(); public Builder() { } @@ -62,51 +62,51 @@ public Builder with(Builder builder) { } /** - * Customize the schema loaders. + * Customize the resource loaders. * * @param customizer the customizer * @return the builder */ - public Builder values(Consumer> customizer) { + public Builder values(Consumer> customizer) { customizer.accept(this.values); return this; } /** - * Adds a schema loader. + * Adds a resource loader. * - * @param schemaLoader the schema loader + * @param resourceLoader the resource loader * @return the builder */ - public Builder add(SchemaLoader schemaLoader) { - this.values.add(schemaLoader); + public Builder add(ResourceLoader resourceLoader) { + this.values.add(resourceLoader); return this; } /** - * Sets the schema data by absolute IRI. + * Sets the resource data by absolute IRI. * - * @param schemas the map of IRI to schema data + * @param resources the map of IRI to resource data * @return the builder */ - public Builder schemas(Map schemas) { - this.values.add(new MapSchemaLoader(schemas)); + public Builder resources(Map resources) { + this.values.add(new MapResourceLoader(resources)); return this; } /** - * Sets the schema data by absolute IRI function. + * Sets the resource data by absolute IRI function. * - * @param schemas the function that returns schema data given IRI + * @param resources the function that returns resource data given IRI * @return the builder */ - public Builder schemas(Function schemas) { - this.values.add(new MapSchemaLoader(schemas)); + public Builder resources(Function resources) { + this.values.add(new MapResourceLoader(resources)); return this; } /** - * Sets the schema data by using two mapping functions. + * Sets the resource data by using two mapping functions. *

* Firstly to map the IRI to an object. If the object is null no mapping is * performed. @@ -118,17 +118,17 @@ public Builder schemas(Function schemas) { * @param mapObjectToData the mappingof object to schema data * @return the builder */ - public Builder schemas(Function mapIriToObject, Function mapObjectToData) { - this.values.add(new MapSchemaLoader(mapIriToObject, mapObjectToData)); + public Builder resources(Function mapIriToObject, Function mapObjectToData) { + this.values.add(new MapResourceLoader(mapIriToObject, mapObjectToData)); return this; } /** - * Builds a {@link SchemaLoaders}. + * Builds a {@link ResourceLoaders}. * - * @return the schema loaders + * @return the resource loaders */ - public SchemaLoaders build() { + public ResourceLoaders build() { return values; } } diff --git a/src/main/java/com/networknt/schema/JsonMetaSchemaFactory.java b/src/main/java/com/networknt/schema/resource/SchemaIdResolver.java similarity index 57% rename from src/main/java/com/networknt/schema/JsonMetaSchemaFactory.java rename to src/main/java/com/networknt/schema/resource/SchemaIdResolver.java index 31d7f1adb..f5b307563 100644 --- a/src/main/java/com/networknt/schema/JsonMetaSchemaFactory.java +++ b/src/main/java/com/networknt/schema/resource/SchemaIdResolver.java @@ -13,20 +13,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.resource; + +import com.networknt.schema.AbsoluteIri; /** - * Factory for {@link JsonMetaSchema}. + * Schema ID resolver used to map the schema $id indicated by an absolute IRI to a retrieval + * IRI. */ @FunctionalInterface -public interface JsonMetaSchemaFactory { +public interface SchemaIdResolver { /** - * Gets the meta-schema given the IRI. + * Resolves a schema $id indicated by an absolute IRI to a retrieval IRI. * - * @param iri the meta-schema IRI - * @param schemaFactory the schema factory - * @param config the config - * @return the meta-schema + * @param schemaId the $id of the schema + * @return the retrieval IRI or null if this resolver doesn't support the mapping */ - JsonMetaSchema getMetaSchema(String iri, JsonSchemaFactory schemaFactory, SchemaValidatorsConfig config); + AbsoluteIri resolve(AbsoluteIri schemaId); } diff --git a/src/main/java/com/networknt/schema/resource/SchemaMappers.java b/src/main/java/com/networknt/schema/resource/SchemaIdResolvers.java similarity index 74% rename from src/main/java/com/networknt/schema/resource/SchemaMappers.java rename to src/main/java/com/networknt/schema/resource/SchemaIdResolvers.java index 9757c6837..f56ad8991 100644 --- a/src/main/java/com/networknt/schema/resource/SchemaMappers.java +++ b/src/main/java/com/networknt/schema/resource/SchemaIdResolvers.java @@ -27,18 +27,18 @@ * Schema Mappers used to map an ID indicated by an absolute IRI to a retrieval * IRI. */ -public class SchemaMappers extends ArrayList { +public class SchemaIdResolvers extends ArrayList { private static final long serialVersionUID = 1L; - public SchemaMappers() { + public SchemaIdResolvers() { super(); } - public SchemaMappers(Collection c) { + public SchemaIdResolvers(Collection c) { super(c); } - public SchemaMappers(int initialCapacity) { + public SchemaIdResolvers(int initialCapacity) { super(initialCapacity); } @@ -47,7 +47,7 @@ public static Builder builder() { } public static class Builder { - private final SchemaMappers values = new SchemaMappers(); + private final SchemaIdResolvers values = new SchemaIdResolvers(); public Builder() { } @@ -64,12 +64,12 @@ public Builder with(Builder builder) { } /** - * Customize the schema mappers. + * Customize the schema id resolvers. * * @param customizer the customizer * @return the builder */ - public Builder values(Consumer> customizer) { + public Builder values(Consumer> customizer) { customizer.accept(this.values); return this; } @@ -77,11 +77,11 @@ public Builder values(Consumer> customizer) { /** * Adds a schema mapper. * - * @param schemaMapper the schema mapper + * @param schemaIdResolver the schema mapper * @return the builder */ - public Builder add(SchemaMapper schemaMapper) { - this.values.add(schemaMapper); + public Builder add(SchemaIdResolver schemaIdResolver) { + this.values.add(schemaIdResolver); return this; } @@ -93,7 +93,7 @@ public Builder add(SchemaMapper schemaMapper) { * @return the builder */ public Builder mapPrefix(String source, String replacement) { - this.values.add(new PrefixSchemaMapper(source, replacement)); + this.values.add(new PrefixSchemaIdResolver(source, replacement)); return this; } @@ -104,7 +104,7 @@ public Builder mapPrefix(String source, String replacement) { * @return the builder */ public Builder mappings(Map mappings) { - this.values.add(new MapSchemaMapper(mappings)); + this.values.add(new MapSchemaIdResolver(mappings)); return this; } @@ -115,7 +115,7 @@ public Builder mappings(Map mappings) { * @return the builder */ public Builder mappings(Function mappings) { - this.values.add(new MapSchemaMapper(mappings)); + this.values.add(new MapSchemaIdResolver(mappings)); return this; } @@ -127,16 +127,16 @@ public Builder mappings(Function mappings) { * @return the builder */ public Builder mappings(Predicate test, Function mappings) { - this.values.add(new MapSchemaMapper(test, mappings)); + this.values.add(new MapSchemaIdResolver(test, mappings)); return this; } /** - * Builds a {@link SchemaMappers} + * Builds a {@link SchemaIdResolvers} * * @return the schema mappers */ - public SchemaMappers build() { + public SchemaIdResolvers build() { return values; } } diff --git a/src/main/java/com/networknt/schema/resource/SchemaLoader.java b/src/main/java/com/networknt/schema/resource/SchemaLoader.java index 86aa0f748..d6cb49d7d 100644 --- a/src/main/java/com/networknt/schema/resource/SchemaLoader.java +++ b/src/main/java/com/networknt/schema/resource/SchemaLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 the original author or authors. + * Copyright (c) 2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,18 +15,213 @@ */ package com.networknt.schema.resource; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Predicate; + import com.networknt.schema.AbsoluteIri; +import com.networknt.schema.Error; +import com.networknt.schema.InvalidSchemaException; /** - * Schema Loader used to load a schema given the retrieval IRI. + * Schema Loader used to load the schema resource from the schema $id. + *

+ * By default the SchemaLoader does not fetch remote resources. This must be + * explicitly configured using {@link Builder#fetchRemoteResources}. */ -@FunctionalInterface -public interface SchemaLoader { +public class SchemaLoader { + private static final MetaSchemaIdResolver META_SCHEMA_ID_RESOLVER = MetaSchemaIdResolver.getInstance(); + private static final ClasspathResourceLoader CLASSPATH_RESOURCE_LOADER = ClasspathResourceLoader.getInstance(); + + private static class DefaultHolder { + private static final SchemaLoader DEFAULT = new SchemaLoader(Collections.emptyList(), Collections.emptyList()); + } + + private static class RemoteFetcher { + private static final SchemaLoader REMOTE_FETCHER = SchemaLoader.builder().fetchRemoteResources().build(); + } + + /** + * Gets the default schema loader. + *

+ * By default this does not fetch remote resources and must be explicitly + * configured to do so. + * + * @return the default schema loader + */ + public static SchemaLoader getDefault() { + return DefaultHolder.DEFAULT; + } + /** - * Loads a schema given the retrieval IRI. + * Gets the schema loader the does remote fetching. * - * @param absoluteIri the retrieval IRI - * @return the input stream source + * @return the schema loader that does remote fetching */ - InputStreamSource getSchema(AbsoluteIri absoluteIri); + public static SchemaLoader getRemoteFetcher() { + return RemoteFetcher.REMOTE_FETCHER; + } + + protected final List resourceLoaders; + protected final List schemaIdResolvers; + protected final Predicate allow; + protected final Predicate block; + + public SchemaLoader(ResourceLoader resourceLoader) { + this(Collections.emptyList(), Collections.singletonList(resourceLoader)); + } + + public SchemaLoader(SchemaIdResolver schemaIdResolver, ResourceLoader resourceLoader) { + this(Collections.singletonList(schemaIdResolver), Collections.singletonList(resourceLoader)); + } + + public SchemaLoader(List schemaIdResolvers, List resourceLoaders) { + this(schemaIdResolvers, resourceLoaders, null, null); + } + + public SchemaLoader(List schemaIdResolvers, List resourceLoaders, + Predicate allow, Predicate block) { + this.schemaIdResolvers = schemaIdResolvers; + this.resourceLoaders = resourceLoaders; + this.allow = allow; + this.block = block; + } + + public SchemaLoader(SchemaLoader copy) { + this(new ArrayList<>(copy.schemaIdResolvers), new ArrayList<>(copy.resourceLoaders)); + } + + public InputStreamSource getSchemaResource(AbsoluteIri absoluteIri) { + if (this.allow != null) { + if (!this.allow.test(absoluteIri)) { + throw new InvalidSchemaException(Error.builder() + .message("Schema from ''{0}'' is not allowed to be loaded.").arguments(absoluteIri).build()); + } + } + if (this.block != null) { + if (this.block.test(absoluteIri)) { + throw new InvalidSchemaException(Error.builder() + .message("Schema from ''{0}'' is not allowed to be loaded.").arguments(absoluteIri).build()); + } + } + AbsoluteIri mappedResult = absoluteIri; + for (SchemaIdResolver mapper : schemaIdResolvers) { + AbsoluteIri mapped = mapper.resolve(mappedResult); + if (mapped != null) { + mappedResult = mapped; + } + } + AbsoluteIri mapped = resolveMetaSchemaId(absoluteIri); + if (mapped != null) { + mappedResult = mapped; + } + InputStreamSource result = getClasspathResource(mappedResult); + if (result != null) { + return result; + } + for (ResourceLoader loader : resourceLoaders) { + result = loader.getResource(mappedResult); + if (result != null) { + return result; + } + } + return null; + } + + protected AbsoluteIri resolveMetaSchemaId(AbsoluteIri absoluteIri) { + return META_SCHEMA_ID_RESOLVER.resolve(absoluteIri); + } + + protected InputStreamSource getClasspathResource(AbsoluteIri absoluteIri) { + return CLASSPATH_RESOURCE_LOADER.getResource(absoluteIri); + } + + public List getResourceLoaders() { + return this.resourceLoaders; + } + + public List getSchemaIdResolvers() { + return this.schemaIdResolvers; + } + + public static Builder builder() { + return new Builder(); + } + + public static Builder builder(SchemaLoader copy) { + Builder builder = new Builder(); + if (!copy.getResourceLoaders().isEmpty()) { + builder.resourceLoaders(r -> r.values(c -> c.addAll(copy.resourceLoaders))); + } + if (!copy.getSchemaIdResolvers().isEmpty()) { + builder.schemaIdResolvers(r -> r.values(c -> c.addAll(copy.schemaIdResolvers))); + } + builder.allow(copy.allow); + builder.block(copy.block); + return builder; + } + + public static class Builder { + private SchemaIdResolvers.Builder schemaIdResolversBuilder = new SchemaIdResolvers.Builder(); + private ResourceLoaders.Builder resourceLoadersBuilder = new ResourceLoaders.Builder(); + private Predicate allow = null; + private Predicate block = null; + private boolean fetchRemoteResources = false; + + public Builder() { + } + + public Builder schemaIdResolvers(Consumer customizer) { + customizer.accept(schemaIdResolversBuilder); + return this; + } + + public Builder resourceLoaders(Consumer customizer) { + customizer.accept(resourceLoadersBuilder); + return this; + } + + public Builder allow(Predicate allow) { + this.allow = allow; + return this; + } + + public Builder block(Predicate block) { + this.block = block; + return this; + } + + public Builder fetchRemoteResources(boolean fetch) { + this.fetchRemoteResources = fetch; + return this; + } + + /** + * Adds the IriResourceLoader to allow fetching of remote resources. + * + * @return the builder + */ + public Builder fetchRemoteResources() { + return fetchRemoteResources(true); + } + + public SchemaIdResolvers.Builder getSchemaIdResolversBuilder() { + return schemaIdResolversBuilder; + } + + public ResourceLoaders.Builder getResourceLoadersBuilder() { + return resourceLoadersBuilder; + } + + public SchemaLoader build() { + if (this.fetchRemoteResources) { + // This ensures the IriResourceLoader is added at the end + this.resourceLoadersBuilder.add(IriResourceLoader.getInstance()); + } + return new SchemaLoader(schemaIdResolversBuilder.build(), resourceLoadersBuilder.build(), this.allow, + this.block); + } + } } diff --git a/src/main/java/com/networknt/schema/result/JsonNodeResult.java b/src/main/java/com/networknt/schema/result/InstanceResult.java similarity index 79% rename from src/main/java/com/networknt/schema/result/JsonNodeResult.java rename to src/main/java/com/networknt/schema/result/InstanceResult.java index 8b464d37b..7925d13c9 100644 --- a/src/main/java/com/networknt/schema/result/JsonNodeResult.java +++ b/src/main/java/com/networknt/schema/result/InstanceResult.java @@ -17,19 +17,19 @@ import java.util.Objects; -import com.networknt.schema.JsonNodePath; import com.networknt.schema.SchemaLocation; +import com.networknt.schema.path.NodePath; /** - * Sub schema results. + * Instance results. */ -public class JsonNodeResult { - private final JsonNodePath instanceLocation; +public class InstanceResult { + private final NodePath instanceLocation; private final SchemaLocation schemaLocation; - private final JsonNodePath evaluationPath; + private final NodePath evaluationPath; private final boolean valid; - public JsonNodeResult(JsonNodePath instanceLocation, SchemaLocation schemaLocation, JsonNodePath evaluationPath, + public InstanceResult(NodePath instanceLocation, SchemaLocation schemaLocation, NodePath evaluationPath, boolean valid) { super(); this.instanceLocation = instanceLocation; @@ -38,7 +38,7 @@ public JsonNodeResult(JsonNodePath instanceLocation, SchemaLocation schemaLocati this.valid = valid; } - public JsonNodePath getInstanceLocation() { + public NodePath getInstanceLocation() { return instanceLocation; } @@ -46,7 +46,7 @@ public SchemaLocation getSchemaLocation() { return schemaLocation; } - public JsonNodePath getEvaluationPath() { + public NodePath getEvaluationPath() { return evaluationPath; } @@ -73,7 +73,7 @@ public boolean equals(Object obj) { return false; if (getClass() != obj.getClass()) return false; - JsonNodeResult other = (JsonNodeResult) obj; + InstanceResult other = (InstanceResult) obj; return Objects.equals(evaluationPath, other.evaluationPath) && Objects.equals(instanceLocation, other.instanceLocation) && Objects.equals(schemaLocation, other.schemaLocation) && valid == other.valid; diff --git a/src/main/java/com/networknt/schema/result/JsonNodeResults.java b/src/main/java/com/networknt/schema/result/InstanceResults.java similarity index 65% rename from src/main/java/com/networknt/schema/result/JsonNodeResults.java rename to src/main/java/com/networknt/schema/result/InstanceResults.java index 0b3f5e893..88e446ea6 100644 --- a/src/main/java/com/networknt/schema/result/JsonNodeResults.java +++ b/src/main/java/com/networknt/schema/result/InstanceResults.java @@ -20,30 +20,30 @@ import java.util.List; import java.util.Map; -import com.networknt.schema.JsonNodePath; import com.networknt.schema.SchemaLocation; +import com.networknt.schema.path.NodePath; /** - * Sub schema results. + * Instance results. */ -public class JsonNodeResults { +public class InstanceResults { /** * Stores the invalid results. */ - private final Map> values = new HashMap<>(); + private final Map> values = new HashMap<>(); - public void setResult(JsonNodePath instanceLocation, SchemaLocation schemaLocation, JsonNodePath evaluationPath, + public void setResult(NodePath instanceLocation, SchemaLocation schemaLocation, NodePath evaluationPath, boolean valid) { - JsonNodeResult result = new JsonNodeResult(instanceLocation, schemaLocation, evaluationPath, valid); - List v = values.computeIfAbsent(instanceLocation, k -> new ArrayList<>()); + InstanceResult result = new InstanceResult(instanceLocation, schemaLocation, evaluationPath, valid); + List v = values.computeIfAbsent(instanceLocation, k -> new ArrayList<>()); v.add(result); } - public boolean isValid(JsonNodePath instanceLocation, JsonNodePath evaluationPath) { - List instance = values.get(instanceLocation); + public boolean isValid(NodePath instanceLocation, NodePath evaluationPath) { + List instance = values.get(instanceLocation); if (instance != null) { - for (JsonNodeResult result : instance) { + for (InstanceResult result : instance) { if (evaluationPath.startsWith(result.getEvaluationPath())) { if(!result.isValid()) { return false; diff --git a/src/main/java/com/networknt/schema/serialization/BasicNodeReader.java b/src/main/java/com/networknt/schema/serialization/BasicNodeReader.java new file mode 100644 index 000000000..08d8c106a --- /dev/null +++ b/src/main/java/com/networknt/schema/serialization/BasicNodeReader.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.networknt.schema.serialization; + +import java.io.IOException; +import java.io.InputStream; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.networknt.schema.InputFormat; + +/** + * Basic implementation of {@link NodeReader}. + */ +public class BasicNodeReader implements NodeReader { + private static class Holder { + private static final BasicNodeReader INSTANCE = new BasicNodeReader(); + } + + public static BasicNodeReader getInstance() { + return Holder.INSTANCE; + } + + protected BasicNodeReader() { + } + + @Override + public JsonNode readTree(String content, InputFormat inputFormat) throws IOException { + return getObjectMapper(inputFormat).readTree(content); + } + + @Override + public JsonNode readTree(InputStream content, InputFormat inputFormat) throws IOException { + return getObjectMapper(inputFormat).readTree(content); + } + + /** + * Gets the object mapper for the input format. + * + * @param inputFormat the input format + * @return the object mapper + */ + protected ObjectMapper getObjectMapper(InputFormat inputFormat) { + if (InputFormat.JSON.equals(inputFormat)) { + return JsonMapperFactory.getInstance(); + } else if (InputFormat.YAML.equals(inputFormat)) { + return YamlMapperFactory.getInstance(); + } + throw new IllegalArgumentException("Unsupported input format "+inputFormat); + } +} diff --git a/src/main/java/com/networknt/schema/serialization/DefaultJsonNodeReader.java b/src/main/java/com/networknt/schema/serialization/DefaultNodeReader.java similarity index 87% rename from src/main/java/com/networknt/schema/serialization/DefaultJsonNodeReader.java rename to src/main/java/com/networknt/schema/serialization/DefaultNodeReader.java index 10707edca..242887fd5 100644 --- a/src/main/java/com/networknt/schema/serialization/DefaultJsonNodeReader.java +++ b/src/main/java/com/networknt/schema/serialization/DefaultNodeReader.java @@ -11,9 +11,9 @@ import com.networknt.schema.utils.JsonNodes; /** - * Default {@link JsonNodeReader}. + * Default {@link NodeReader}. */ -public class DefaultJsonNodeReader implements JsonNodeReader { +public class DefaultNodeReader implements NodeReader { protected final ObjectMapper jsonMapper; protected final ObjectMapper yamlMapper; protected final JsonNodeFactoryFactory jsonNodeFactoryFactory; @@ -25,7 +25,7 @@ public class DefaultJsonNodeReader implements JsonNodeReader { * @param yamlMapper the yaml mapper * @param jsonNodeFactoryFactory the json node factory factory */ - protected DefaultJsonNodeReader(ObjectMapper jsonMapper, ObjectMapper yamlMapper, + protected DefaultNodeReader(ObjectMapper jsonMapper, ObjectMapper yamlMapper, JsonNodeFactoryFactory jsonNodeFactoryFactory) { this.jsonMapper = jsonMapper; this.yamlMapper = yamlMapper; @@ -84,7 +84,7 @@ protected ObjectMapper getObjectMapper(InputFormat inputFormat) { } /** - * Gets the builder for {@link DefaultJsonNodeReader}. + * Gets the builder for {@link DefaultNodeReader}. * * @return the builder */ @@ -93,7 +93,7 @@ public static Builder builder() { } /** - * Builder support for {@link JsonNodeReader}. + * Builder support for {@link NodeReader}. * * @param the super type */ @@ -143,7 +143,7 @@ public T jsonNodeFactoryFactory(JsonNodeFactoryFactory jsonNodeFactoryFactory) { } /** - * Builder for {@link DefaultJsonNodeReader}. + * Builder for {@link DefaultNodeReader}. */ public static class Builder extends BuilderSupport { @@ -162,12 +162,12 @@ public Builder locationAware() { } /** - * Builds the {@link JsonNodeReader}. + * Builds the {@link NodeReader}. * * @return the object reader */ - public JsonNodeReader build() { - return new DefaultJsonNodeReader(this.jsonMapper, this.yamlMapper, this.jsonNodeFactoryFactory); + public NodeReader build() { + return new DefaultNodeReader(this.jsonMapper, this.yamlMapper, this.jsonNodeFactoryFactory); } } } diff --git a/src/main/java/com/networknt/schema/serialization/JsonNodeReader.java b/src/main/java/com/networknt/schema/serialization/NodeReader.java similarity index 86% rename from src/main/java/com/networknt/schema/serialization/JsonNodeReader.java rename to src/main/java/com/networknt/schema/serialization/NodeReader.java index cb4b53f36..39cff35d1 100644 --- a/src/main/java/com/networknt/schema/serialization/JsonNodeReader.java +++ b/src/main/java/com/networknt/schema/serialization/NodeReader.java @@ -24,7 +24,7 @@ /** * Reader for reading content to {@link JsonNode}. */ -public interface JsonNodeReader { +public interface NodeReader { /** * Deserialize content as a tree. @@ -47,11 +47,11 @@ public interface JsonNodeReader { JsonNode readTree(InputStream content, InputFormat inputFormat) throws IOException; /** - * Creates a builder for {@link JsonNodeReader}. + * Creates a builder for {@link NodeReader}. * * @return the builder */ - static DefaultJsonNodeReader.Builder builder() { - return DefaultJsonNodeReader.builder(); + static DefaultNodeReader.Builder builder() { + return DefaultNodeReader.builder(); } } diff --git a/src/main/java/com/networknt/schema/serialization/node/LocationJsonNodeFactory.java b/src/main/java/com/networknt/schema/serialization/node/LocationJsonNodeFactory.java index 1f027fb71..87fa9ec75 100644 --- a/src/main/java/com/networknt/schema/serialization/node/LocationJsonNodeFactory.java +++ b/src/main/java/com/networknt/schema/serialization/node/LocationJsonNodeFactory.java @@ -32,7 +32,7 @@ import com.fasterxml.jackson.databind.util.RawValue; /** - * {@link JsonNodeFactory} that creates {@link JsonLocationAware} nodes. + * {@link JsonNodeFactory} that creates {@link TokenStreamLocationAware} nodes. *

* Note that this will adversely affect performance as nodes with the same value * can no longer be cached and reused. @@ -57,12 +57,12 @@ public LocationJsonNodeFactory(JsonParser jsonParser) { @Override public BooleanNode booleanNode(boolean v) { - return new JsonLocationAwareBooleanNode(v, this.jsonParser.currentTokenLocation()); + return new TokenStreamLocationAwareBooleanNode(v, this.jsonParser.currentTokenLocation()); } @Override public NullNode nullNode() { - return new JsonLocationAwareNullNode(this.jsonParser.currentTokenLocation()); + return new TokenStreamLocationAwareNullNode(this.jsonParser.currentTokenLocation()); } @Override @@ -72,7 +72,7 @@ public JsonNode missingNode() { @Override public NumericNode numberNode(byte v) { - return new JsonLocationAwareIntNode(v, this.jsonParser.currentTokenLocation()); + return new TokenStreamLocationAwareIntNode(v, this.jsonParser.currentTokenLocation()); } @Override @@ -82,7 +82,7 @@ public ValueNode numberNode(Byte v) { @Override public NumericNode numberNode(short v) { - return new JsonLocationAwareShortNode(v, this.jsonParser.currentTokenLocation()); + return new TokenStreamLocationAwareShortNode(v, this.jsonParser.currentTokenLocation()); } @Override @@ -92,7 +92,7 @@ public ValueNode numberNode(Short value) { @Override public NumericNode numberNode(int v) { - return new JsonLocationAwareIntNode(v, this.jsonParser.currentTokenLocation()); + return new TokenStreamLocationAwareIntNode(v, this.jsonParser.currentTokenLocation()); } @Override @@ -102,7 +102,7 @@ public ValueNode numberNode(Integer v) { @Override public NumericNode numberNode(long v) { - return new JsonLocationAwareLongNode(v, this.jsonParser.currentTokenLocation()); + return new TokenStreamLocationAwareLongNode(v, this.jsonParser.currentTokenLocation()); } @Override @@ -112,12 +112,12 @@ public ValueNode numberNode(Long v) { @Override public ValueNode numberNode(BigInteger v) { - return (v == null) ? nullNode() : new JsonLocationAwareBigIntegerNode(v, this.jsonParser.currentTokenLocation()); + return (v == null) ? nullNode() : new TokenStreamLocationAwareBigIntegerNode(v, this.jsonParser.currentTokenLocation()); } @Override public NumericNode numberNode(float v) { - return new JsonLocationAwareFloatNode(v, this.jsonParser.currentTokenLocation()); + return new TokenStreamLocationAwareFloatNode(v, this.jsonParser.currentTokenLocation()); } @Override @@ -127,7 +127,7 @@ public ValueNode numberNode(Float v) { @Override public NumericNode numberNode(double v) { - return new JsonLocationAwareDoubleNode(v, this.jsonParser.currentTokenLocation()); + return new TokenStreamLocationAwareDoubleNode(v, this.jsonParser.currentTokenLocation()); } @Override @@ -137,47 +137,47 @@ public ValueNode numberNode(Double v) { @Override public ValueNode numberNode(BigDecimal v) { - return (v == null) ? nullNode() : new JsonLocationAwareDecimalNode(v, this.jsonParser.currentTokenLocation()); + return (v == null) ? nullNode() : new TokenStreamLocationAwareDecimalNode(v, this.jsonParser.currentTokenLocation()); } @Override public TextNode textNode(String text) { - return new JsonLocationAwareTextNode(text, this.jsonParser.currentTokenLocation()); + return new TokenStreamLocationAwareTextNode(text, this.jsonParser.currentTokenLocation()); } @Override public BinaryNode binaryNode(byte[] data) { - return new JsonLocationAwareBinaryNode(data, this.jsonParser.currentTokenLocation()); + return new TokenStreamLocationAwareBinaryNode(data, this.jsonParser.currentTokenLocation()); } @Override public BinaryNode binaryNode(byte[] data, int offset, int length) { - return new JsonLocationAwareBinaryNode(data, offset, length, this.jsonParser.currentTokenLocation()); + return new TokenStreamLocationAwareBinaryNode(data, offset, length, this.jsonParser.currentTokenLocation()); } @Override public ArrayNode arrayNode() { - return new JsonLocationAwareArrayNode(this, this.jsonParser.currentTokenLocation()); + return new TokenStreamLocationAwareArrayNode(this, this.jsonParser.currentTokenLocation()); } @Override public ArrayNode arrayNode(int capacity) { - return new JsonLocationAwareArrayNode(this, capacity, this.jsonParser.currentTokenLocation()); + return new TokenStreamLocationAwareArrayNode(this, capacity, this.jsonParser.currentTokenLocation()); } @Override public ObjectNode objectNode() { - return new JsonLocationAwareObjectNode(this, this.jsonParser.currentTokenLocation()); + return new TokenStreamLocationAwareObjectNode(this, this.jsonParser.currentTokenLocation()); } @Override public ValueNode pojoNode(Object pojo) { - return new JsonLocationAwarePOJONode(pojo, this.jsonParser.currentTokenLocation()); + return new TokenStreamLocationAwarePOJONode(pojo, this.jsonParser.currentTokenLocation()); } @Override public ValueNode rawValueNode(RawValue value) { - return new JsonLocationAwarePOJONode(value, this.jsonParser.currentTokenLocation()); + return new TokenStreamLocationAwarePOJONode(value, this.jsonParser.currentTokenLocation()); } } diff --git a/src/main/java/com/networknt/schema/serialization/node/JsonLocationAware.java b/src/main/java/com/networknt/schema/serialization/node/TokenStreamLocationAware.java similarity index 88% rename from src/main/java/com/networknt/schema/serialization/node/JsonLocationAware.java rename to src/main/java/com/networknt/schema/serialization/node/TokenStreamLocationAware.java index 5e70699d8..073970292 100644 --- a/src/main/java/com/networknt/schema/serialization/node/JsonLocationAware.java +++ b/src/main/java/com/networknt/schema/serialization/node/TokenStreamLocationAware.java @@ -20,11 +20,11 @@ /** * JsonNodes that are aware of the token location will implement this interface. */ -public interface JsonLocationAware { +public interface TokenStreamLocationAware { /** * Gets the token location. * * @return the token location */ - JsonLocation tokenLocation(); + JsonLocation tokenStreamLocation(); } diff --git a/src/main/java/com/networknt/schema/serialization/node/JsonLocationAwareArrayNode.java b/src/main/java/com/networknt/schema/serialization/node/TokenStreamLocationAwareArrayNode.java similarity index 56% rename from src/main/java/com/networknt/schema/serialization/node/JsonLocationAwareArrayNode.java rename to src/main/java/com/networknt/schema/serialization/node/TokenStreamLocationAwareArrayNode.java index 1e59f8f2f..cfa6569d2 100644 --- a/src/main/java/com/networknt/schema/serialization/node/JsonLocationAwareArrayNode.java +++ b/src/main/java/com/networknt/schema/serialization/node/TokenStreamLocationAwareArrayNode.java @@ -23,32 +23,32 @@ import com.fasterxml.jackson.databind.node.JsonNodeFactory; /** - * {@link ArrayNode} that is {@link JsonLocationAware}. + * {@link ArrayNode} that is {@link TokenStreamLocationAware}. */ -public class JsonLocationAwareArrayNode extends ArrayNode implements JsonLocationAware { +public class TokenStreamLocationAwareArrayNode extends ArrayNode implements TokenStreamLocationAware { /** * */ private static final long serialVersionUID = 1L; - private final JsonLocation tokenLocation; + private final JsonLocation tokenStreamLocation; - public JsonLocationAwareArrayNode(JsonNodeFactory nf, int capacity, JsonLocation tokenLocation) { + public TokenStreamLocationAwareArrayNode(JsonNodeFactory nf, int capacity, JsonLocation tokenStreamLocation) { super(nf, capacity); - this.tokenLocation = tokenLocation; + this.tokenStreamLocation = tokenStreamLocation; } - public JsonLocationAwareArrayNode(JsonNodeFactory nf, List children, JsonLocation tokenLocation) { + public TokenStreamLocationAwareArrayNode(JsonNodeFactory nf, List children, JsonLocation tokenStreamLocation) { super(nf, children); - this.tokenLocation = tokenLocation; + this.tokenStreamLocation = tokenStreamLocation; } - public JsonLocationAwareArrayNode(JsonNodeFactory nf, JsonLocation tokenLocation) { + public TokenStreamLocationAwareArrayNode(JsonNodeFactory nf, JsonLocation tokenStreamLocation) { super(nf); - this.tokenLocation = tokenLocation; + this.tokenStreamLocation = tokenStreamLocation; } @Override - public JsonLocation tokenLocation() { - return this.tokenLocation; + public JsonLocation tokenStreamLocation() { + return this.tokenStreamLocation; } } diff --git a/src/main/java/com/networknt/schema/serialization/node/JsonLocationAwareBigIntegerNode.java b/src/main/java/com/networknt/schema/serialization/node/TokenStreamLocationAwareBigIntegerNode.java similarity index 64% rename from src/main/java/com/networknt/schema/serialization/node/JsonLocationAwareBigIntegerNode.java rename to src/main/java/com/networknt/schema/serialization/node/TokenStreamLocationAwareBigIntegerNode.java index d1cd995fa..c3b621a98 100644 --- a/src/main/java/com/networknt/schema/serialization/node/JsonLocationAwareBigIntegerNode.java +++ b/src/main/java/com/networknt/schema/serialization/node/TokenStreamLocationAwareBigIntegerNode.java @@ -21,22 +21,22 @@ import com.fasterxml.jackson.databind.node.BigIntegerNode; /** - * {@link BigIntegerNode} that is {@link JsonLocationAware}. + * {@link BigIntegerNode} that is {@link TokenStreamLocationAware}. */ -public class JsonLocationAwareBigIntegerNode extends BigIntegerNode implements JsonLocationAware { +public class TokenStreamLocationAwareBigIntegerNode extends BigIntegerNode implements TokenStreamLocationAware { /** * */ private static final long serialVersionUID = 1L; - private final JsonLocation tokenLocation; + private final JsonLocation tokenStreamLocation; - public JsonLocationAwareBigIntegerNode(BigInteger v, JsonLocation tokenLocation) { + public TokenStreamLocationAwareBigIntegerNode(BigInteger v, JsonLocation tokenStreamLocation) { super(v); - this.tokenLocation = tokenLocation; + this.tokenStreamLocation = tokenStreamLocation; } @Override - public JsonLocation tokenLocation() { - return this.tokenLocation; + public JsonLocation tokenStreamLocation() { + return this.tokenStreamLocation; } } diff --git a/src/main/java/com/networknt/schema/serialization/node/JsonLocationAwareBinaryNode.java b/src/main/java/com/networknt/schema/serialization/node/TokenStreamLocationAwareBinaryNode.java similarity index 58% rename from src/main/java/com/networknt/schema/serialization/node/JsonLocationAwareBinaryNode.java rename to src/main/java/com/networknt/schema/serialization/node/TokenStreamLocationAwareBinaryNode.java index 04bec537a..dc0e46019 100644 --- a/src/main/java/com/networknt/schema/serialization/node/JsonLocationAwareBinaryNode.java +++ b/src/main/java/com/networknt/schema/serialization/node/TokenStreamLocationAwareBinaryNode.java @@ -19,28 +19,28 @@ import com.fasterxml.jackson.databind.node.BinaryNode; /** - * {@link BinaryNode} that is {@link JsonLocationAware}. + * {@link BinaryNode} that is {@link TokenStreamLocationAware}. */ -public class JsonLocationAwareBinaryNode extends BinaryNode implements JsonLocationAware { +public class TokenStreamLocationAwareBinaryNode extends BinaryNode implements TokenStreamLocationAware { /** * */ private static final long serialVersionUID = 1L; - private final JsonLocation tokenLocation; + private final JsonLocation tokenStreamLocation; - public JsonLocationAwareBinaryNode(byte[] data, JsonLocation tokenLocation) { + public TokenStreamLocationAwareBinaryNode(byte[] data, JsonLocation tokenStreamLocation) { super(data); - this.tokenLocation = tokenLocation; + this.tokenStreamLocation = tokenStreamLocation; } - public JsonLocationAwareBinaryNode(byte[] data, int offset, int length, JsonLocation tokenLocation) { + public TokenStreamLocationAwareBinaryNode(byte[] data, int offset, int length, JsonLocation tokenStreamLocation) { super(data, offset, length); - this.tokenLocation = tokenLocation; + this.tokenStreamLocation = tokenStreamLocation; } @Override - public JsonLocation tokenLocation() { - return this.tokenLocation; + public JsonLocation tokenStreamLocation() { + return this.tokenStreamLocation; } } diff --git a/src/main/java/com/networknt/schema/serialization/node/JsonLocationAwareBooleanNode.java b/src/main/java/com/networknt/schema/serialization/node/TokenStreamLocationAwareBooleanNode.java similarity index 64% rename from src/main/java/com/networknt/schema/serialization/node/JsonLocationAwareBooleanNode.java rename to src/main/java/com/networknt/schema/serialization/node/TokenStreamLocationAwareBooleanNode.java index 2b6fee413..867d38445 100644 --- a/src/main/java/com/networknt/schema/serialization/node/JsonLocationAwareBooleanNode.java +++ b/src/main/java/com/networknt/schema/serialization/node/TokenStreamLocationAwareBooleanNode.java @@ -19,22 +19,22 @@ import com.fasterxml.jackson.databind.node.BooleanNode; /** - * {@link BooleanNode} that is {@link JsonLocationAware}. + * {@link BooleanNode} that is {@link TokenStreamLocationAware}. */ -public class JsonLocationAwareBooleanNode extends BooleanNode implements JsonLocationAware { +public class TokenStreamLocationAwareBooleanNode extends BooleanNode implements TokenStreamLocationAware { /** * */ private static final long serialVersionUID = 1L; - private final JsonLocation tokenLocation; + private final JsonLocation tokenStreamLocation; - public JsonLocationAwareBooleanNode(boolean v, JsonLocation tokenLocation) { + public TokenStreamLocationAwareBooleanNode(boolean v, JsonLocation tokenStreamLocation) { super(v); - this.tokenLocation = tokenLocation; + this.tokenStreamLocation = tokenStreamLocation; } @Override - public JsonLocation tokenLocation() { - return this.tokenLocation; + public JsonLocation tokenStreamLocation() { + return this.tokenStreamLocation; } } diff --git a/src/main/java/com/networknt/schema/serialization/node/JsonLocationAwareDecimalNode.java b/src/main/java/com/networknt/schema/serialization/node/TokenStreamLocationAwareDecimalNode.java similarity index 64% rename from src/main/java/com/networknt/schema/serialization/node/JsonLocationAwareDecimalNode.java rename to src/main/java/com/networknt/schema/serialization/node/TokenStreamLocationAwareDecimalNode.java index f850cb4a5..5da546b1c 100644 --- a/src/main/java/com/networknt/schema/serialization/node/JsonLocationAwareDecimalNode.java +++ b/src/main/java/com/networknt/schema/serialization/node/TokenStreamLocationAwareDecimalNode.java @@ -21,22 +21,22 @@ import com.fasterxml.jackson.databind.node.DecimalNode; /** - * {@link DecimalNode} that is {@link JsonLocationAware}. + * {@link DecimalNode} that is {@link TokenStreamLocationAware}. */ -public class JsonLocationAwareDecimalNode extends DecimalNode implements JsonLocationAware { +public class TokenStreamLocationAwareDecimalNode extends DecimalNode implements TokenStreamLocationAware { /** * */ private static final long serialVersionUID = 1L; - private final JsonLocation tokenLocation; + private final JsonLocation tokenStreamLocation; - public JsonLocationAwareDecimalNode(BigDecimal v, JsonLocation tokenLocation) { + public TokenStreamLocationAwareDecimalNode(BigDecimal v, JsonLocation tokenStreamLocation) { super(v); - this.tokenLocation = tokenLocation; + this.tokenStreamLocation = tokenStreamLocation; } @Override - public JsonLocation tokenLocation() { - return this.tokenLocation; + public JsonLocation tokenStreamLocation() { + return this.tokenStreamLocation; } } diff --git a/src/main/java/com/networknt/schema/serialization/node/JsonLocationAwareDoubleNode.java b/src/main/java/com/networknt/schema/serialization/node/TokenStreamLocationAwareDoubleNode.java similarity index 64% rename from src/main/java/com/networknt/schema/serialization/node/JsonLocationAwareDoubleNode.java rename to src/main/java/com/networknt/schema/serialization/node/TokenStreamLocationAwareDoubleNode.java index 110a0836b..5c07ef536 100644 --- a/src/main/java/com/networknt/schema/serialization/node/JsonLocationAwareDoubleNode.java +++ b/src/main/java/com/networknt/schema/serialization/node/TokenStreamLocationAwareDoubleNode.java @@ -19,22 +19,22 @@ import com.fasterxml.jackson.databind.node.DoubleNode; /** - * {@link DoubleNode} that is {@link JsonLocationAware}. + * {@link DoubleNode} that is {@link TokenStreamLocationAware}. */ -public class JsonLocationAwareDoubleNode extends DoubleNode implements JsonLocationAware { +public class TokenStreamLocationAwareDoubleNode extends DoubleNode implements TokenStreamLocationAware { /** * */ private static final long serialVersionUID = 1L; - private final JsonLocation tokenLocation; + private final JsonLocation tokenStreamLocation; - public JsonLocationAwareDoubleNode(double v, JsonLocation tokenLocation) { + public TokenStreamLocationAwareDoubleNode(double v, JsonLocation tokenStreamLocation) { super(v); - this.tokenLocation = tokenLocation; + this.tokenStreamLocation = tokenStreamLocation; } @Override - public JsonLocation tokenLocation() { - return this.tokenLocation; + public JsonLocation tokenStreamLocation() { + return this.tokenStreamLocation; } } diff --git a/src/main/java/com/networknt/schema/serialization/node/JsonLocationAwareFloatNode.java b/src/main/java/com/networknt/schema/serialization/node/TokenStreamLocationAwareFloatNode.java similarity index 64% rename from src/main/java/com/networknt/schema/serialization/node/JsonLocationAwareFloatNode.java rename to src/main/java/com/networknt/schema/serialization/node/TokenStreamLocationAwareFloatNode.java index 54067ae0f..654d5d0bb 100644 --- a/src/main/java/com/networknt/schema/serialization/node/JsonLocationAwareFloatNode.java +++ b/src/main/java/com/networknt/schema/serialization/node/TokenStreamLocationAwareFloatNode.java @@ -19,22 +19,22 @@ import com.fasterxml.jackson.databind.node.FloatNode; /** - * {@link FloatNode} that is {@link JsonLocationAware}. + * {@link FloatNode} that is {@link TokenStreamLocationAware}. */ -public class JsonLocationAwareFloatNode extends FloatNode implements JsonLocationAware { +public class TokenStreamLocationAwareFloatNode extends FloatNode implements TokenStreamLocationAware { /** * */ private static final long serialVersionUID = 1L; - private final JsonLocation tokenLocation; + private final JsonLocation tokenStreamLocation; - public JsonLocationAwareFloatNode(float v, JsonLocation tokenLocation) { + public TokenStreamLocationAwareFloatNode(float v, JsonLocation tokenStreamLocation) { super(v); - this.tokenLocation = tokenLocation; + this.tokenStreamLocation = tokenStreamLocation; } @Override - public JsonLocation tokenLocation() { - return this.tokenLocation; + public JsonLocation tokenStreamLocation() { + return this.tokenStreamLocation; } } diff --git a/src/main/java/com/networknt/schema/serialization/node/JsonLocationAwareIntNode.java b/src/main/java/com/networknt/schema/serialization/node/TokenStreamLocationAwareIntNode.java similarity index 65% rename from src/main/java/com/networknt/schema/serialization/node/JsonLocationAwareIntNode.java rename to src/main/java/com/networknt/schema/serialization/node/TokenStreamLocationAwareIntNode.java index e72fd28dc..5c5e29b9d 100644 --- a/src/main/java/com/networknt/schema/serialization/node/JsonLocationAwareIntNode.java +++ b/src/main/java/com/networknt/schema/serialization/node/TokenStreamLocationAwareIntNode.java @@ -19,22 +19,22 @@ import com.fasterxml.jackson.databind.node.IntNode; /** - * {@link IntNode} that is {@link JsonLocationAware}. + * {@link IntNode} that is {@link TokenStreamLocationAware}. */ -public class JsonLocationAwareIntNode extends IntNode implements JsonLocationAware { +public class TokenStreamLocationAwareIntNode extends IntNode implements TokenStreamLocationAware { /** * */ private static final long serialVersionUID = 1L; - private final JsonLocation tokenLocation; + private final JsonLocation tokenStreamLocation; - public JsonLocationAwareIntNode(int v, JsonLocation tokenLocation) { + public TokenStreamLocationAwareIntNode(int v, JsonLocation tokenStreamLocation) { super(v); - this.tokenLocation = tokenLocation; + this.tokenStreamLocation = tokenStreamLocation; } @Override - public JsonLocation tokenLocation() { - return this.tokenLocation; + public JsonLocation tokenStreamLocation() { + return this.tokenStreamLocation; } } diff --git a/src/main/java/com/networknt/schema/serialization/node/JsonLocationAwareLongNode.java b/src/main/java/com/networknt/schema/serialization/node/TokenStreamLocationAwareLongNode.java similarity index 64% rename from src/main/java/com/networknt/schema/serialization/node/JsonLocationAwareLongNode.java rename to src/main/java/com/networknt/schema/serialization/node/TokenStreamLocationAwareLongNode.java index 0ceb5714d..5d107717f 100644 --- a/src/main/java/com/networknt/schema/serialization/node/JsonLocationAwareLongNode.java +++ b/src/main/java/com/networknt/schema/serialization/node/TokenStreamLocationAwareLongNode.java @@ -19,22 +19,22 @@ import com.fasterxml.jackson.databind.node.LongNode; /** - * {@link LongNode} that is {@link JsonLocationAware}. + * {@link LongNode} that is {@link TokenStreamLocationAware}. */ -public class JsonLocationAwareLongNode extends LongNode implements JsonLocationAware { +public class TokenStreamLocationAwareLongNode extends LongNode implements TokenStreamLocationAware { /** * */ private static final long serialVersionUID = 1L; - private final JsonLocation tokenLocation; + private final JsonLocation tokenStreamLocation; - public JsonLocationAwareLongNode(long v, JsonLocation tokenLocation) { + public TokenStreamLocationAwareLongNode(long v, JsonLocation tokenStreamLocation) { super(v); - this.tokenLocation = tokenLocation; + this.tokenStreamLocation = tokenStreamLocation; } @Override - public JsonLocation tokenLocation() { - return this.tokenLocation; + public JsonLocation tokenStreamLocation() { + return this.tokenStreamLocation; } } diff --git a/src/main/java/com/networknt/schema/serialization/node/JsonLocationAwareNullNode.java b/src/main/java/com/networknt/schema/serialization/node/TokenStreamLocationAwareNullNode.java similarity index 65% rename from src/main/java/com/networknt/schema/serialization/node/JsonLocationAwareNullNode.java rename to src/main/java/com/networknt/schema/serialization/node/TokenStreamLocationAwareNullNode.java index e73463488..329ebab3c 100644 --- a/src/main/java/com/networknt/schema/serialization/node/JsonLocationAwareNullNode.java +++ b/src/main/java/com/networknt/schema/serialization/node/TokenStreamLocationAwareNullNode.java @@ -19,22 +19,22 @@ import com.fasterxml.jackson.databind.node.NullNode; /** - * {@link NullNode} that is {@link JsonLocationAware}. + * {@link NullNode} that is {@link TokenStreamLocationAware}. */ -public class JsonLocationAwareNullNode extends NullNode implements JsonLocationAware { +public class TokenStreamLocationAwareNullNode extends NullNode implements TokenStreamLocationAware { /** * */ private static final long serialVersionUID = 1L; - private final JsonLocation tokenLocation; + private final JsonLocation tokenStreamLocation; - public JsonLocationAwareNullNode(JsonLocation tokenLocation) { + public TokenStreamLocationAwareNullNode(JsonLocation tokenStreamLocation) { super(); - this.tokenLocation = tokenLocation; + this.tokenStreamLocation = tokenStreamLocation; } @Override - public JsonLocation tokenLocation() { - return this.tokenLocation; + public JsonLocation tokenStreamLocation() { + return this.tokenStreamLocation; } } diff --git a/src/main/java/com/networknt/schema/serialization/node/JsonLocationAwareObjectNode.java b/src/main/java/com/networknt/schema/serialization/node/TokenStreamLocationAwareObjectNode.java similarity index 60% rename from src/main/java/com/networknt/schema/serialization/node/JsonLocationAwareObjectNode.java rename to src/main/java/com/networknt/schema/serialization/node/TokenStreamLocationAwareObjectNode.java index 6bf776c3a..b33c04741 100644 --- a/src/main/java/com/networknt/schema/serialization/node/JsonLocationAwareObjectNode.java +++ b/src/main/java/com/networknt/schema/serialization/node/TokenStreamLocationAwareObjectNode.java @@ -23,27 +23,27 @@ import com.fasterxml.jackson.databind.node.ObjectNode; /** - * {@link ObjectNode} that is {@link JsonLocationAware}. + * {@link ObjectNode} that is {@link TokenStreamLocationAware}. */ -public class JsonLocationAwareObjectNode extends ObjectNode implements JsonLocationAware { +public class TokenStreamLocationAwareObjectNode extends ObjectNode implements TokenStreamLocationAware { /** * */ private static final long serialVersionUID = 1L; - private final JsonLocation tokenLocation; + private final JsonLocation tokenStreamLocation; - public JsonLocationAwareObjectNode(JsonNodeFactory nc, Map children, JsonLocation tokenLocation) { + public TokenStreamLocationAwareObjectNode(JsonNodeFactory nc, Map children, JsonLocation tokenStreamLocation) { super(nc, children); - this.tokenLocation = tokenLocation; + this.tokenStreamLocation = tokenStreamLocation; } - public JsonLocationAwareObjectNode(JsonNodeFactory nc, JsonLocation tokenLocation) { + public TokenStreamLocationAwareObjectNode(JsonNodeFactory nc, JsonLocation tokenStreamLocation) { super(nc); - this.tokenLocation = tokenLocation; + this.tokenStreamLocation = tokenStreamLocation; } @Override - public JsonLocation tokenLocation() { - return this.tokenLocation; + public JsonLocation tokenStreamLocation() { + return this.tokenStreamLocation; } } diff --git a/src/main/java/com/networknt/schema/serialization/node/JsonLocationAwarePOJONode.java b/src/main/java/com/networknt/schema/serialization/node/TokenStreamLocationAwarePOJONode.java similarity index 64% rename from src/main/java/com/networknt/schema/serialization/node/JsonLocationAwarePOJONode.java rename to src/main/java/com/networknt/schema/serialization/node/TokenStreamLocationAwarePOJONode.java index 7ca728363..5d4c89cdb 100644 --- a/src/main/java/com/networknt/schema/serialization/node/JsonLocationAwarePOJONode.java +++ b/src/main/java/com/networknt/schema/serialization/node/TokenStreamLocationAwarePOJONode.java @@ -19,22 +19,22 @@ import com.fasterxml.jackson.databind.node.POJONode; /** - * {@link POJONode} that is {@link JsonLocationAware}. + * {@link POJONode} that is {@link TokenStreamLocationAware}. */ -public class JsonLocationAwarePOJONode extends POJONode implements JsonLocationAware { +public class TokenStreamLocationAwarePOJONode extends POJONode implements TokenStreamLocationAware { /** * */ private static final long serialVersionUID = 1L; - private final JsonLocation tokenLocation; + private final JsonLocation tokenStreamLocation; - public JsonLocationAwarePOJONode(Object v, JsonLocation tokenLocation) { + public TokenStreamLocationAwarePOJONode(Object v, JsonLocation tokenStreamLocation) { super(v); - this.tokenLocation = tokenLocation; + this.tokenStreamLocation = tokenStreamLocation; } @Override - public JsonLocation tokenLocation() { - return this.tokenLocation; + public JsonLocation tokenStreamLocation() { + return this.tokenStreamLocation; } } diff --git a/src/main/java/com/networknt/schema/serialization/node/JsonLocationAwareShortNode.java b/src/main/java/com/networknt/schema/serialization/node/TokenStreamLocationAwareShortNode.java similarity index 64% rename from src/main/java/com/networknt/schema/serialization/node/JsonLocationAwareShortNode.java rename to src/main/java/com/networknt/schema/serialization/node/TokenStreamLocationAwareShortNode.java index 60027c05d..64c7ad886 100644 --- a/src/main/java/com/networknt/schema/serialization/node/JsonLocationAwareShortNode.java +++ b/src/main/java/com/networknt/schema/serialization/node/TokenStreamLocationAwareShortNode.java @@ -19,22 +19,22 @@ import com.fasterxml.jackson.databind.node.ShortNode; /** - * {@link ShortNode} that is {@link JsonLocationAware}. + * {@link ShortNode} that is {@link TokenStreamLocationAware}. */ -public class JsonLocationAwareShortNode extends ShortNode implements JsonLocationAware { +public class TokenStreamLocationAwareShortNode extends ShortNode implements TokenStreamLocationAware { /** * */ private static final long serialVersionUID = 1L; - private final JsonLocation tokenLocation; + private final JsonLocation tokenStreamLocation; - public JsonLocationAwareShortNode(short v, JsonLocation tokenLocation) { + public TokenStreamLocationAwareShortNode(short v, JsonLocation tokenStreamLocation) { super(v); - this.tokenLocation = tokenLocation; + this.tokenStreamLocation = tokenStreamLocation; } @Override - public JsonLocation tokenLocation() { - return this.tokenLocation; + public JsonLocation tokenStreamLocation() { + return this.tokenStreamLocation; } } diff --git a/src/main/java/com/networknt/schema/serialization/node/JsonLocationAwareTextNode.java b/src/main/java/com/networknt/schema/serialization/node/TokenStreamLocationAwareTextNode.java similarity index 64% rename from src/main/java/com/networknt/schema/serialization/node/JsonLocationAwareTextNode.java rename to src/main/java/com/networknt/schema/serialization/node/TokenStreamLocationAwareTextNode.java index 6f3b16cec..32ebea8c1 100644 --- a/src/main/java/com/networknt/schema/serialization/node/JsonLocationAwareTextNode.java +++ b/src/main/java/com/networknt/schema/serialization/node/TokenStreamLocationAwareTextNode.java @@ -19,22 +19,22 @@ import com.fasterxml.jackson.databind.node.TextNode; /** - * {@link TextNode} that is {@link JsonLocationAware}. + * {@link TextNode} that is {@link TokenStreamLocationAware}. */ -public class JsonLocationAwareTextNode extends TextNode implements JsonLocationAware { +public class TokenStreamLocationAwareTextNode extends TextNode implements TokenStreamLocationAware { /** * */ private static final long serialVersionUID = 1L; - private final JsonLocation tokenLocation; + private final JsonLocation tokenStreamLocation; - public JsonLocationAwareTextNode(String v, JsonLocation tokenLocation) { + public TokenStreamLocationAwareTextNode(String v, JsonLocation tokenStreamLocation) { super(v); - this.tokenLocation = tokenLocation; + this.tokenStreamLocation = tokenStreamLocation; } @Override - public JsonLocation tokenLocation() { - return this.tokenLocation; + public JsonLocation tokenStreamLocation() { + return this.tokenStreamLocation; } } diff --git a/src/main/java/com/networknt/schema/utils/CachingSupplier.java b/src/main/java/com/networknt/schema/utils/CachingSupplier.java index 0f43f9478..bd64d3b97 100644 --- a/src/main/java/com/networknt/schema/utils/CachingSupplier.java +++ b/src/main/java/com/networknt/schema/utils/CachingSupplier.java @@ -22,22 +22,23 @@ * {@link Supplier} that caches the value. *

* This is not threadsafe. - * - * @param the type of results supplied by this supplier + * + * @param the type of results cached by this supplier */ public class CachingSupplier implements Supplier { - private final Supplier delegate; - private T cached = null; + private Supplier delegate; + private T cache = null; - public CachingSupplier(Supplier supplier) { - this.delegate = supplier; + public CachingSupplier(Supplier delegate) { + this.delegate = delegate; } @Override public T get() { - if (this.cached == null) { - this.cached = this.delegate.get(); + if (this.cache == null && this.delegate != null) { + this.cache = this.delegate.get(); + this.delegate = null; } - return this.cached; + return this.cache; } } diff --git a/src/main/java/com/networknt/schema/utils/JsonNodeUtil.java b/src/main/java/com/networknt/schema/utils/JsonNodeTypes.java similarity index 53% rename from src/main/java/com/networknt/schema/utils/JsonNodeUtil.java rename to src/main/java/com/networknt/schema/utils/JsonNodeTypes.java index df2b91bc3..cdd9bd818 100644 --- a/src/main/java/com/networknt/schema/utils/JsonNodeUtil.java +++ b/src/main/java/com/networknt/schema/utils/JsonNodeTypes.java @@ -1,72 +1,26 @@ package com.networknt.schema.utils; -import java.util.ArrayList; -import java.util.Collection; - import com.fasterxml.jackson.databind.JsonNode; -import com.networknt.schema.JsonSchema; -import com.networknt.schema.JsonType; -import com.networknt.schema.PathType; -import com.networknt.schema.SchemaValidatorsConfig; -import com.networknt.schema.SpecVersion.VersionFlag; -import com.networknt.schema.TypeFactory; -import com.networknt.schema.ValidationContext; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaContext; +import com.networknt.schema.SchemaRegistryConfig; +import com.networknt.schema.SpecificationVersion; -public class JsonNodeUtil { - private static final long V6_VALUE = VersionFlag.V6.getVersionFlagValue(); +public class JsonNodeTypes { + private static final long V6_VALUE = SpecificationVersion.DRAFT_6.getOrder(); private static final String TYPE = "type"; private static final String ENUM = "enum"; private static final String REF = "$ref"; private static final String NULLABLE = "nullable"; - public static Collection allPaths(PathType pathType, String root, JsonNode node) { - Collection collector = new ArrayList<>(); - visitNode(pathType, root, node, collector); - return collector; - } - - private static void visitNode(PathType pathType, String root, JsonNode node, Collection collector) { - if (node.isObject()) { - visitObject(pathType, root, node, collector); - } else if (node.isArray()) { - visitArray(pathType, root, node, collector); - } - } - - private static void visitArray(PathType pathType, String root, JsonNode node, Collection collector) { - int size = node.size(); - for (int i = 0; i < size; ++i) { - String path = pathType.append(root, i); - collector.add(path); - visitNode(pathType, path, node.get(i), collector); - } - } - - private static void visitObject(PathType pathType, String root, JsonNode node, Collection collector) { - node.fields().forEachRemaining(entry -> { - String path = pathType.append(root, entry.getKey()); - collector.add(path); - visitNode(pathType, path, entry.getValue(), collector); - }); - } - public static boolean isNodeNullable(JsonNode schema){ JsonNode nullable = schema.get(NULLABLE); return nullable != null && nullable.asBoolean(); } - //Check to see if a JsonNode is nullable with checking the isHandleNullableField - public static boolean isNodeNullable(JsonNode schema, SchemaValidatorsConfig config){ - // check if the parent schema declares the fields as nullable - if (config.isNullableKeywordEnabled()) { - return isNodeNullable(schema); - } - return false; - } - - public static boolean equalsToSchemaType(JsonNode node, JsonType schemaType, JsonSchema parentSchema, ValidationContext validationContext) { - SchemaValidatorsConfig config = validationContext.getConfig(); + public static boolean equalsToSchemaType(JsonNode node, JsonType schemaType, Schema parentSchema, SchemaContext schemaContext) { + SchemaRegistryConfig config = schemaContext.getSchemaRegistryConfig(); JsonType nodeType = TypeFactory.getValueNodeType(node, config); // in the case that node type is not the same as schema type, try to convert node to the // same type of schema. In REST API, query parameters, path parameters and headers are all @@ -79,15 +33,15 @@ public static boolean equalsToSchemaType(JsonNode node, JsonType schemaType, Jso if (schemaType == JsonType.NUMBER && nodeType == JsonType.INTEGER) { return true; } - if (schemaType == JsonType.INTEGER && nodeType == JsonType.NUMBER && node.canConvertToExactIntegral() && V6_VALUE <= detectVersion(validationContext)) { + if (schemaType == JsonType.INTEGER && nodeType == JsonType.NUMBER && node.canConvertToExactIntegral() && V6_VALUE <= detectVersion(schemaContext)) { return true; } if (nodeType == JsonType.NULL) { - if (parentSchema != null && config.isNullableKeywordEnabled()) { - JsonSchema grandParentSchema = parentSchema.getParentSchema(); - if (grandParentSchema != null && JsonNodeUtil.isNodeNullable(grandParentSchema.getSchemaNode()) - || JsonNodeUtil.isNodeNullable(parentSchema.getSchemaNode())) { + if (parentSchema != null && schemaContext.isNullableKeywordEnabled()) { + Schema grandParentSchema = parentSchema.getParentSchema(); + if (grandParentSchema != null && JsonNodeTypes.isNodeNullable(grandParentSchema.getSchemaNode()) + || JsonNodeTypes.isNodeNullable(parentSchema.getSchemaNode())) { return true; } } @@ -95,7 +49,7 @@ public static boolean equalsToSchemaType(JsonNode node, JsonType schemaType, Jso // Skip the type validation when the schema is an enum object schema. Since the current type // of node itself can be used for type validation. - if (isEnumObjectSchema(parentSchema)) { + if (isEnumObjectSchema(parentSchema) && !config.isStrict("type", Boolean.TRUE)) { return true; } if (config != null && config.isTypeLoose()) { @@ -105,11 +59,11 @@ public static boolean equalsToSchemaType(JsonNode node, JsonType schemaType, Jso } if (nodeType == JsonType.STRING) { if (schemaType == JsonType.INTEGER) { - return StringChecker.isInteger(node.textValue()); + return Strings.isInteger(node.textValue()); } else if (schemaType == JsonType.BOOLEAN) { - return StringChecker.isBoolean(node.textValue()); + return Strings.isBoolean(node.textValue()); } else if (schemaType == JsonType.NUMBER) { - return StringChecker.isNumeric(node.textValue()); + return Strings.isNumeric(node.textValue()); } } } @@ -119,8 +73,8 @@ public static boolean equalsToSchemaType(JsonNode node, JsonType schemaType, Jso return true; } - private static long detectVersion(ValidationContext validationContext) { - return validationContext.activeDialect().orElse(VersionFlag.V4).getVersionFlagValue(); + private static long detectVersion(SchemaContext schemaContext) { + return schemaContext.getDialect().getSpecificationVersion().getOrder(); } /** @@ -131,18 +85,18 @@ private static long detectVersion(ValidationContext validationContext) { * @param config the SchemaValidatorsConfig to depend on * @return boolean to indicate if it is a number */ - public static boolean isNumber(JsonNode node, SchemaValidatorsConfig config) { + public static boolean isNumber(JsonNode node, SchemaRegistryConfig config) { if (node.isNumber()) { return true; } else if (config.isTypeLoose()) { if (TypeFactory.getValueNodeType(node, config) == JsonType.STRING) { - return StringChecker.isNumeric(node.textValue()); + return Strings.isNumeric(node.textValue()); } } return false; } - private static boolean isEnumObjectSchema(JsonSchema jsonSchema) { + private static boolean isEnumObjectSchema(Schema jsonSchema) { // There are three conditions for enum object schema // 1. The current schema contains key "type", and the value is object // 2. The current schema contains key "enum", and the value is an array diff --git a/src/main/java/com/networknt/schema/utils/JsonNodes.java b/src/main/java/com/networknt/schema/utils/JsonNodes.java index 3bfd9aa6d..e0e76d17c 100644 --- a/src/main/java/com/networknt/schema/utils/JsonNodes.java +++ b/src/main/java/com/networknt/schema/utils/JsonNodes.java @@ -25,8 +25,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectReader; import com.fasterxml.jackson.databind.node.JsonNodeFactory; -import com.networknt.schema.JsonNodePath; -import com.networknt.schema.serialization.node.JsonLocationAware; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.serialization.node.TokenStreamLocationAware; import com.networknt.schema.serialization.node.JsonNodeFactoryFactory; /** @@ -42,7 +42,7 @@ public class JsonNodes { * @return the node found at the path or null */ @SuppressWarnings("unchecked") - public static T get(JsonNode node, JsonNodePath path) { + public static T get(JsonNode node, NodePath path) { int nameCount = path.getNameCount(); JsonNode current = node; for (int x = 0; x < nameCount; x++) { @@ -118,14 +118,14 @@ public static JsonNode readTree(ObjectMapper objectMapper, InputStream inputStre } /** - * Gets the token location of the {@link JsonNode} that implements {@link JsonLocationAware}. + * Gets the token location of the {@link JsonNode} that implements {@link TokenStreamLocationAware}. * * @param jsonNode the node * @return the JsonLocation */ - public static JsonLocation tokenLocationOf(JsonNode jsonNode) { - if (jsonNode instanceof JsonLocationAware) { - return ((JsonLocationAware) jsonNode).tokenLocation(); + public static JsonLocation tokenStreamLocationOf(JsonNode jsonNode) { + if (jsonNode instanceof TokenStreamLocationAware) { + return ((TokenStreamLocationAware) jsonNode).tokenStreamLocation(); } throw new IllegalArgumentException("JsonNode does not contain the location information."); } diff --git a/src/main/java/com/networknt/schema/JsonType.java b/src/main/java/com/networknt/schema/utils/JsonType.java similarity index 92% rename from src/main/java/com/networknt/schema/JsonType.java rename to src/main/java/com/networknt/schema/utils/JsonType.java index ddf933670..709001a3b 100644 --- a/src/main/java/com/networknt/schema/JsonType.java +++ b/src/main/java/com/networknt/schema/utils/JsonType.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.utils; /** * Indicates the type. diff --git a/src/main/java/com/networknt/schema/utils/JsonSchemaRefs.java b/src/main/java/com/networknt/schema/utils/SchemaRefs.java similarity index 70% rename from src/main/java/com/networknt/schema/utils/JsonSchemaRefs.java rename to src/main/java/com/networknt/schema/utils/SchemaRefs.java index 9a6231fd4..fa8d8ff14 100644 --- a/src/main/java/com/networknt/schema/utils/JsonSchemaRefs.java +++ b/src/main/java/com/networknt/schema/utils/SchemaRefs.java @@ -15,17 +15,17 @@ */ package com.networknt.schema.utils; -import com.networknt.schema.DynamicRefValidator; -import com.networknt.schema.JsonSchema; -import com.networknt.schema.JsonSchemaRef; -import com.networknt.schema.JsonValidator; -import com.networknt.schema.RecursiveRefValidator; -import com.networknt.schema.RefValidator; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaRef; +import com.networknt.schema.keyword.DynamicRefValidator; +import com.networknt.schema.keyword.KeywordValidator; +import com.networknt.schema.keyword.RecursiveRefValidator; +import com.networknt.schema.keyword.RefValidator; /** - * Utility methods for JsonSchemaRef. + * Utility methods for SchemaRef. */ -public class JsonSchemaRefs { +public class SchemaRefs { /** * Gets the ref. @@ -33,8 +33,8 @@ public class JsonSchemaRefs { * @param schema the schema * @return the ref */ - public static JsonSchemaRef from(JsonSchema schema) { - for (JsonValidator validator : schema.getValidators()) { + public static SchemaRef from(Schema schema) { + for (KeywordValidator validator : schema.getValidators()) { if (validator instanceof RefValidator) { return ((RefValidator) validator).getSchemaRef(); } else if (validator instanceof DynamicRefValidator) { diff --git a/src/main/java/com/networknt/schema/utils/SetView.java b/src/main/java/com/networknt/schema/utils/SetView.java deleted file mode 100644 index a7385f02a..000000000 --- a/src/main/java/com/networknt/schema/utils/SetView.java +++ /dev/null @@ -1,204 +0,0 @@ -package com.networknt.schema.utils; - -import java.lang.reflect.Array; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.Objects; -import java.util.Set; - -/** - * View of a list of sets. - *

- * This is used for performance to reduce copies but breaks the semantics of the - * set where the elements must all be unique. - * - * @param the type contains in the set - */ -public class SetView implements Set { - private final List> sets = new ArrayList<>(); - - /** - * Adds a set to the view. - * - * @param set to add to the view - * @return the view - */ - public SetView union(Set set) { - if (set != null && !set.isEmpty()) { - this.sets.add(set); - } - return this; - } - - @Override - public int size() { - int size = 0; - for (Set set : sets) { - size += set.size(); - } - return size; - } - - @Override - public boolean isEmpty() { - return sets.isEmpty(); - } - - @Override - public boolean contains(Object o) { - for (Set set : sets) { - if (set.contains(o)) { - return true; - } - } - return false; - } - - @Override - public Iterator iterator() { - return new SetViewIterator<>(this); - } - - @Override - public Object[] toArray() { - int size = size(); - Object[] result = new Object[size]; - Iterator iterator = iterator(); - for (int x = 0; x < size; x++) { - result[x] = iterator.hasNext() ? iterator.next() : null; - } - return result; - } - - @SuppressWarnings("unchecked") - @Override - public T[] toArray(T[] a) { - int size = size(); - T[] result = size <= a.length ? a : (T[]) Array.newInstance(a.getClass().getComponentType(), size); - Iterator iterator = iterator(); - for (int x = 0; x < size; x++) { - result[x] = iterator.hasNext() ? (T) iterator.next() : null; - } - return result; - } - - @Override - public boolean containsAll(Collection c) { - for (Object e : c) { - if (!contains(e)) { - return false; - } - } - return true; - } - - @Override - public boolean add(E e) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean remove(Object o) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean addAll(Collection coll) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean removeAll(Collection coll) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean retainAll(Collection coll) { - throw new UnsupportedOperationException(); - } - - @Override - public void clear() { - throw new UnsupportedOperationException(); - } - - /** - * Iterator. - * - * @param the type contains in the set - */ - public static class SetViewIterator implements Iterator { - private Iterator> sets = null; - private Iterator current = null; - - public SetViewIterator(SetView view) { - this.sets = view.sets.iterator(); - if (this.sets.hasNext()) { - this.current = this.sets.next().iterator(); - } - } - - @Override - public boolean hasNext() { - if (this.current.hasNext()) { - return true; - } - while (this.sets.hasNext()) { - this.current = this.sets.next().iterator(); - if (this.current.hasNext()) { - return true; - } - } - return false; - } - - @Override - public E next() { - return this.current.next(); - } - } - - @Override - public int hashCode() { - return Objects.hash(sets); - } - - @Override - public boolean equals(Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof Set)) { - return false; - } - Collection collection = (Collection) obj; - if (collection.size() != size()) { - return false; - } - try { - return containsAll(collection); - } catch (ClassCastException ignore) { - return false; - } catch (NullPointerException ignore) { - return false; - } - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append('['); - Iterator iterator = iterator(); - if (iterator.hasNext()) { - builder.append(iterator.next().toString()); - } - while (iterator.hasNext()) { - builder.append(", "); - builder.append(iterator.next().toString()); - } - builder.append(']'); - return builder.toString(); - } -} diff --git a/src/main/java/com/networknt/schema/utils/StringUtils.java b/src/main/java/com/networknt/schema/utils/StringUtils.java deleted file mode 100644 index 230f92c36..000000000 --- a/src/main/java/com/networknt/schema/utils/StringUtils.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2020 Network New Technologies Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.networknt.schema.utils; - -public final class StringUtils { - - private StringUtils() { - } - - public static boolean isBlank(String s) { - return null == s || s.trim().isEmpty(); - } - - public static boolean isNotBlank(String s) { - return null != s && !s.trim().isEmpty(); - } - -} diff --git a/src/main/java/com/networknt/schema/utils/StringChecker.java b/src/main/java/com/networknt/schema/utils/Strings.java similarity index 53% rename from src/main/java/com/networknt/schema/utils/StringChecker.java rename to src/main/java/com/networknt/schema/utils/Strings.java index 4ba6388bf..0858655a3 100644 --- a/src/main/java/com/networknt/schema/utils/StringChecker.java +++ b/src/main/java/com/networknt/schema/utils/Strings.java @@ -1,7 +1,25 @@ -package com.networknt.schema.utils; +/* + * Copyright (c) 2020 Network New Technologies Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ -public class StringChecker { +package com.networknt.schema.utils; +/** + * Utility methods for working with Strings. + */ +public final class Strings { private static final char CHAR_0 = '0'; private static final char CHAR_1 = '1'; private static final char CHAR_9 = '9'; @@ -11,22 +29,25 @@ public class StringChecker { private static final char CHAR_E = 'E'; private static final char CHAR_e = 'e'; - public static boolean isInteger(String str) { - if (str == null || str.isEmpty()) { + private Strings() { + } + + public static boolean isInteger(String string) { + if (string == null || string.isEmpty()) { return false; } // all code below could be replaced with //return str.matrch("[-+]?(?:0|[1-9]\\d*)") int i = 0; - if (str.charAt(0) == '-' || str.charAt(0) == '+') { - if (str.length() == 1) { + if (string.charAt(0) == '-' || string.charAt(0) == '+') { + if (string.length() == 1) { return false; } i = 1; } - for (; i < str.length(); i++) { - char c = str.charAt(i); + for (; i < string.length(); i++) { + char c = string.charAt(i); if (c < '0' || c > '9') { return false; } @@ -34,40 +55,40 @@ public static boolean isInteger(String str) { return true; } - public static boolean isBoolean(String s) { - return "true".equals(s) || "false".equals(s); + public static boolean isBoolean(String string) { + return "true".equals(string) || "false".equals(string); } - public static boolean isNumeric(String str) { - if (str == null || str.isEmpty()) { + public static boolean isNumeric(String string) { + if (string == null || string.isEmpty()) { return false; } // all code below could be replaced with //return str.matrch("[-+]?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?") int i = 0; - int len = str.length(); + int len = string.length(); - if (str.charAt(i) == MINUS || str.charAt(i) == PLUS) { - if (str.length() == 1) { + if (string.charAt(i) == MINUS || string.charAt(i) == PLUS) { + if (string.length() == 1) { return false; } i = 1; } - char character = str.charAt(i++); + char character = string.charAt(i++); if (character == CHAR_0) { // TODO: if leading zeros are supported (counter to JSON spec) handle it here if (i < len) { - character = str.charAt(i++); + character = string.charAt(i++); if (character != DOT && character != CHAR_E && character != CHAR_e) { return false; } } } else if (CHAR_1 <= character && character <= CHAR_9) { while (i < len && CHAR_0 <= character && character <= CHAR_9) { - character = str.charAt(i++); + character = string.charAt(i++); } } else { return false; @@ -77,9 +98,9 @@ public static boolean isNumeric(String str) { if (i >= len) { return false; } - character = str.charAt(i++); + character = string.charAt(i++); while (i < len && CHAR_0 <= character && character <= CHAR_9) { - character = str.charAt(i++); + character = string.charAt(i++); } } @@ -87,18 +108,22 @@ public static boolean isNumeric(String str) { if (i >= len) { return false; } - character = str.charAt(i++); + character = string.charAt(i++); if (character == PLUS || character == MINUS) { if (i >= len) { return false; } - character = str.charAt(i++); + character = string.charAt(i++); } while (i < len && CHAR_0 <= character && character <= CHAR_9) { - character = str.charAt(i++); + character = string.charAt(i++); } } return i >= len && (CHAR_0 <= character && character <= CHAR_9); } + + public static boolean isBlank(String string) { + return null == string || string.trim().isEmpty(); + } } diff --git a/src/main/java/com/networknt/schema/CachedSupplier.java b/src/main/java/com/networknt/schema/utils/ThreadSafeCachingSupplier.java similarity index 78% rename from src/main/java/com/networknt/schema/CachedSupplier.java rename to src/main/java/com/networknt/schema/utils/ThreadSafeCachingSupplier.java index 4411bdd05..d4a9c1f63 100644 --- a/src/main/java/com/networknt/schema/CachedSupplier.java +++ b/src/main/java/com/networknt/schema/utils/ThreadSafeCachingSupplier.java @@ -13,20 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.utils; import java.util.function.Supplier; /** - * Supplier that caches the output. + * {@link Supplier} that caches the value. * - * @param the type cached + * @param the type of results cached by this supplier */ -public class CachedSupplier implements Supplier { +public class ThreadSafeCachingSupplier implements Supplier { private volatile Supplier delegate; private volatile T cache = null; - public CachedSupplier(Supplier delegate) { + public ThreadSafeCachingSupplier(Supplier delegate) { this.delegate = delegate; } diff --git a/src/main/java/com/networknt/schema/TypeFactory.java b/src/main/java/com/networknt/schema/utils/TypeFactory.java similarity index 93% rename from src/main/java/com/networknt/schema/TypeFactory.java rename to src/main/java/com/networknt/schema/utils/TypeFactory.java index cb986053d..ec2808c0c 100644 --- a/src/main/java/com/networknt/schema/TypeFactory.java +++ b/src/main/java/com/networknt/schema/utils/TypeFactory.java @@ -14,10 +14,11 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.utils; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.JsonNodeType; +import com.networknt.schema.SchemaRegistryConfig; /** * Type factory. @@ -74,7 +75,7 @@ public static JsonType getSchemaNodeType(JsonNode node) { * @param config the config * @return the json type */ - public static JsonType getValueNodeType(JsonNode node, SchemaValidatorsConfig config) { + public static JsonType getValueNodeType(JsonNode node, SchemaRegistryConfig config) { if (node == null) { // This returns JsonType.UNKNOWN to be consistent with the behavior when // JsonNodeType.MISSING diff --git a/src/main/java/com/networknt/schema/vocabulary/Vocabularies.java b/src/main/java/com/networknt/schema/vocabulary/Vocabularies.java new file mode 100644 index 000000000..f54d1e2c4 --- /dev/null +++ b/src/main/java/com/networknt/schema/vocabulary/Vocabularies.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.networknt.schema.vocabulary; + +import java.util.HashMap; +import java.util.Map; + +/** + * Vocabularies. + */ +public class Vocabularies { + private static final Map VALUES; + + static { + Map mapping = new HashMap<>(); + mapping.put(Vocabulary.DRAFT_2019_09_CORE.getId(), Vocabulary.DRAFT_2019_09_CORE); + mapping.put(Vocabulary.DRAFT_2019_09_APPLICATOR.getId(), Vocabulary.DRAFT_2019_09_APPLICATOR); + mapping.put(Vocabulary.DRAFT_2019_09_VALIDATION.getId(), Vocabulary.DRAFT_2019_09_VALIDATION); + mapping.put(Vocabulary.DRAFT_2019_09_META_DATA.getId(), Vocabulary.DRAFT_2019_09_META_DATA); + mapping.put(Vocabulary.DRAFT_2019_09_FORMAT.getId(), Vocabulary.DRAFT_2019_09_FORMAT); + mapping.put(Vocabulary.DRAFT_2019_09_CONTENT.getId(), Vocabulary.DRAFT_2019_09_CONTENT); + + mapping.put(Vocabulary.DRAFT_2020_12_CORE.getId(), Vocabulary.DRAFT_2020_12_CORE); + mapping.put(Vocabulary.DRAFT_2020_12_APPLICATOR.getId(), Vocabulary.DRAFT_2020_12_APPLICATOR); + mapping.put(Vocabulary.DRAFT_2020_12_UNEVALUATED.getId(), Vocabulary.DRAFT_2020_12_UNEVALUATED); + mapping.put(Vocabulary.DRAFT_2020_12_VALIDATION.getId(), Vocabulary.DRAFT_2020_12_VALIDATION); + mapping.put(Vocabulary.DRAFT_2020_12_META_DATA.getId(), Vocabulary.DRAFT_2020_12_META_DATA); + mapping.put(Vocabulary.DRAFT_2020_12_FORMAT_ANNOTATION.getId(), Vocabulary.DRAFT_2020_12_FORMAT_ANNOTATION); + mapping.put(Vocabulary.DRAFT_2020_12_FORMAT_ASSERTION.getId(), Vocabulary.DRAFT_2020_12_FORMAT_ASSERTION); + mapping.put(Vocabulary.DRAFT_2020_12_CONTENT.getId(), Vocabulary.DRAFT_2020_12_CONTENT); + + mapping.put(Vocabulary.OPENAPI_3_1_BASE.getId(), Vocabulary.OPENAPI_3_1_BASE); + + VALUES = mapping; + } + + /** + * Gets the vocabulary given its uri. + * + * @param uri the vocabulary + * @return the vocabulary + */ + public static Vocabulary getVocabulary(String uri) { + return VALUES.get(uri); + } +} diff --git a/src/main/java/com/networknt/schema/vocabulary/Vocabulary.java b/src/main/java/com/networknt/schema/vocabulary/Vocabulary.java new file mode 100644 index 000000000..1505b9016 --- /dev/null +++ b/src/main/java/com/networknt/schema/vocabulary/Vocabulary.java @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.networknt.schema.vocabulary; + +import java.util.Arrays; +import java.util.LinkedHashSet; +import java.util.Objects; +import java.util.Set; + +import com.networknt.schema.keyword.AnnotationKeyword; +import com.networknt.schema.keyword.Keyword; +import com.networknt.schema.keyword.NonValidationKeyword; +import com.networknt.schema.keyword.KeywordType; + +/** + * Represents a vocabulary in meta-schema. + *

+ * This contains the id and the keywords in the vocabulary. + */ +public class Vocabulary { + + // 2019-09 + public static final Vocabulary DRAFT_2019_09_CORE = new Vocabulary("https://json-schema.org/draft/2019-09/vocab/core", + new NonValidationKeyword("$id"), new NonValidationKeyword("$schema"), new NonValidationKeyword("$anchor"), + KeywordType.REF, KeywordType.RECURSIVE_REF, new NonValidationKeyword("$recursiveAnchor"), + new NonValidationKeyword("$vocabulary"), new NonValidationKeyword("$comment"), + new NonValidationKeyword("$defs")); + public static final Vocabulary DRAFT_2019_09_APPLICATOR = new Vocabulary( + "https://json-schema.org/draft/2019-09/vocab/applicator", new NonValidationKeyword("additionalItems"), + KeywordType.UNEVALUATED_ITEMS, KeywordType.ITEMS_LEGACY, KeywordType.CONTAINS, + KeywordType.ADDITIONAL_PROPERTIES, KeywordType.UNEVALUATED_PROPERTIES, + KeywordType.PROPERTIES, KeywordType.PATTERN_PROPERTIES, KeywordType.DEPENDENT_SCHEMAS, + KeywordType.PROPERTY_NAMES, KeywordType.IF_THEN_ELSE, new NonValidationKeyword("then"), + new NonValidationKeyword("else"), KeywordType.ALL_OF, KeywordType.ANY_OF, + KeywordType.ONE_OF, KeywordType.NOT); + public static final Vocabulary DRAFT_2019_09_VALIDATION = new Vocabulary( + "https://json-schema.org/draft/2019-09/vocab/validation", KeywordType.MULTIPLE_OF, + KeywordType.MAXIMUM, KeywordType.EXCLUSIVE_MAXIMUM, KeywordType.MINIMUM, + KeywordType.EXCLUSIVE_MINIMUM, KeywordType.MAX_LENGTH, KeywordType.MIN_LENGTH, + KeywordType.PATTERN, KeywordType.MAX_ITEMS, KeywordType.MIN_ITEMS, + KeywordType.UNIQUE_ITEMS, KeywordType.MAX_CONTAINS, KeywordType.MIN_CONTAINS, + KeywordType.MAX_PROPERTIES, KeywordType.MIN_PROPERTIES, KeywordType.REQUIRED, + KeywordType.DEPENDENT_REQUIRED, KeywordType.CONST, KeywordType.ENUM, + KeywordType.TYPE); + public static final Vocabulary DRAFT_2019_09_META_DATA = new Vocabulary( + "https://json-schema.org/draft/2019-09/vocab/meta-data", new AnnotationKeyword("title"), + new AnnotationKeyword("description"), new AnnotationKeyword("default"), new AnnotationKeyword("deprecated"), + KeywordType.READ_ONLY, KeywordType.WRITE_ONLY, new AnnotationKeyword("examples")); + public static final Vocabulary DRAFT_2019_09_FORMAT = new Vocabulary("https://json-schema.org/draft/2019-09/vocab/format", + KeywordType.FORMAT); + public static final Vocabulary DRAFT_2019_09_CONTENT = new Vocabulary( + "https://json-schema.org/draft/2019-09/vocab/content", new AnnotationKeyword("contentMediaType"), + new AnnotationKeyword("contentEncoding"), new AnnotationKeyword("contentSchema")); + + // 2020-12 + public static final Vocabulary DRAFT_2020_12_CORE = new Vocabulary("https://json-schema.org/draft/2020-12/vocab/core", + new NonValidationKeyword("$id"), new NonValidationKeyword("$schema"), KeywordType.REF, + new NonValidationKeyword("$anchor"), KeywordType.DYNAMIC_REF, + new NonValidationKeyword("$dynamicAnchor"), new NonValidationKeyword("$vocabulary"), + new NonValidationKeyword("$comment"), new NonValidationKeyword("$defs")); + public static final Vocabulary DRAFT_2020_12_APPLICATOR = new Vocabulary( + "https://json-schema.org/draft/2020-12/vocab/applicator", KeywordType.PREFIX_ITEMS, + KeywordType.ITEMS, KeywordType.CONTAINS, KeywordType.ADDITIONAL_PROPERTIES, + KeywordType.PROPERTIES, KeywordType.PATTERN_PROPERTIES, KeywordType.DEPENDENT_SCHEMAS, + KeywordType.PROPERTY_NAMES, KeywordType.IF_THEN_ELSE, new NonValidationKeyword("then"), + new NonValidationKeyword("else"), KeywordType.ALL_OF, KeywordType.ANY_OF, + KeywordType.ONE_OF, KeywordType.NOT); + public static final Vocabulary DRAFT_2020_12_UNEVALUATED = new Vocabulary( + "https://json-schema.org/draft/2020-12/vocab/unevaluated", KeywordType.UNEVALUATED_ITEMS, + KeywordType.UNEVALUATED_PROPERTIES); + public static final Vocabulary DRAFT_2020_12_VALIDATION = new Vocabulary( + "https://json-schema.org/draft/2020-12/vocab/validation", KeywordType.TYPE, KeywordType.CONST, + KeywordType.ENUM, KeywordType.MULTIPLE_OF, KeywordType.MAXIMUM, + KeywordType.EXCLUSIVE_MAXIMUM, KeywordType.MINIMUM, KeywordType.EXCLUSIVE_MINIMUM, + KeywordType.MAX_LENGTH, KeywordType.MIN_LENGTH, KeywordType.PATTERN, + KeywordType.MAX_ITEMS, KeywordType.MIN_ITEMS, KeywordType.UNIQUE_ITEMS, + KeywordType.MAX_CONTAINS, KeywordType.MIN_CONTAINS, KeywordType.MAX_PROPERTIES, + KeywordType.MIN_PROPERTIES, KeywordType.REQUIRED, KeywordType.DEPENDENT_REQUIRED); + public static final Vocabulary DRAFT_2020_12_META_DATA = new Vocabulary( + "https://json-schema.org/draft/2020-12/vocab/meta-data", new AnnotationKeyword("title"), + new AnnotationKeyword("description"), new AnnotationKeyword("default"), new AnnotationKeyword("deprecated"), + KeywordType.READ_ONLY, KeywordType.WRITE_ONLY, new AnnotationKeyword("examples")); + public static final Vocabulary DRAFT_2020_12_FORMAT_ANNOTATION = new Vocabulary( + "https://json-schema.org/draft/2020-12/vocab/format-annotation", KeywordType.FORMAT); + public static final Vocabulary DRAFT_2020_12_FORMAT_ASSERTION = new Vocabulary( + "https://json-schema.org/draft/2020-12/vocab/format-assertion", KeywordType.FORMAT); + public static final Vocabulary DRAFT_2020_12_CONTENT = new Vocabulary( + "https://json-schema.org/draft/2020-12/vocab/content", new AnnotationKeyword("contentEncoding"), + new AnnotationKeyword("contentMediaType"), new AnnotationKeyword("contentSchema")); + + // OpenAPI 3.1 + public static final Vocabulary OPENAPI_3_1_BASE = new Vocabulary("https://spec.openapis.org/oas/3.1/vocab/base", + new AnnotationKeyword("example"), KeywordType.DISCRIMINATOR, new AnnotationKeyword("externalDocs"), + new AnnotationKeyword("xml")); + + private final String id; + private final Set keywords; + + /** + * Constructor. + * + * @param id the id + * @param keywords the keywords + */ + public Vocabulary(String id, Keyword... keywords) { + this.id = id; + this.keywords = new LinkedHashSet<>(); + this.keywords.addAll(Arrays.asList(keywords)); + } + + /** + * The id of the vocabulary. + * + * @return the id + */ + public String getId() { + return id; + } + + /** + * The keywords in the vocabulary. + * + * @return the keywords + */ + public Set getKeywords() { + return keywords; + } + + @Override + public int hashCode() { + return Objects.hash(id, keywords); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Vocabulary other = (Vocabulary) obj; + return Objects.equals(id, other.id) && Objects.equals(keywords, other.keywords); + } + + @Override + public String toString() { + return "Vocabulary [id=" + id + ", keywords=" + keywords + "]"; + } + +} diff --git a/src/main/java/com/networknt/schema/VocabularyFactory.java b/src/main/java/com/networknt/schema/vocabulary/VocabularyRegistry.java similarity index 70% rename from src/main/java/com/networknt/schema/VocabularyFactory.java rename to src/main/java/com/networknt/schema/vocabulary/VocabularyRegistry.java index a451c0d3a..e712c652f 100644 --- a/src/main/java/com/networknt/schema/VocabularyFactory.java +++ b/src/main/java/com/networknt/schema/vocabulary/VocabularyRegistry.java @@ -13,18 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.vocabulary; /** - * Factory for {@link Vocabulary}. + * Registry for {@link Vocabulary}. */ @FunctionalInterface -public interface VocabularyFactory { +public interface VocabularyRegistry { /** - * Gets the vocabulary given the vocabulary iri. + * Gets the vocabulary given the vocabulary id. * - * @param iri the vocabulary iri + * @param id the vocabulary id which is an iri * @return the vocabulary */ - Vocabulary getVocabulary(String iri); + Vocabulary getVocabulary(String id); } diff --git a/src/main/java/com/networknt/schema/walk/AbstractWalkListenerRunner.java b/src/main/java/com/networknt/schema/walk/AbstractWalkListenerRunner.java index cb0d197a9..b7ef458f2 100644 --- a/src/main/java/com/networknt/schema/walk/AbstractWalkListenerRunner.java +++ b/src/main/java/com/networknt/schema/walk/AbstractWalkListenerRunner.java @@ -2,26 +2,26 @@ import com.fasterxml.jackson.databind.JsonNode; import com.networknt.schema.ExecutionContext; -import com.networknt.schema.JsonNodePath; -import com.networknt.schema.JsonSchema; -import com.networknt.schema.JsonValidator; -import com.networknt.schema.ValidationMessage; +import com.networknt.schema.Schema; +import com.networknt.schema.keyword.KeywordValidator; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.Error; import java.util.List; public abstract class AbstractWalkListenerRunner implements WalkListenerRunner { protected WalkEvent constructWalkEvent(ExecutionContext executionContext, String keyword, JsonNode instanceNode, - JsonNode rootNode, JsonNodePath instanceLocation, JsonSchema schema, JsonValidator validator) { + JsonNode rootNode, NodePath instanceLocation, Schema schema, KeywordValidator validator) { return WalkEvent.builder().executionContext(executionContext).instanceLocation(instanceLocation) .keyword(keyword).instanceNode(instanceNode) .rootNode(rootNode).schema(schema).validator(validator).build(); } - protected boolean runPreWalkListeners(List walkListeners, WalkEvent walkEvent) { + protected boolean runPreWalkListeners(List walkListeners, WalkEvent walkEvent) { boolean continueToWalkMethod = true; if (walkListeners != null) { - for (JsonSchemaWalkListener walkListener : walkListeners) { + for (WalkListener walkListener : walkListeners) { WalkFlow walkFlow = walkListener.onWalkStart(walkEvent); if (WalkFlow.SKIP.equals(walkFlow) || WalkFlow.ABORT.equals(walkFlow)) { continueToWalkMethod = false; @@ -34,11 +34,11 @@ protected boolean runPreWalkListeners(List walkListeners return continueToWalkMethod; } - protected void runPostWalkListeners(List walkListeners, WalkEvent walkEvent, - List validationMessages) { + protected void runPostWalkListeners(List walkListeners, WalkEvent walkEvent, + List errors) { if (walkListeners != null) { - for (JsonSchemaWalkListener walkListener : walkListeners) { - walkListener.onWalkEnd(walkEvent, validationMessages); + for (WalkListener walkListener : walkListeners) { + walkListener.onWalkEnd(walkEvent, errors); } } } diff --git a/src/main/java/com/networknt/schema/ApplyDefaultsStrategy.java b/src/main/java/com/networknt/schema/walk/ApplyDefaultsStrategy.java similarity index 91% rename from src/main/java/com/networknt/schema/ApplyDefaultsStrategy.java rename to src/main/java/com/networknt/schema/walk/ApplyDefaultsStrategy.java index 391a160a0..bbd80f0bd 100644 --- a/src/main/java/com/networknt/schema/ApplyDefaultsStrategy.java +++ b/src/main/java/com/networknt/schema/walk/ApplyDefaultsStrategy.java @@ -1,7 +1,7 @@ -package com.networknt.schema; +package com.networknt.schema.walk; public class ApplyDefaultsStrategy { - static final ApplyDefaultsStrategy EMPTY_APPLY_DEFAULTS_STRATEGY = new ApplyDefaultsStrategy(false, false, false); + public static final ApplyDefaultsStrategy EMPTY_APPLY_DEFAULTS_STRATEGY = new ApplyDefaultsStrategy(false, false, false); private final boolean applyPropertyDefaults; private final boolean applyPropertyDefaultsIfNull; diff --git a/src/main/java/com/networknt/schema/walk/DefaultItemWalkListenerRunner.java b/src/main/java/com/networknt/schema/walk/DefaultItemWalkListenerRunner.java deleted file mode 100644 index 6d0e3d865..000000000 --- a/src/main/java/com/networknt/schema/walk/DefaultItemWalkListenerRunner.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.networknt.schema.walk; - -import com.fasterxml.jackson.databind.JsonNode; -import com.networknt.schema.ExecutionContext; -import com.networknt.schema.JsonNodePath; -import com.networknt.schema.JsonSchema; -import com.networknt.schema.JsonValidator; -import com.networknt.schema.ValidationMessage; - -import java.util.List; - -public class DefaultItemWalkListenerRunner extends AbstractWalkListenerRunner { - - private final List itemWalkListeners; - - public DefaultItemWalkListenerRunner(List itemWalkListeners) { - this.itemWalkListeners = itemWalkListeners; - } - - @Override - public boolean runPreWalkListeners(ExecutionContext executionContext, String keyword, JsonNode instanceNode, - JsonNode rootNode, JsonNodePath instanceLocation, JsonSchema schema, JsonValidator validator) { - WalkEvent walkEvent = constructWalkEvent(executionContext, keyword, instanceNode, rootNode, instanceLocation, - schema, validator); - return runPreWalkListeners(itemWalkListeners, walkEvent); - } - - @Override - public void runPostWalkListeners(ExecutionContext executionContext, String keyword, JsonNode instanceNode, - JsonNode rootNode, JsonNodePath instanceLocation, JsonSchema schema, JsonValidator validator, List validationMessages) { - WalkEvent walkEvent = constructWalkEvent(executionContext, keyword, instanceNode, rootNode, instanceLocation, - schema, validator); - runPostWalkListeners(itemWalkListeners, walkEvent, validationMessages); - } - -} \ No newline at end of file diff --git a/src/main/java/com/networknt/schema/walk/DefaultKeywordWalkListenerRunner.java b/src/main/java/com/networknt/schema/walk/DefaultKeywordWalkListenerRunner.java deleted file mode 100644 index 6f3692f51..000000000 --- a/src/main/java/com/networknt/schema/walk/DefaultKeywordWalkListenerRunner.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.networknt.schema.walk; - -import com.fasterxml.jackson.databind.JsonNode; -import com.networknt.schema.*; - -import java.util.List; -import java.util.Map; - -public class DefaultKeywordWalkListenerRunner extends AbstractWalkListenerRunner { - - private final Map> keywordWalkListenersMap; - - public DefaultKeywordWalkListenerRunner(Map> keywordWalkListenersMap) { - this.keywordWalkListenersMap = keywordWalkListenersMap; - } - - @Override - public boolean runPreWalkListeners(ExecutionContext executionContext, String keyword, JsonNode instanceNode, JsonNode rootNode, - JsonNodePath instanceLocation, JsonSchema schema, JsonValidator validator) { - boolean continueRunningListenersAndWalk = true; - WalkEvent keywordWalkEvent = constructWalkEvent(executionContext, keyword, instanceNode, rootNode, instanceLocation, schema, validator); - // Run Listeners that are setup only for this keyword. - List currentKeywordListeners = keywordWalkListenersMap.get(keyword); - continueRunningListenersAndWalk = runPreWalkListeners(currentKeywordListeners, keywordWalkEvent); - if (continueRunningListenersAndWalk) { - // Run Listeners that are setup for all keywords. - List allKeywordListeners = keywordWalkListenersMap - .get(SchemaValidatorsConfig.ALL_KEYWORD_WALK_LISTENER_KEY); - runPreWalkListeners(allKeywordListeners, keywordWalkEvent); - } - return continueRunningListenersAndWalk; - } - - @Override - public void runPostWalkListeners(ExecutionContext executionContext, String keyword, JsonNode instanceNode, JsonNode rootNode, JsonNodePath instanceLocation, - JsonSchema schema, JsonValidator validator, List validationMessages) { - WalkEvent keywordWalkEvent = constructWalkEvent(executionContext, keyword, instanceNode, rootNode, instanceLocation, schema, validator); - // Run Listeners that are setup only for this keyword. - List currentKeywordListeners = keywordWalkListenersMap.get(keyword); - runPostWalkListeners(currentKeywordListeners, keywordWalkEvent, validationMessages); - // Run Listeners that are setup for all keywords. - List allKeywordListeners = keywordWalkListenersMap - .get(SchemaValidatorsConfig.ALL_KEYWORD_WALK_LISTENER_KEY); - runPostWalkListeners(allKeywordListeners, keywordWalkEvent, validationMessages); - } - -} diff --git a/src/main/java/com/networknt/schema/walk/DefaultPropertyWalkListenerRunner.java b/src/main/java/com/networknt/schema/walk/DefaultPropertyWalkListenerRunner.java deleted file mode 100644 index 7acdc407d..000000000 --- a/src/main/java/com/networknt/schema/walk/DefaultPropertyWalkListenerRunner.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.networknt.schema.walk; - -import com.fasterxml.jackson.databind.JsonNode; -import com.networknt.schema.ExecutionContext; -import com.networknt.schema.JsonNodePath; -import com.networknt.schema.JsonSchema; -import com.networknt.schema.JsonValidator; -import com.networknt.schema.ValidationMessage; - -import java.util.List; - -public class DefaultPropertyWalkListenerRunner extends AbstractWalkListenerRunner { - - private final List propertyWalkListeners; - - public DefaultPropertyWalkListenerRunner(List propertyWalkListeners) { - this.propertyWalkListeners = propertyWalkListeners; - } - - @Override - public boolean runPreWalkListeners(ExecutionContext executionContext, String keyword, JsonNode instanceNode, JsonNode rootNode, - JsonNodePath instanceLocation, JsonSchema schema, JsonValidator validator) { - WalkEvent walkEvent = constructWalkEvent(executionContext, keyword, instanceNode, rootNode, instanceLocation, schema, validator); - return runPreWalkListeners(propertyWalkListeners, walkEvent); - } - - @Override - public void runPostWalkListeners(ExecutionContext executionContext, String keyword, JsonNode instanceNode, JsonNode rootNode, JsonNodePath instanceLocation, - JsonSchema schema, JsonValidator validator, List validationMessages) { - WalkEvent walkEvent = constructWalkEvent(executionContext, keyword, instanceNode, rootNode, instanceLocation, schema, validator); - runPostWalkListeners(propertyWalkListeners, walkEvent, validationMessages); - - } - -} diff --git a/src/main/java/com/networknt/schema/walk/ItemWalkListenerRunner.java b/src/main/java/com/networknt/schema/walk/ItemWalkListenerRunner.java new file mode 100644 index 000000000..62522e20d --- /dev/null +++ b/src/main/java/com/networknt/schema/walk/ItemWalkListenerRunner.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.networknt.schema.walk; + +import com.fasterxml.jackson.databind.JsonNode; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.keyword.KeywordValidator; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.Error; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +/** + * A {@link WalkListenerRunner} for walking items. + */ +public class ItemWalkListenerRunner extends AbstractWalkListenerRunner { + + private final List itemWalkListeners; + + public ItemWalkListenerRunner(List itemWalkListeners) { + this.itemWalkListeners = itemWalkListeners; + } + + @Override + public boolean runPreWalkListeners(ExecutionContext executionContext, String keyword, JsonNode instanceNode, + JsonNode rootNode, NodePath instanceLocation, Schema schema, KeywordValidator validator) { + WalkEvent walkEvent = constructWalkEvent(executionContext, keyword, instanceNode, rootNode, instanceLocation, + schema, validator); + return runPreWalkListeners(itemWalkListeners, walkEvent); + } + + @Override + public void runPostWalkListeners(ExecutionContext executionContext, String keyword, JsonNode instanceNode, + JsonNode rootNode, NodePath instanceLocation, Schema schema, KeywordValidator validator, List errors) { + WalkEvent walkEvent = constructWalkEvent(executionContext, keyword, instanceNode, rootNode, instanceLocation, + schema, validator); + runPostWalkListeners(itemWalkListeners, walkEvent, errors); + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private List itemWalkListeners = new ArrayList<>(); + + public Builder itemWalkListener(WalkListener itemWalkListener) { + this.itemWalkListeners.add(itemWalkListener); + return this; + } + + public Builder itemWalkListeners(Consumer> itemWalkListeners) { + itemWalkListeners.accept(this.itemWalkListeners); + return this; + } + + public ItemWalkListenerRunner build() { + return new ItemWalkListenerRunner(itemWalkListeners); + } + } + +} \ No newline at end of file diff --git a/src/main/java/com/networknt/schema/walk/JsonSchemaWalker.java b/src/main/java/com/networknt/schema/walk/JsonSchemaWalker.java deleted file mode 100644 index 091f6f3ac..000000000 --- a/src/main/java/com/networknt/schema/walk/JsonSchemaWalker.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.networknt.schema.walk; - -import com.fasterxml.jackson.databind.JsonNode; -import com.networknt.schema.BaseJsonValidator; -import com.networknt.schema.ExecutionContext; -import com.networknt.schema.JsonNodePath; - -public interface JsonSchemaWalker { - /** - * - * This method gives the capability to walk through the given JsonNode, allowing - * functionality beyond validation like collecting information,handling cross-cutting - * concerns like logging or instrumentation. This method also performs - * the validation if {@code shouldValidateSchema} is set to true.
- *
- * {@link BaseJsonValidator#walk(ExecutionContext, JsonNode, JsonNode, JsonNodePath, boolean)} provides - * a default implementation of this method. However, validators that parse - * sub-schemas should override this method to call walk method on those - * sub-schemas. - * - * @param executionContext ExecutionContext - * @param node JsonNode - * @param rootNode JsonNode - * @param instanceLocation JsonNodePath - * @param shouldValidateSchema boolean - */ - void walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, - JsonNodePath instanceLocation, boolean shouldValidateSchema); -} diff --git a/src/main/java/com/networknt/schema/walk/KeywordWalkListenerRunner.java b/src/main/java/com/networknt/schema/walk/KeywordWalkListenerRunner.java new file mode 100644 index 000000000..9a22e2340 --- /dev/null +++ b/src/main/java/com/networknt/schema/walk/KeywordWalkListenerRunner.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.networknt.schema.walk; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; + +import com.fasterxml.jackson.databind.JsonNode; +import com.networknt.schema.Error; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.keyword.Keyword; +import com.networknt.schema.keyword.KeywordValidator; +import com.networknt.schema.path.NodePath; + +/** + * A {@link WalkListenerRunner} for walking keywords. + */ +public class KeywordWalkListenerRunner extends AbstractWalkListenerRunner { + private final List allKeywordWalkListeners; + private final Map> keywordWalkListenersMap; + + public KeywordWalkListenerRunner(List allKeywordWalkListeners, + Map> keywordWalkListenersMap) { + this.allKeywordWalkListeners = allKeywordWalkListeners; + this.keywordWalkListenersMap = keywordWalkListenersMap; + } + + @Override + public boolean runPreWalkListeners(ExecutionContext executionContext, String keyword, JsonNode instanceNode, + JsonNode rootNode, NodePath instanceLocation, Schema schema, KeywordValidator validator) { + boolean continueRunningListenersAndWalk = true; + WalkEvent keywordWalkEvent = constructWalkEvent(executionContext, keyword, instanceNode, rootNode, + instanceLocation, schema, validator); + // Run Listeners that are setup only for this keyword. + List currentKeywordListeners = keywordWalkListenersMap.get(keyword); + continueRunningListenersAndWalk = runPreWalkListeners(currentKeywordListeners, keywordWalkEvent); + if (continueRunningListenersAndWalk) { + // Run Listeners that are setup for all keywords. + runPreWalkListeners(allKeywordWalkListeners, keywordWalkEvent); + } + return continueRunningListenersAndWalk; + } + + @Override + public void runPostWalkListeners(ExecutionContext executionContext, String keyword, JsonNode instanceNode, + JsonNode rootNode, NodePath instanceLocation, Schema schema, KeywordValidator validator, + List errors) { + WalkEvent keywordWalkEvent = constructWalkEvent(executionContext, keyword, instanceNode, rootNode, + instanceLocation, schema, validator); + // Run Listeners that are setup only for this keyword. + List currentKeywordListeners = keywordWalkListenersMap.get(keyword); + runPostWalkListeners(currentKeywordListeners, keywordWalkEvent, errors); + // Run Listeners that are setup for all keywords. + runPostWalkListeners(allKeywordWalkListeners, keywordWalkEvent, errors); + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private Map> keywordWalkListeners = new HashMap<>(); + private List allKeywordWalkListeners = new ArrayList<>(); + + public Builder keywordWalkListener(String keyword, WalkListener keywordWalkListener) { + this.keywordWalkListeners.computeIfAbsent(keyword, key -> new ArrayList<>()).add(keywordWalkListener); + return this; + } + + public Builder keywordWalkListener(Keyword keyword, WalkListener keywordWalkListener) { + return keywordWalkListener(keyword.getValue(), keywordWalkListener); + } + + public Builder keywordWalkListener(WalkListener keywordWalkListener) { + allKeywordWalkListeners.add(keywordWalkListener); + return this; + } + + public Builder keywordWalkListeners(Consumer>> keywordWalkListeners) { + keywordWalkListeners.accept(this.keywordWalkListeners); + return this; + } + + public KeywordWalkListenerRunner build() { + return new KeywordWalkListenerRunner(allKeywordWalkListeners, keywordWalkListeners); + } + } +} diff --git a/src/main/java/com/networknt/schema/walk/PropertyWalkListenerRunner.java b/src/main/java/com/networknt/schema/walk/PropertyWalkListenerRunner.java new file mode 100644 index 000000000..d10fb10bb --- /dev/null +++ b/src/main/java/com/networknt/schema/walk/PropertyWalkListenerRunner.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.networknt.schema.walk; + +import com.fasterxml.jackson.databind.JsonNode; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.keyword.KeywordValidator; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.Error; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +/** + * A {@link WalkListenerRunner} for walking properties. + */ +public class PropertyWalkListenerRunner extends AbstractWalkListenerRunner { + + private final List propertyWalkListeners; + + public PropertyWalkListenerRunner(List propertyWalkListeners) { + this.propertyWalkListeners = propertyWalkListeners; + } + + @Override + public boolean runPreWalkListeners(ExecutionContext executionContext, String keyword, JsonNode instanceNode, + JsonNode rootNode, NodePath instanceLocation, Schema schema, KeywordValidator validator) { + WalkEvent walkEvent = constructWalkEvent(executionContext, keyword, instanceNode, rootNode, instanceLocation, + schema, validator); + return runPreWalkListeners(propertyWalkListeners, walkEvent); + } + + @Override + public void runPostWalkListeners(ExecutionContext executionContext, String keyword, JsonNode instanceNode, + JsonNode rootNode, NodePath instanceLocation, Schema schema, KeywordValidator validator, + List errors) { + WalkEvent walkEvent = constructWalkEvent(executionContext, keyword, instanceNode, rootNode, instanceLocation, + schema, validator); + runPostWalkListeners(propertyWalkListeners, walkEvent, errors); + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private List propertyWalkListeners = new ArrayList<>(); + + public Builder propertyWalkListener(WalkListener propertyWalkListener) { + this.propertyWalkListeners.add(propertyWalkListener); + return this; + } + + public Builder propertyWalkListeners(Consumer> propertyWalkListeners) { + propertyWalkListeners.accept(this.propertyWalkListeners); + return this; + } + + public PropertyWalkListenerRunner build() { + return new PropertyWalkListenerRunner(propertyWalkListeners); + } + } +} diff --git a/src/main/java/com/networknt/schema/walk/WalkConfig.java b/src/main/java/com/networknt/schema/walk/WalkConfig.java new file mode 100644 index 000000000..d008abad9 --- /dev/null +++ b/src/main/java/com/networknt/schema/walk/WalkConfig.java @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.networknt.schema.walk; + +import java.util.List; + +import com.fasterxml.jackson.databind.JsonNode; +import com.networknt.schema.Error; +import com.networknt.schema.ExecutionContext; +import com.networknt.schema.Schema; +import com.networknt.schema.keyword.KeywordValidator; +import com.networknt.schema.path.NodePath; + +/** + * Configuration used when walking a schema. + */ +public class WalkConfig { + private static class Holder { + private static final WalkConfig INSTANCE = WalkConfig.builder().build(); + } + + public static WalkConfig getInstance() { + return Holder.INSTANCE; + } + + /** + * {@link WalkListenerRunner} that performs no operations but indicates that it + * should walk. + */ + public static class NoOpWalkListenerRunner implements WalkListenerRunner { + private static class Holder { + private static final NoOpWalkListenerRunner INSTANCE = new NoOpWalkListenerRunner(); + } + + public static NoOpWalkListenerRunner getInstance() { + return Holder.INSTANCE; + } + + @Override + public boolean runPreWalkListeners(ExecutionContext executionContext, String keyword, JsonNode instanceNode, + JsonNode rootNode, NodePath instanceLocation, Schema schema, KeywordValidator validator) { + // Always walk + return true; + } + + @Override + public void runPostWalkListeners(ExecutionContext executionContext, String keyword, JsonNode instanceNode, + JsonNode rootNode, NodePath instanceLocation, Schema schema, KeywordValidator validator, + List errors) { + } + } + + /** + * The strategy the walker uses to sets nodes that are missing or NullNode to + * the default value, if any, and mutate the input json. + */ + private final ApplyDefaultsStrategy applyDefaultsStrategy; + + private final WalkListenerRunner itemWalkListenerRunner; + + private final WalkListenerRunner keywordWalkListenerRunner; + + private final WalkListenerRunner propertyWalkListenerRunner; + + WalkConfig(ApplyDefaultsStrategy applyDefaultsStrategy, WalkListenerRunner itemWalkListenerRunner, + WalkListenerRunner keywordWalkListenerRunner, WalkListenerRunner propertyWalkListenerRunner) { + super(); + this.applyDefaultsStrategy = applyDefaultsStrategy; + this.itemWalkListenerRunner = itemWalkListenerRunner; + this.keywordWalkListenerRunner = keywordWalkListenerRunner; + this.propertyWalkListenerRunner = propertyWalkListenerRunner; + } + + /** + * Gets the strategy for applying defaults. + * + * @return the strategy for applying defaults + */ + public ApplyDefaultsStrategy getApplyDefaultsStrategy() { + return this.applyDefaultsStrategy; + } + + /** + * Gets the property walk listener runner. + * + * @return the property walk listener runner + */ + + public WalkListenerRunner getPropertyWalkListenerRunner() { + return this.propertyWalkListenerRunner; + } + + /** + * Gets the item walk listener runner. + * + * @return the item walk listener runner + */ + public WalkListenerRunner getItemWalkListenerRunner() { + return this.itemWalkListenerRunner; + } + + /** + * Gets the keyword walk listener runner. + * + * @return the keyword walk listener runner + */ + public WalkListenerRunner getKeywordWalkListenerRunner() { + return this.keywordWalkListenerRunner; + } + + /** + * Creates a new builder for {@link WalkConfig}. + * + * @return the builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Creates a new builder for {@link WalkConfig} and copies the configuration. + * + * @param config the configuration to copy + * @return the builder + */ + public static Builder builder(WalkConfig config) { + Builder builder = new Builder(); + builder.applyDefaultsStrategy = config.applyDefaultsStrategy; + builder.itemWalkListenerRunner = config.itemWalkListenerRunner; + builder.keywordWalkListenerRunner = config.keywordWalkListenerRunner; + builder.propertyWalkListenerRunner = config.propertyWalkListenerRunner; + return builder; + } + + /** + * Builder for {@link WalkConfig}. + */ + public static class Builder { + private ApplyDefaultsStrategy applyDefaultsStrategy = null; + private WalkListenerRunner itemWalkListenerRunner = null; + private WalkListenerRunner keywordWalkListenerRunner = null; + private WalkListenerRunner propertyWalkListenerRunner = null; + + /** + * Sets the strategy the walker uses to sets nodes to the default value. + *

+ * Defaults to {@link ApplyDefaultsStrategy#EMPTY_APPLY_DEFAULTS_STRATEGY}. + * + * @param applyDefaultsStrategy the strategy + * @return the builder + */ + public Builder applyDefaultsStrategy(ApplyDefaultsStrategy applyDefaultsStrategy) { + this.applyDefaultsStrategy = applyDefaultsStrategy; + return this; + } + + public Builder itemWalkListenerRunner(WalkListenerRunner itemWalkListenerRunner) { + this.itemWalkListenerRunner = itemWalkListenerRunner; + return this; + } + + public Builder keywordWalkListenerRunner(WalkListenerRunner keywordWalkListenerRunner) { + this.keywordWalkListenerRunner = keywordWalkListenerRunner; + return this; + } + + public Builder propertyWalkListenerRunner(WalkListenerRunner propertyWalkListenerRunner) { + this.propertyWalkListenerRunner = propertyWalkListenerRunner; + return this; + } + + public WalkConfig build() { + return new WalkConfig( + applyDefaultsStrategy != null ? applyDefaultsStrategy + : ApplyDefaultsStrategy.EMPTY_APPLY_DEFAULTS_STRATEGY, + itemWalkListenerRunner != null ? itemWalkListenerRunner : NoOpWalkListenerRunner.getInstance(), + keywordWalkListenerRunner != null ? keywordWalkListenerRunner + : NoOpWalkListenerRunner.getInstance(), + propertyWalkListenerRunner != null ? propertyWalkListenerRunner + : NoOpWalkListenerRunner.getInstance()); + } + } +} diff --git a/src/main/java/com/networknt/schema/walk/WalkEvent.java b/src/main/java/com/networknt/schema/walk/WalkEvent.java index 36f857c6f..93549d4fe 100644 --- a/src/main/java/com/networknt/schema/walk/WalkEvent.java +++ b/src/main/java/com/networknt/schema/walk/WalkEvent.java @@ -2,22 +2,22 @@ import com.fasterxml.jackson.databind.JsonNode; import com.networknt.schema.ExecutionContext; -import com.networknt.schema.JsonNodePath; -import com.networknt.schema.JsonSchema; -import com.networknt.schema.JsonValidator; +import com.networknt.schema.Schema; +import com.networknt.schema.keyword.KeywordValidator; +import com.networknt.schema.path.NodePath; /** - * Encapsulation of Walk data that is passed into the {@link JsonSchemaWalkListener}. + * Encapsulation of Walk data that is passed into the {@link WalkListener}. */ public class WalkEvent { private ExecutionContext executionContext; - private JsonSchema schema; + private Schema schema; private String keyword; private JsonNode rootNode; private JsonNode instanceNode; - private JsonNodePath instanceLocation; - private JsonValidator validator; + private NodePath instanceLocation; + private KeywordValidator validator; /** * Gets the execution context. @@ -38,7 +38,7 @@ public ExecutionContext getExecutionContext() { * * @return the schema */ - public JsonSchema getSchema() { + public Schema getSchema() { return schema; } @@ -77,7 +77,7 @@ public JsonNode getInstanceNode() { * * @return the instance location of the instance node */ - public JsonNodePath getInstanceLocation() { + public NodePath getInstanceLocation() { return instanceLocation; } @@ -87,7 +87,7 @@ public JsonNodePath getInstanceLocation() { * @return the validator */ @SuppressWarnings("unchecked") - public T getValidator() { + public T getValidator() { return (T) this.validator; } @@ -110,7 +110,7 @@ public WalkEventBuilder executionContext(ExecutionContext executionContext) { return this; } - public WalkEventBuilder schema(JsonSchema schema) { + public WalkEventBuilder schema(Schema schema) { walkEvent.schema = schema; return this; } @@ -130,12 +130,12 @@ public WalkEventBuilder rootNode(JsonNode rootNode) { return this; } - public WalkEventBuilder instanceLocation(JsonNodePath instanceLocation) { + public WalkEventBuilder instanceLocation(NodePath instanceLocation) { walkEvent.instanceLocation = instanceLocation; return this; } - public WalkEventBuilder validator(JsonValidator validator) { + public WalkEventBuilder validator(KeywordValidator validator) { walkEvent.validator = validator; return this; } diff --git a/src/main/java/com/networknt/schema/walk/JsonSchemaWalkListener.java b/src/main/java/com/networknt/schema/walk/WalkListener.java similarity index 52% rename from src/main/java/com/networknt/schema/walk/JsonSchemaWalkListener.java rename to src/main/java/com/networknt/schema/walk/WalkListener.java index a93c49367..e1ac73dc5 100644 --- a/src/main/java/com/networknt/schema/walk/JsonSchemaWalkListener.java +++ b/src/main/java/com/networknt/schema/walk/WalkListener.java @@ -1,6 +1,6 @@ package com.networknt.schema.walk; -import com.networknt.schema.ValidationMessage; +import com.networknt.schema.Error; import java.util.List; @@ -9,9 +9,9 @@ * Listener class that captures walkStart and walkEnd events. * */ -public interface JsonSchemaWalkListener { +public interface WalkListener { WalkFlow onWalkStart(WalkEvent walkEvent); - void onWalkEnd(WalkEvent walkEvent, List validationMessages); + void onWalkEnd(WalkEvent walkEvent, List errors); } diff --git a/src/main/java/com/networknt/schema/walk/WalkListenerRunner.java b/src/main/java/com/networknt/schema/walk/WalkListenerRunner.java index 4a0ef3dcf..66f2a6ad3 100644 --- a/src/main/java/com/networknt/schema/walk/WalkListenerRunner.java +++ b/src/main/java/com/networknt/schema/walk/WalkListenerRunner.java @@ -2,19 +2,19 @@ import com.fasterxml.jackson.databind.JsonNode; import com.networknt.schema.ExecutionContext; -import com.networknt.schema.JsonNodePath; -import com.networknt.schema.JsonSchema; -import com.networknt.schema.JsonValidator; -import com.networknt.schema.ValidationMessage; +import com.networknt.schema.Schema; +import com.networknt.schema.keyword.KeywordValidator; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.Error; import java.util.List; public interface WalkListenerRunner { boolean runPreWalkListeners(ExecutionContext executionContext, String keyword, JsonNode instanceNode, - JsonNode rootNode, JsonNodePath instanceLocation, JsonSchema schema, JsonValidator validator); + JsonNode rootNode, NodePath instanceLocation, Schema schema, KeywordValidator validator); void runPostWalkListeners(ExecutionContext executionContext, String keyword, JsonNode instanceNode, - JsonNode rootNode, JsonNodePath instanceLocation, JsonSchema schema, JsonValidator validator, List errors); + JsonNode rootNode, NodePath instanceLocation, Schema schema, KeywordValidator validator, List errors); } diff --git a/src/main/java/com/networknt/schema/walk/Walker.java b/src/main/java/com/networknt/schema/walk/Walker.java new file mode 100644 index 000000000..bb250d426 --- /dev/null +++ b/src/main/java/com/networknt/schema/walk/Walker.java @@ -0,0 +1,29 @@ +package com.networknt.schema.walk; + +import com.fasterxml.jackson.databind.JsonNode; +import com.networknt.schema.Validator; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.ExecutionContext; + +public interface Walker { + /** + * This method gives the capability to walk through the given JsonNode, allowing + * functionality beyond validation like collecting information,handling + * cross-cutting concerns like logging or instrumentation. This method also + * performs the validation if {@code shouldValidateSchema} is set to true.
+ *
+ * {@link Validator#walk(ExecutionContext, JsonNode, JsonNode, NodePath, boolean)} + * provides a default implementation of this method. However, validators that + * parse sub-schemas should override this method to call walk method on those + * sub-schemas. + * + * @param executionContext the execution context + * @param instanceNode the instance node being processed + * @param instance the instance document that the instance node + * belongs to + * @param instanceLocation the location of the instance node being processed + * @param shouldValidateSchema true to validate the schema while walking + */ + void walk(ExecutionContext executionContext, JsonNode instanceNode, JsonNode instance, + NodePath instanceLocation, boolean shouldValidateSchema); +} diff --git a/src/main/resources/jsv-messages.properties b/src/main/resources/jsv-messages.properties index 8e94095b6..773da5783 100644 --- a/src/main/resources/jsv-messages.properties +++ b/src/main/resources/jsv-messages.properties @@ -1,70 +1,73 @@ -$ref = {0}: has an error with ''refs'' -additionalItems = {0}: index ''{1}'' is not defined in the schema and the schema does not allow additional items -additionalProperties = {0}: property ''{1}'' is not defined in the schema and the schema does not allow additional properties -allOf = {0}: must be valid to all the schemas {1} -anyOf = {0}: must be valid to any of the schemas {1} -const = {0}: must be the constant value ''{1}'' -contains = {0}: does not contain an element that passes these validations: {2} -contains.max = {0}: must contain at most {1} element(s) that passes these validations: {2} -contains.min = {0}: must contain at least {1} element(s) that passes these validations: {2} -dependencies = {0}: has an error with dependencies {1} -dependentRequired = {0}: has a missing property ''{1}'' which is dependent required because ''{2}'' is present -dependentSchemas = {0}: has an error with dependentSchemas {1} -enum = {0}: does not have a value in the enumeration {1} -exclusiveMaximum = {0}: must have an exclusive maximum value of {1} -exclusiveMinimum = {0}: must have an exclusive minimum value of {1} -false = {0}: schema for ''{1}'' is false -format = {0}: does not match the {1} pattern {2} -format.date = {0}: does not match the {1} pattern must be a valid RFC 3339 full-date -format.date-time = {0}: does not match the {1} pattern must be a valid RFC 3339 date-time -format.duration = {0}: does not match the {1} pattern must be a valid ISO 8601 duration -format.email = {0}: does not match the {1} pattern must be a valid RFC 5321 Mailbox -format.ipv4 = {0}: does not match the {1} pattern must be a valid RFC 2673 IP address -format.ipv6 = {0}: does not match the {1} pattern must be a valid RFC 4291 IP address -format.idn-email = {0}: does not match the {1} pattern must be a valid RFC 6531 Mailbox -format.idn-hostname = {0}: does not match the {1} pattern must be a valid RFC 5890 internationalized hostname -format.iri = {0}: does not match the {1} pattern must be a valid RFC 3987 IRI -format.iri-reference = {0}: does not match the {1} pattern must be a valid RFC 3987 IRI-reference -format.uri = {0}: does not match the {1} pattern must be a valid RFC 3986 URI -format.uri-reference = {0}: does not match the {1} pattern must be a valid RFC 3986 URI-reference -format.uri-template = {0}: does not match the {1} pattern must be a valid RFC 6570 URI Template -format.uuid = {0}: does not match the {1} pattern must be a valid RFC 4122 UUID -format.regex = {0}: does not match the {1} pattern must be a valid ECMA-262 regular expression -format.time = {0}: does not match the {1} pattern must be a valid RFC 3339 time -format.hostname = {0}: does not match the {1} pattern must be a valid RFC 1123 host name -format.json-pointer = {0}: does not match the {1} pattern must be a valid RFC 6901 JSON Pointer -format.relative-json-pointer = {0}: does not match the {1} pattern must be a valid IETF Relative JSON Pointer -format.unknown = {0}: has an unknown format ''{1}'' -id = {0}: ''{1}'' is not a valid {2} -items = {0}: index ''{1}'' is not defined in the schema and the schema does not allow additional items -maxContains = {0}: must be a non-negative integer in {1} -maxItems = {0}: must have at most {1} items but found {2} -maxLength = {0}: must be at most {1} characters long -maxProperties = {0}: must have at most {1} properties -maximum = {0}: must have a maximum value of {1} -minContains = {0}: must be a non-negative integer in {1} -minContainsVsMaxContains = {0}: minContains must less than or equal to maxContains in {1} -minItems = {0}: must have at least {1} items but found {2} -minLength = {0}: must be at least {1} characters long -minProperties = {0}: must have at least {1} properties -minimum = {0}: must have a minimum value of {1} -multipleOf = {0}: must be multiple of {1} -not = {0}: must not be valid to the schema {1} -notAllowed = {0}: property ''{1}'' is not allowed but it is in the data -oneOf = {0}: must be valid to one and only one schema, but {1} are valid -oneOf.indexes = {0}: must be valid to one and only one schema, but {1} are valid with indexes ''{2}'' -pattern = {0}: does not match the regex pattern {1} -patternProperties = {0}: has some error with ''pattern properties'' -prefixItems = {0}: no validator found at this index -properties = {0}: has an error with ''properties'' -propertyNames = {0}: property ''{1}'' name is not valid: {2} -readOnly = {0}: is a readonly field, it cannot be changed -required = {0}: required property ''{1}'' not found -type = {0}: {1} found, {2} expected -unevaluatedItems = {0}: index ''{1}'' is not evaluated and the schema does not allow unevaluated items -unevaluatedProperties = {0}: property ''{1}'' is not evaluated and the schema does not allow unevaluated properties -unionType = {0}: {1} found, {2} expected -uniqueItems = {0}: must have only unique items in the array -writeOnly = {0}: is a write-only field, it cannot appear in the data -contentEncoding = {0}: does not match content encoding {1} -contentMediaType = {0}: is not a content media type \ No newline at end of file +$ref = has an error with ''refs'' +additionalItems = index ''{0}'' is not defined in the schema and the schema does not allow additional items +additionalProperties = property ''{0}'' is not defined in the schema and the schema does not allow additional properties +allOf = must be valid to all the schemas {0} +anyOf = must be valid to any of the schemas {0} +const = must be the constant value ''{0}'' +contains = does not contain an element that passes these validations: {1} +contains.max = must contain at most {0} element(s) that passes these validations: {1} +contains.min = must contain at least {0} element(s) that passes these validations: {1} +dependencies = has an error with dependencies {0} +dependentRequired = has a missing property ''{0}'' which is dependent required because ''{1}'' is present +dependentSchemas = has an error with dependentSchemas {0} +enum = does not have a value in the enumeration {0} +exclusiveMaximum = must have an exclusive maximum value of {0} +exclusiveMinimum = must have an exclusive minimum value of {0} +false = schema for ''{0}'' is false +format = does not match the {0} pattern +format.date = does not match the {0} pattern must be a valid RFC 3339 full-date +format.date-time = does not match the {0} pattern must be a valid RFC 3339 date-time +format.duration = does not match the {0} pattern must be a valid ISO 8601 duration +format.email = does not match the {0} pattern must be a valid RFC 5321 Mailbox +format.ipv4 = does not match the {0} pattern must be a valid RFC 2673 IP address +format.ipv6 = does not match the {0} pattern must be a valid RFC 4291 IP address +format.idn-email = does not match the {0} pattern must be a valid RFC 6531 Mailbox +format.idn-hostname = does not match the {0} pattern must be a valid RFC 5890 internationalized hostname +format.iri = does not match the {0} pattern must be a valid RFC 3987 IRI +format.iri-reference = does not match the {0} pattern must be a valid RFC 3987 IRI-reference +format.uri = does not match the {0} pattern must be a valid RFC 3986 URI +format.uri-reference = does not match the {0} pattern must be a valid RFC 3986 URI-reference +format.uri-template = does not match the {0} pattern must be a valid RFC 6570 URI Template +format.uuid = does not match the {0} pattern must be a valid RFC 4122 UUID +format.regex = does not match the {0} pattern must be a valid ECMA-262 regular expression +format.time = does not match the {0} pattern must be a valid RFC 3339 time +format.hostname = does not match the {0} pattern must be a valid RFC 1123 host name +format.json-pointer = does not match the {0} pattern must be a valid RFC 6901 JSON Pointer +format.relative-json-pointer = does not match the {0} pattern must be a valid IETF Relative JSON Pointer +format.unknown = has an unknown format ''{0}'' +id = ''{0}'' is not a valid {1} +items = index ''{0}'' is not defined in the schema and the schema does not allow additional items +maxContains = must be a non-negative integer in {0} +maxItems = must have at most {0} items but found {1} +maxLength = must be at most {0} characters long +maxProperties = must have at most {0} properties +maximum = must have a maximum value of {0} +minContains = must be a non-negative integer in {0} +minContainsVsMaxContains = minContains must less than or equal to maxContains in {0} +minItems = must have at least {0} items but found {1} +minLength = must be at least {0} characters long +minProperties = must have at least {0} properties +minimum = must have a minimum value of {0} +multipleOf = must be multiple of {0} +not = must not be valid to the schema {0} +notAllowed = property ''{0}'' is not allowed but it is in the data +oneOf = must be valid to one and only one schema, but {0} are valid +oneOf.indexes = must be valid to one and only one schema, but {0} are valid with indexes ''{1}'' +pattern = does not match the regex pattern {0} +patternProperties = has some error with ''pattern properties'' +prefixItems = no validator found at this index +properties = has an error with ''properties'' +propertyNames = property ''{0}'' name is not valid: {1} +readOnly = is a readonly field, it cannot be changed +required = required property ''{0}'' not found +type = {0} found, {1} expected +unevaluatedItems = index ''{0}'' is not evaluated and the schema does not allow unevaluated items +unevaluatedProperties = property ''{0}'' is not evaluated and the schema does not allow unevaluated properties +unionType = {0} found, {1} expected +uniqueItems = must have only unique items in the array +writeOnly = is a write-only field, it cannot appear in the data +contentEncoding = does not match content encoding {0} +contentMediaType = is not a content media type +discriminator.missing_discriminating_value = required property ''{0}'' for discriminator not found +discriminator.anyOf.no_match_found = no matching schema found for discriminator value ''{0}'' +discriminator.oneOf.no_match_found = no matching schema found for discriminator value ''{0}'' \ No newline at end of file diff --git a/src/main/resources/jsv-messages_ar.properties b/src/main/resources/jsv-messages_ar.properties index 2dd53b2a5..6016c7319 100644 --- a/src/main/resources/jsv-messages_ar.properties +++ b/src/main/resources/jsv-messages_ar.properties @@ -1,70 +1,70 @@ -$ref = {0}: \u0628\u0647 \u062E\u0637\u0623 \u0641\u064A ''refs'' -additionalItems = {0}: \u0644\u0645 \u064A\u062A\u0645 \u062A\u0639\u0631\u064A\u0641 \u0627\u0644\u0641\u0647\u0631\u0633 ''{1}'' \u0641\u064A \u0627\u0644\u0645\u062E\u0637\u0637 \u0648\u0644\u0627 \u064A\u0633\u0645\u062D \u0627\u0644\u0645\u062E\u0637\u0637 \u0628\u0639\u0646\u0627\u0635\u0631 \u0625\u0636\u0627\u0641\u064A\u0629 -additionalProperties = {0}: \u0627\u0644\u062E\u0627\u0635\u064A\u0629 ''{1}'' \u063A\u064A\u0631 \u0645\u062D\u062F\u062F\u0629 \u0641\u064A \u0627\u0644\u0645\u062E\u0637\u0637 \u0648\u0644\u0627 \u064A\u0633\u0645\u062D \u0627\u0644\u0645\u062E\u0637\u0637 \u0628\u062E\u0635\u0627\u0626\u0635 \u0625\u0636\u0627\u0641\u064A\u0629 -allOf = {0}: \u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0635\u0627\u0644\u062D\u064B\u0627 \u0644\u062C\u0645\u064A\u0639 \u0627\u0644\u0645\u062E\u0637\u0637\u0627\u062A {1} -anyOf = {0}: \u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0635\u0627\u0644\u062D\u064B\u0627 \u0644\u0623\u064A \u0645\u0646 \u0627\u0644\u0645\u062E\u0637\u0637\u0627\u062A {1} -const = {0}: \u064A\u062C\u0628 \u0623\u0646 \u062A\u0643\u0648\u0646 \u0627\u0644\u0642\u064A\u0645\u0629 \u0627\u0644\u062B\u0627\u0628\u062A\u0629 ''{1}'' -contains = {0}: \u0644\u0627 \u064A\u062D\u062A\u0648\u064A \u0639\u0644\u0649 \u0639\u0646\u0635\u0631 \u064A\u0642\u0648\u0645 \u0628\u062A\u0645\u0631\u064A\u0631 \u0639\u0645\u0644\u064A\u0627\u062A \u0627\u0644\u062A\u062D\u0642\u0642 \u0647\u0630\u0647: {2} -contains.max = {0}: \u064A\u062C\u0628 \u0623\u0646 \u064A\u062D\u062A\u0648\u064A \u0639\u0644\u0649 {1} \u0639\u0646\u0635\u0631 (\u0639\u0646\u0627\u0635\u0631) \u0639\u0644\u0649 \u0627\u0644\u0623\u0643\u062B\u0631 \u064A\u062C\u062A\u0627\u0632 \u0639\u0645\u0644\u064A\u0627\u062A \u0627\u0644\u062A\u062D\u0642\u0642 \u0647\u0630\u0647: {2} -contains.min = {0}: \u064A\u062C\u0628 \u0623\u0646 \u064A\u062D\u062A\u0648\u064A \u0639\u0644\u0649 {1} \u0639\u0646\u0635\u0631 (\u0639\u0646\u0627\u0635\u0631) \u0639\u0644\u0649 \u0627\u0644\u0623\u0642\u0644 \u064A\u0642\u0648\u0645 \u0628\u062A\u0645\u0631\u064A\u0631 \u0639\u0645\u0644\u064A\u0627\u062A \u0627\u0644\u062A\u062D\u0642\u0642 \u0647\u0630\u0647: {2} -dependencies = {0}: \u064A\u0648\u062C\u062F \u062E\u0637\u0623 \u0641\u064A \u0627\u0644\u062A\u0628\u0639\u064A\u0627\u062A {1} -dependentRequired = {0}: \u0628\u0647 \u062E\u0627\u0635\u064A\u0629 \u0645\u0641\u0642\u0648\u062F\u0629 ''{1}'' \u0648\u0647\u064A \u062A\u0627\u0628\u0639\u0629 \u0645\u0637\u0644\u0648\u0628\u0629 \u0644\u0623\u0646 ''{2}'' \u0645\u0648\u062C\u0648\u062F\u0629 -dependentSchemas = {0}: \u0628\u0647 \u062E\u0637\u0623 \u0641\u064AdependentSchemas {1} -enum = {0}: \u0644\u0627 \u064A\u062D\u062A\u0648\u064A \u0639\u0644\u0649 \u0642\u064A\u0645\u0629 \u0641\u064A \u0627\u0644\u062A\u0639\u062F\u0627\u062F {1} -exclusiveMaximum = {0}: \u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0644\u0647 \u0642\u064A\u0645\u0629 \u0642\u0635\u0648\u0649 \u062D\u0635\u0631\u064A\u0629 \u062A\u0628\u0644\u063A {1} -exclusiveMinimum = {0}: \u064A\u062C\u0628 \u0623\u0646 \u064A\u062D\u062A\u0648\u064A \u0639\u0644\u0649 \u0642\u064A\u0645\u0629 \u062F\u0646\u064A\u0627 \u062D\u0635\u0631\u064A\u0629 \u062A\u0628\u0644\u063A {1} -false = {0}: \u0645\u062E\u0637\u0637 ''{1}'' \u063A\u064A\u0631 \u0635\u062D\u064A\u062D -format = {0}: \u0644\u0627 \u064A\u0637\u0627\u0628\u0642 \u0627\u0644\u0646\u0645\u0637 {1} {2} -format.date = {0}: \u0644\u0627 \u064A\u062A\u0637\u0627\u0628\u0642 \u0645\u0639 \u0627\u0644\u0646\u0645\u0637 {1} \u0648\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u062A\u0627\u0631\u064A\u062E\u064B\u0627 \u0643\u0627\u0645\u0644\u0627\u064B \u0635\u0627\u0644\u062D\u064B\u0627 \u0644\u0640 RFC 3339 -format.date-time = {0}: \u0644\u0627 \u064A\u062A\u0637\u0627\u0628\u0642 \u0645\u0639 \u0627\u0644\u0646\u0645\u0637 {1} \u0648\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u062A\u0627\u0631\u064A\u062E\u064B\u0627 \u0648\u0648\u0642\u062A\u064B\u0627 \u0635\u0627\u0644\u062D\u064B\u0627 \u0641\u064A RFC 3339 -format.duration = {0}: \u0644\u0627 \u064A\u062A\u0637\u0627\u0628\u0642 \u0645\u0639 \u0627\u0644\u0646\u0645\u0637 {1} \u0648\u064A\u062C\u0628 \u0623\u0646 \u062A\u0643\u0648\u0646 \u0645\u062F\u0629 ISO 8601 \u0635\u0627\u0644\u062D\u0629 -format.email = {0}: \u0644\u0627 \u064A\u062A\u0637\u0627\u0628\u0642 \u0645\u0639 \u0627\u0644\u0646\u0645\u0637 {1} \u0648\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0635\u0646\u062F\u0648\u0642 \u0628\u0631\u064A\u062F RFC 5321 \u0635\u0627\u0644\u062D\u064B\u0627 -format.ipv4 = {0}: \u0644\u0627 \u064A\u062A\u0637\u0627\u0628\u0642 \u0645\u0639 \u0627\u0644\u0646\u0645\u0637 {1} \u0648\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0639\u0646\u0648\u0627\u0646 IP \u0635\u0627\u0644\u062D\u064B\u0627 \u0644\u0640 RFC 2673 -format.ipv6 = {0}: \u0644\u0627 \u064A\u062A\u0637\u0627\u0628\u0642 \u0645\u0639 \u0627\u0644\u0646\u0645\u0637 {1} \u0648\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0639\u0646\u0648\u0627\u0646 IP \u0635\u0627\u0644\u062D\u064B\u0627 \u0644\u0640 RFC 4291 -format.idn-email = {0}: \u0644\u0627 \u064A\u062A\u0637\u0627\u0628\u0642 \u0645\u0639 \u0627\u0644\u0646\u0645\u0637 {1} \u0648\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0635\u0646\u062F\u0648\u0642 \u0628\u0631\u064A\u062F RFC 6531 \u0635\u0627\u0644\u062D\u064B\u0627 -format.idn-hostname = {0}: \u0644\u0627 \u064A\u062A\u0637\u0627\u0628\u0642 \u0645\u0639 \u0627\u0644\u0646\u0645\u0637 {1} \u0648\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0627\u0633\u0645 \u0645\u0636\u064A\u0641 \u062F\u0648\u0644\u064A\u064B\u0627 \u0635\u0627\u0644\u062D\u064B\u0627 \u0644\u0640 RFC 5890 -format.iri = {0}: \u0644\u0627 \u064A\u062A\u0637\u0627\u0628\u0642 \u0645\u0639 \u0627\u0644\u0646\u0645\u0637 {1} \u0648\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 RFC 3987 IRI \u0635\u0627\u0644\u062D\u064B\u0627 -format.iri-reference = {0}: \u0644\u0627 \u064A\u062A\u0637\u0627\u0628\u0642 \u0645\u0639 \u0627\u0644\u0646\u0645\u0637 {1} \u0648\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0645\u0631\u062C\u0639 RFC 3987 IRI \u0635\u0627\u0644\u062D\u064B\u0627 -format.uri = {0}: \u0644\u0627 \u064A\u062A\u0637\u0627\u0628\u0642 \u0645\u0639 \u0627\u0644\u0646\u0645\u0637 {1} \u0648\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0639\u0646\u0648\u0627\u0646 URI \u0635\u0627\u0644\u062D\u064B\u0627 \u0644\u0640 RFC 3986 -format.uri-reference = {0}: \u0644\u0627 \u064A\u062A\u0637\u0627\u0628\u0642 \u0645\u0639 \u0627\u0644\u0646\u0645\u0637 {1} \u0648\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0645\u0631\u062C\u0639 URI \u0635\u0627\u0644\u062D\u064B\u0627 \u0644\u0640 RFC 3986 -format.uri-template = {0}: \u0644\u0627 \u064A\u062A\u0637\u0627\u0628\u0642 \u0645\u0639 \u0627\u0644\u0646\u0645\u0637 {1} \u0648\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0642\u0627\u0644\u0628 URI RFC 6570 \u0635\u0627\u0644\u062D\u064B\u0627 -format.uuid = {0}: \u0644\u0627 \u064A\u062A\u0637\u0627\u0628\u0642 \u0645\u0639 \u0627\u0644\u0646\u0645\u0637 {1} \u0648\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 RFC 4122 UUID \u0635\u0627\u0644\u062D\u064B\u0627 -format.regex = {0}: \u0644\u0627 \u064A\u062A\u0637\u0627\u0628\u0642 \u0645\u0639 \u0627\u0644\u0646\u0645\u0637 {1} \u0648\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u062A\u0639\u0628\u064A\u0631\u064B\u0627 \u0639\u0627\u062F\u064A\u064B\u0627 \u0635\u0627\u0644\u062D\u064B\u0627 \u0644\u0640 ECMA-262 -format.time = {0}: \u0644\u0627 \u064A\u062A\u0637\u0627\u0628\u0642 \u0645\u0639 \u0627\u0644\u0646\u0645\u0637 {1} \u0648\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0648\u0642\u062A RFC 3339 \u0635\u0627\u0644\u062D\u064B\u0627 -format.hostname = {0}: \u0644\u0627 \u064A\u062A\u0637\u0627\u0628\u0642 \u0645\u0639 \u0627\u0644\u0646\u0645\u0637 {1} \u0648\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0627\u0633\u0645 \u0645\u0636\u064A\u0641 RFC 1123 \u0635\u0627\u0644\u062D\u064B\u0627 -format.json-pointer = {0}: \u0644\u0627 \u064A\u062A\u0637\u0627\u0628\u0642 \u0645\u0639 \u0627\u0644\u0646\u0645\u0637 {1} \u0648\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0645\u0624\u0634\u0631 RFC 6901 JSON \u0635\u0627\u0644\u062D\u064B\u0627 -format.relative-json-pointer = {0}: \u0644\u0627 \u064A\u062A\u0637\u0627\u0628\u0642 \u0645\u0639 \u0627\u0644\u0646\u0645\u0637 {1} \u0648\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0645\u0624\u0634\u0631 IETF Relative JSON \u0635\u0627\u0644\u062D\u064B\u0627 -format.unknown = {0}: \u0644\u0647 \u062A\u0646\u0633\u064A\u0642 \u063A\u064A\u0631 \u0645\u0639\u0631\u0648\u0641 ''{1}'' -id = {0}: ''{1}'' \u0644\u064A\u0633 {2} \u0635\u0627\u0644\u062D\u064B\u0627 -items = {0}: \u0644\u0645 \u064A\u062A\u0645 \u062A\u0639\u0631\u064A\u0641 \u0627\u0644\u0641\u0647\u0631\u0633 ''{1}'' \u0641\u064A \u0627\u0644\u0645\u062E\u0637\u0637 \u0648\u0644\u0627 \u064A\u0633\u0645\u062D \u0627\u0644\u0645\u062E\u0637\u0637 \u0628\u0639\u0646\u0627\u0635\u0631 \u0625\u0636\u0627\u0641\u064A\u0629 -maxContains = {0}: \u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0639\u062F\u062F\u064B\u0627 \u0635\u062D\u064A\u062D\u064B\u0627 \u063A\u064A\u0631 \u0633\u0627\u0644\u0628 \u0641\u064A {1} -maxItems = {0}: \u064A\u062C\u0628 \u0623\u0646 \u064A\u062D\u062A\u0648\u064A \u0639\u0644\u0649 {1} \u0639\u0646\u0635\u0631 \u0639\u0644\u0649 \u0627\u0644\u0623\u0643\u062B\u0631 \u0648\u0644\u0643\u0646 \u062A\u0645 \u0627\u0644\u0639\u062B\u0648\u0631 \u0639\u0644\u0649 {2} -maxLength = {0}: \u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0637\u0648\u0644\u0647 {1} \u062D\u0631\u0641\u064B\u0627 \u0639\u0644\u0649 \u0627\u0644\u0623\u0643\u062B\u0631 -maxProperties = {0}: \u064A\u062C\u0628 \u0623\u0646 \u064A\u062D\u062A\u0648\u064A \u0639\u0644\u0649 {1} \u0645\u0646 \u0627\u0644\u062E\u0635\u0627\u0626\u0635 \u0639\u0644\u0649 \u0627\u0644\u0623\u0643\u062B\u0631 -maximum = {0}: \u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0627\u0644\u062D\u062F \u0627\u0644\u0623\u0642\u0635\u0649 \u0644\u0642\u064A\u0645\u0629 {1} -minContains = {0}: \u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0639\u062F\u062F\u064B\u0627 \u0635\u062D\u064A\u062D\u064B\u0627 \u063A\u064A\u0631 \u0633\u0627\u0644\u0628 \u0641\u064A {1} -minContainsVsMaxContains = {0}: \u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 minContains \u0623\u0642\u0644 \u0645\u0646 \u0623\u0648 \u064A\u0633\u0627\u0648\u064A maxContains \u0641\u064A {1} -minItems = {0}: \u064A\u062C\u0628 \u0623\u0646 \u064A\u062D\u062A\u0648\u064A \u0639\u0644\u0649 {1} \u0639\u0646\u0635\u0631 \u0639\u0644\u0649 \u0627\u0644\u0623\u0642\u0644 \u0648\u0644\u0643\u0646 \u062A\u0645 \u0627\u0644\u0639\u062B\u0648\u0631 \u0639\u0644\u0649 {2} -minLength = {0}: \u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0637\u0648\u0644\u0647 {1} \u062D\u0631\u0641\u064B\u0627 \u0639\u0644\u0649 \u0627\u0644\u0623\u0642\u0644 -minProperties = {0}: \u064A\u062C\u0628 \u0623\u0646 \u062A\u062D\u062A\u0648\u064A \u0639\u0644\u0649 {1} \u0645\u0646 \u0627\u0644\u062E\u0635\u0627\u0626\u0635 \u0639\u0644\u0649 \u0627\u0644\u0623\u0642\u0644 -minimum = {0}: \u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0627\u0644\u062D\u062F \u0627\u0644\u0623\u062F\u0646\u0649 \u0644\u0642\u064A\u0645\u0629 {1} -multipleOf = {0}: \u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0645\u0646 \u0645\u0636\u0627\u0639\u0641\u0627\u062A {1} -not = {0}: \u064A\u062C\u0628 \u0623\u0646 \u0644\u0627 \u064A\u0643\u0648\u0646 \u0635\u0627\u0644\u062D\u064B\u0627 \u0644\u0644\u0645\u062E\u0637\u0637 {1} -notAllowed = {0}: \u0627\u0644\u062E\u0627\u0635\u064A\u0629 ''{1}'' \u063A\u064A\u0631 \u0645\u0633\u0645\u0648\u062D \u0628\u0647\u0627 \u0648\u0644\u0643\u0646\u0647\u0627 \u0645\u0648\u062C\u0648\u062F\u0629 \u0641\u064A \u0627\u0644\u0628\u064A\u0627\u0646\u0627\u062A -oneOf = {0}: \u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0635\u0627\u0644\u062D\u064B\u0627 \u0644\u0645\u062E\u0637\u0637 \u0648\u0627\u062D\u062F \u0641\u0642\u0637\u060C \u0648\u0644\u0643\u0646 {1} \u0635\u0627\u0644\u062D -oneOf.indexes = {0}: \u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0635\u0627\u0644\u062D\u064B\u0627 \u0644\u0645\u062E\u0637\u0637 \u0648\u0627\u062D\u062F \u0641\u0642\u0637\u060C \u0648\u0644\u0643\u0646 {1} \u0635\u0627\u0644\u062D \u0645\u0639 \u0627\u0644\u0641\u0647\u0627\u0631\u0633 ''{2}'' -pattern = {0}: \u0644\u0627 \u064A\u062A\u0637\u0627\u0628\u0642 \u0645\u0639 \u0646\u0645\u0637 \u0627\u0644\u062A\u0639\u0628\u064A\u0631 \u0627\u0644\u0639\u0627\u062F\u064A {1} -patternProperties = {0}: \u0628\u0647 \u0628\u0639\u0636 \u0627\u0644\u0623\u062E\u0637\u0627\u0621 \u0641\u064A ''\u062E\u0635\u0627\u0626\u0635 \u0627\u0644\u0646\u0645\u0637'' -prefixItems = {0}: \u0644\u0645 \u064A\u062A\u0645 \u0627\u0644\u0639\u062B\u0648\u0631 \u0639\u0644\u0649 \u0623\u062F\u0627\u0629 \u0627\u0644\u062A\u062D\u0642\u0642 \u0641\u064A \u0647\u0630\u0627 \u0627\u0644\u0641\u0647\u0631\u0633 -properties = {0}: \u064A\u0648\u062C\u062F \u062E\u0637\u0623 \u0641\u064A ''\u0627\u0644\u062E\u0635\u0627\u0626\u0635'' -propertyNames = {0}: \u0627\u0633\u0645 \u0627\u0644\u062E\u0627\u0635\u064A\u0629 ''{1}'' \u063A\u064A\u0631 \u0635\u0627\u0644\u062D: {2} -readOnly = {0}: \u0647\u0648 \u062D\u0642\u0644 \u0644\u0644\u0642\u0631\u0627\u0621\u0629 \u0641\u0642\u0637\u060C \u0648\u0644\u0627 \u064A\u0645\u0643\u0646 \u062A\u063A\u064A\u064A\u0631\u0647 -required = {0}: \u0627\u0644\u062E\u0627\u0635\u064A\u0629 \u0627\u0644\u0645\u0637\u0644\u0648\u0628\u0629 ''{1}'' \u063A\u064A\u0631 \u0645\u0648\u062C\u0648\u062F\u0629 -type = {0}: \u062A\u0645 \u0627\u0644\u0639\u062B\u0648\u0631 \u0639\u0644\u0649 {1}\u060C \u0648\u0627\u0644\u0645\u062A\u0648\u0642\u0639 \u0647\u0648 {2}. -unevaluatedItems = {0}: \u0644\u0645 \u064A\u062A\u0645 \u062A\u0642\u064A\u064A\u0645 \u0627\u0644\u0641\u0647\u0631\u0633 ''{1}'' \u0648\u0644\u0627 \u064A\u0633\u0645\u062D \u0627\u0644\u0645\u062E\u0637\u0637 \u0628\u0627\u0644\u0639\u0646\u0627\u0635\u0631 \u063A\u064A\u0631 \u0627\u0644\u0645\u0642\u064A\u064E\u0651\u0645\u0629 -unevaluatedProperties = {0}: \u0627\u0644\u062E\u0627\u0635\u064A\u0629 ''{1}'' \u0644\u0645 \u064A\u062A\u0645 \u062A\u0642\u064A\u064A\u0645\u0647\u0627 \u0648\u0644\u0627 \u064A\u0633\u0645\u062D \u0627\u0644\u0645\u062E\u0637\u0637 \u0628\u0627\u0644\u062E\u0635\u0627\u0626\u0635 \u063A\u064A\u0631 \u0627\u0644\u0645\u0642\u064A\u064E\u0651\u0645\u0629 -unionType = {0}: \u062A\u0645 \u0627\u0644\u0639\u062B\u0648\u0631 \u0639\u0644\u0649 {1}\u060C \u0648\u0627\u0644\u0645\u062A\u0648\u0642\u0639 \u0647\u0648 {2}. -uniqueItems = {0}: \u064A\u062C\u0628 \u0623\u0646 \u062A\u062D\u062A\u0648\u064A \u0639\u0644\u0649 \u0639\u0646\u0627\u0635\u0631 \u0641\u0631\u064A\u062F\u0629 \u0641\u0642\u0637 \u0641\u064A \u0627\u0644\u0645\u0635\u0641\u0648\u0641\u0629 -writeOnly = {0}: \u0647\u0648 \u062D\u0642\u0644 \u0644\u0644\u0643\u062A\u0627\u0628\u0629 \u0641\u0642\u0637\u060C \u0648\u0644\u0627 \u064A\u0645\u0643\u0646 \u0623\u0646 \u064A\u0638\u0647\u0631 \u0641\u064A \u0627\u0644\u0628\u064A\u0627\u0646\u0627\u062A -contentEncoding = {0}: \u0644\u0627 \u064A\u0637\u0627\u0628\u0642 \u062A\u0631\u0645\u064A\u0632 \u0627\u0644\u0645\u062D\u062A\u0648\u0649 {1} -contentMediaType = {0}: \u0644\u064A\u0633 \u0645\u062D\u062A\u0648\u0649 \u062E\u0627\u0635\u064B\u0627 \u0628\u064A +$ref = \u0628\u0647 \u062E\u0637\u0623 \u0641\u064A ''refs'' +additionalItems = \u0644\u0645 \u064A\u062A\u0645 \u062A\u0639\u0631\u064A\u0641 \u0627\u0644\u0641\u0647\u0631\u0633 ''{0}'' \u0641\u064A \u0627\u0644\u0645\u062E\u0637\u0637 \u0648\u0644\u0627 \u064A\u0633\u0645\u062D \u0627\u0644\u0645\u062E\u0637\u0637 \u0628\u0639\u0646\u0627\u0635\u0631 \u0625\u0636\u0627\u0641\u064A\u0629 +additionalProperties = \u0627\u0644\u062E\u0627\u0635\u064A\u0629 ''{0}'' \u063A\u064A\u0631 \u0645\u062D\u062F\u062F\u0629 \u0641\u064A \u0627\u0644\u0645\u062E\u0637\u0637 \u0648\u0644\u0627 \u064A\u0633\u0645\u062D \u0627\u0644\u0645\u062E\u0637\u0637 \u0628\u062E\u0635\u0627\u0626\u0635 \u0625\u0636\u0627\u0641\u064A\u0629 +allOf = \u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0635\u0627\u0644\u062D\u064B\u0627 \u0644\u062C\u0645\u064A\u0639 \u0627\u0644\u0645\u062E\u0637\u0637\u0627\u062A {0} +anyOf = \u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0635\u0627\u0644\u062D\u064B\u0627 \u0644\u0623\u064A \u0645\u0646 \u0627\u0644\u0645\u062E\u0637\u0637\u0627\u062A {0} +const = \u064A\u062C\u0628 \u0623\u0646 \u062A\u0643\u0648\u0646 \u0627\u0644\u0642\u064A\u0645\u0629 \u0627\u0644\u062B\u0627\u0628\u062A\u0629 ''{0}'' +contains = \u0644\u0627 \u064A\u062D\u062A\u0648\u064A \u0639\u0644\u0649 \u0639\u0646\u0635\u0631 \u064A\u0642\u0648\u0645 \u0628\u062A\u0645\u0631\u064A\u0631 \u0639\u0645\u0644\u064A\u0627\u062A \u0627\u0644\u062A\u062D\u0642\u0642 \u0647\u0630\u0647: {1} +contains.max = \u064A\u062C\u0628 \u0623\u0646 \u064A\u062D\u062A\u0648\u064A \u0639\u0644\u0649 {0} \u0639\u0646\u0635\u0631 (\u0639\u0646\u0627\u0635\u0631) \u0639\u0644\u0649 \u0627\u0644\u0623\u0643\u062B\u0631 \u064A\u062C\u062A\u0627\u0632 \u0639\u0645\u0644\u064A\u0627\u062A \u0627\u0644\u062A\u062D\u0642\u0642 \u0647\u0630\u0647: {1} +contains.min = \u064A\u062C\u0628 \u0623\u0646 \u064A\u062D\u062A\u0648\u064A \u0639\u0644\u0649 {0} \u0639\u0646\u0635\u0631 (\u0639\u0646\u0627\u0635\u0631) \u0639\u0644\u0649 \u0627\u0644\u0623\u0642\u0644 \u064A\u0642\u0648\u0645 \u0628\u062A\u0645\u0631\u064A\u0631 \u0639\u0645\u0644\u064A\u0627\u062A \u0627\u0644\u062A\u062D\u0642\u0642 \u0647\u0630\u0647: {1} +dependencies = \u064A\u0648\u062C\u062F \u062E\u0637\u0623 \u0641\u064A \u0627\u0644\u062A\u0628\u0639\u064A\u0627\u062A {0} +dependentRequired = \u0628\u0647 \u062E\u0627\u0635\u064A\u0629 \u0645\u0641\u0642\u0648\u062F\u0629 ''{0}'' \u0648\u0647\u064A \u062A\u0627\u0628\u0639\u0629 \u0645\u0637\u0644\u0648\u0628\u0629 \u0644\u0623\u0646 ''{1}'' \u0645\u0648\u062C\u0648\u062F\u0629 +dependentSchemas = \u0628\u0647 \u062E\u0637\u0623 \u0641\u064AdependentSchemas {0} +enum = \u0644\u0627 \u064A\u062D\u062A\u0648\u064A \u0639\u0644\u0649 \u0642\u064A\u0645\u0629 \u0641\u064A \u0627\u0644\u062A\u0639\u062F\u0627\u062F {0} +exclusiveMaximum = \u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0644\u0647 \u0642\u064A\u0645\u0629 \u0642\u0635\u0648\u0649 \u062D\u0635\u0631\u064A\u0629 \u062A\u0628\u0644\u063A {0} +exclusiveMinimum = \u064A\u062C\u0628 \u0623\u0646 \u064A\u062D\u062A\u0648\u064A \u0639\u0644\u0649 \u0642\u064A\u0645\u0629 \u062F\u0646\u064A\u0627 \u062D\u0635\u0631\u064A\u0629 \u062A\u0628\u0644\u063A {0} +false = \u0645\u062E\u0637\u0637 ''{0}'' \u063A\u064A\u0631 \u0635\u062D\u064A\u062D +format = \u0644\u0627 \u064A\u0637\u0627\u0628\u0642 \u0627\u0644\u0646\u0645\u0637 {0} +format.date = \u0644\u0627 \u064A\u062A\u0637\u0627\u0628\u0642 \u0645\u0639 \u0627\u0644\u0646\u0645\u0637 {0} \u0648\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u062A\u0627\u0631\u064A\u062E\u064B\u0627 \u0643\u0627\u0645\u0644\u0627\u064B \u0635\u0627\u0644\u062D\u064B\u0627 \u0644\u0640 RFC 3339 +format.date-time = \u0644\u0627 \u064A\u062A\u0637\u0627\u0628\u0642 \u0645\u0639 \u0627\u0644\u0646\u0645\u0637 {0} \u0648\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u062A\u0627\u0631\u064A\u062E\u064B\u0627 \u0648\u0648\u0642\u062A\u064B\u0627 \u0635\u0627\u0644\u062D\u064B\u0627 \u0641\u064A RFC 3339 +format.duration = \u0644\u0627 \u064A\u062A\u0637\u0627\u0628\u0642 \u0645\u0639 \u0627\u0644\u0646\u0645\u0637 {0} \u0648\u064A\u062C\u0628 \u0623\u0646 \u062A\u0643\u0648\u0646 \u0645\u062F\u0629 ISO 8601 \u0635\u0627\u0644\u062D\u0629 +format.email = \u0644\u0627 \u064A\u062A\u0637\u0627\u0628\u0642 \u0645\u0639 \u0627\u0644\u0646\u0645\u0637 {0} \u0648\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0635\u0646\u062F\u0648\u0642 \u0628\u0631\u064A\u062F RFC 5321 \u0635\u0627\u0644\u062D\u064B\u0627 +format.ipv4 = \u0644\u0627 \u064A\u062A\u0637\u0627\u0628\u0642 \u0645\u0639 \u0627\u0644\u0646\u0645\u0637 {0} \u0648\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0639\u0646\u0648\u0627\u0646 IP \u0635\u0627\u0644\u062D\u064B\u0627 \u0644\u0640 RFC 2673 +format.ipv6 = \u0644\u0627 \u064A\u062A\u0637\u0627\u0628\u0642 \u0645\u0639 \u0627\u0644\u0646\u0645\u0637 {0} \u0648\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0639\u0646\u0648\u0627\u0646 IP \u0635\u0627\u0644\u062D\u064B\u0627 \u0644\u0640 RFC 4291 +format.idn-email = \u0644\u0627 \u064A\u062A\u0637\u0627\u0628\u0642 \u0645\u0639 \u0627\u0644\u0646\u0645\u0637 {0} \u0648\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0635\u0646\u062F\u0648\u0642 \u0628\u0631\u064A\u062F RFC 6531 \u0635\u0627\u0644\u062D\u064B\u0627 +format.idn-hostname = \u0644\u0627 \u064A\u062A\u0637\u0627\u0628\u0642 \u0645\u0639 \u0627\u0644\u0646\u0645\u0637 {0} \u0648\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0627\u0633\u0645 \u0645\u0636\u064A\u0641 \u062F\u0648\u0644\u064A\u064B\u0627 \u0635\u0627\u0644\u062D\u064B\u0627 \u0644\u0640 RFC 5890 +format.iri = \u0644\u0627 \u064A\u062A\u0637\u0627\u0628\u0642 \u0645\u0639 \u0627\u0644\u0646\u0645\u0637 {0} \u0648\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 RFC 3987 IRI \u0635\u0627\u0644\u062D\u064B\u0627 +format.iri-reference = \u0644\u0627 \u064A\u062A\u0637\u0627\u0628\u0642 \u0645\u0639 \u0627\u0644\u0646\u0645\u0637 {0} \u0648\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0645\u0631\u062C\u0639 RFC 3987 IRI \u0635\u0627\u0644\u062D\u064B\u0627 +format.uri = \u0644\u0627 \u064A\u062A\u0637\u0627\u0628\u0642 \u0645\u0639 \u0627\u0644\u0646\u0645\u0637 {0} \u0648\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0639\u0646\u0648\u0627\u0646 URI \u0635\u0627\u0644\u062D\u064B\u0627 \u0644\u0640 RFC 3986 +format.uri-reference = \u0644\u0627 \u064A\u062A\u0637\u0627\u0628\u0642 \u0645\u0639 \u0627\u0644\u0646\u0645\u0637 {0} \u0648\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0645\u0631\u062C\u0639 URI \u0635\u0627\u0644\u062D\u064B\u0627 \u0644\u0640 RFC 3986 +format.uri-template = \u0644\u0627 \u064A\u062A\u0637\u0627\u0628\u0642 \u0645\u0639 \u0627\u0644\u0646\u0645\u0637 {0} \u0648\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0642\u0627\u0644\u0628 URI RFC 6570 \u0635\u0627\u0644\u062D\u064B\u0627 +format.uuid = \u0644\u0627 \u064A\u062A\u0637\u0627\u0628\u0642 \u0645\u0639 \u0627\u0644\u0646\u0645\u0637 {0} \u0648\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 RFC 4122 UUID \u0635\u0627\u0644\u062D\u064B\u0627 +format.regex = \u0644\u0627 \u064A\u062A\u0637\u0627\u0628\u0642 \u0645\u0639 \u0627\u0644\u0646\u0645\u0637 {0} \u0648\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u062A\u0639\u0628\u064A\u0631\u064B\u0627 \u0639\u0627\u062F\u064A\u064B\u0627 \u0635\u0627\u0644\u062D\u064B\u0627 \u0644\u0640 ECMA-262 +format.time = \u0644\u0627 \u064A\u062A\u0637\u0627\u0628\u0642 \u0645\u0639 \u0627\u0644\u0646\u0645\u0637 {0} \u0648\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0648\u0642\u062A RFC 3339 \u0635\u0627\u0644\u062D\u064B\u0627 +format.hostname = \u0644\u0627 \u064A\u062A\u0637\u0627\u0628\u0642 \u0645\u0639 \u0627\u0644\u0646\u0645\u0637 {0} \u0648\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0627\u0633\u0645 \u0645\u0636\u064A\u0641 RFC 1123 \u0635\u0627\u0644\u062D\u064B\u0627 +format.json-pointer = \u0644\u0627 \u064A\u062A\u0637\u0627\u0628\u0642 \u0645\u0639 \u0627\u0644\u0646\u0645\u0637 {0} \u0648\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0645\u0624\u0634\u0631 RFC 6901 JSON \u0635\u0627\u0644\u062D\u064B\u0627 +format.relative-json-pointer = \u0644\u0627 \u064A\u062A\u0637\u0627\u0628\u0642 \u0645\u0639 \u0627\u0644\u0646\u0645\u0637 {0} \u0648\u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0645\u0624\u0634\u0631 IETF Relative JSON \u0635\u0627\u0644\u062D\u064B\u0627 +format.unknown = \u0644\u0647 \u062A\u0646\u0633\u064A\u0642 \u063A\u064A\u0631 \u0645\u0639\u0631\u0648\u0641 ''{0}'' +id = ''{0}'' \u0644\u064A\u0633 {1} \u0635\u0627\u0644\u062D\u064B\u0627 +items = \u0644\u0645 \u064A\u062A\u0645 \u062A\u0639\u0631\u064A\u0641 \u0627\u0644\u0641\u0647\u0631\u0633 ''{0}'' \u0641\u064A \u0627\u0644\u0645\u062E\u0637\u0637 \u0648\u0644\u0627 \u064A\u0633\u0645\u062D \u0627\u0644\u0645\u062E\u0637\u0637 \u0628\u0639\u0646\u0627\u0635\u0631 \u0625\u0636\u0627\u0641\u064A\u0629 +maxContains = \u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0639\u062F\u062F\u064B\u0627 \u0635\u062D\u064A\u062D\u064B\u0627 \u063A\u064A\u0631 \u0633\u0627\u0644\u0628 \u0641\u064A {0} +maxItems = \u064A\u062C\u0628 \u0623\u0646 \u064A\u062D\u062A\u0648\u064A \u0639\u0644\u0649 {0} \u0639\u0646\u0635\u0631 \u0639\u0644\u0649 \u0627\u0644\u0623\u0643\u062B\u0631 \u0648\u0644\u0643\u0646 \u062A\u0645 \u0627\u0644\u0639\u062B\u0648\u0631 \u0639\u0644\u0649 {1} +maxLength = \u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0637\u0648\u0644\u0647 {0} \u062D\u0631\u0641\u064B\u0627 \u0639\u0644\u0649 \u0627\u0644\u0623\u0643\u062B\u0631 +maxProperties = \u064A\u062C\u0628 \u0623\u0646 \u064A\u062D\u062A\u0648\u064A \u0639\u0644\u0649 {0} \u0645\u0646 \u0627\u0644\u062E\u0635\u0627\u0626\u0635 \u0639\u0644\u0649 \u0627\u0644\u0623\u0643\u062B\u0631 +maximum = \u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0627\u0644\u062D\u062F \u0627\u0644\u0623\u0642\u0635\u0649 \u0644\u0642\u064A\u0645\u0629 {0} +minContains = \u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0639\u062F\u062F\u064B\u0627 \u0635\u062D\u064A\u062D\u064B\u0627 \u063A\u064A\u0631 \u0633\u0627\u0644\u0628 \u0641\u064A {0} +minContainsVsMaxContains = \u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 minContains \u0623\u0642\u0644 \u0645\u0646 \u0623\u0648 \u064A\u0633\u0627\u0648\u064A maxContains \u0641\u064A {0} +minItems = \u064A\u062C\u0628 \u0623\u0646 \u064A\u062D\u062A\u0648\u064A \u0639\u0644\u0649 {0} \u0639\u0646\u0635\u0631 \u0639\u0644\u0649 \u0627\u0644\u0623\u0642\u0644 \u0648\u0644\u0643\u0646 \u062A\u0645 \u0627\u0644\u0639\u062B\u0648\u0631 \u0639\u0644\u0649 {1} +minLength = \u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0637\u0648\u0644\u0647 {0} \u062D\u0631\u0641\u064B\u0627 \u0639\u0644\u0649 \u0627\u0644\u0623\u0642\u0644 +minProperties = \u064A\u062C\u0628 \u0623\u0646 \u062A\u062D\u062A\u0648\u064A \u0639\u0644\u0649 {0} \u0645\u0646 \u0627\u0644\u062E\u0635\u0627\u0626\u0635 \u0639\u0644\u0649 \u0627\u0644\u0623\u0642\u0644 +minimum = \u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0627\u0644\u062D\u062F \u0627\u0644\u0623\u062F\u0646\u0649 \u0644\u0642\u064A\u0645\u0629 {0} +multipleOf = \u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0645\u0646 \u0645\u0636\u0627\u0639\u0641\u0627\u062A {0} +not = \u064A\u062C\u0628 \u0623\u0646 \u0644\u0627 \u064A\u0643\u0648\u0646 \u0635\u0627\u0644\u062D\u064B\u0627 \u0644\u0644\u0645\u062E\u0637\u0637 {0} +notAllowed = \u0627\u0644\u062E\u0627\u0635\u064A\u0629 ''{0}'' \u063A\u064A\u0631 \u0645\u0633\u0645\u0648\u062D \u0628\u0647\u0627 \u0648\u0644\u0643\u0646\u0647\u0627 \u0645\u0648\u062C\u0648\u062F\u0629 \u0641\u064A \u0627\u0644\u0628\u064A\u0627\u0646\u0627\u062A +oneOf = \u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0635\u0627\u0644\u062D\u064B\u0627 \u0644\u0645\u062E\u0637\u0637 \u0648\u0627\u062D\u062F \u0641\u0642\u0637\u060C \u0648\u0644\u0643\u0646 {0} \u0635\u0627\u0644\u062D +oneOf.indexes = \u064A\u062C\u0628 \u0623\u0646 \u064A\u0643\u0648\u0646 \u0635\u0627\u0644\u062D\u064B\u0627 \u0644\u0645\u062E\u0637\u0637 \u0648\u0627\u062D\u062F \u0641\u0642\u0637\u060C \u0648\u0644\u0643\u0646 {0} \u0635\u0627\u0644\u062D \u0645\u0639 \u0627\u0644\u0641\u0647\u0627\u0631\u0633 ''{1}'' +pattern = \u0644\u0627 \u064A\u062A\u0637\u0627\u0628\u0642 \u0645\u0639 \u0646\u0645\u0637 \u0627\u0644\u062A\u0639\u0628\u064A\u0631 \u0627\u0644\u0639\u0627\u062F\u064A {0} +patternProperties = \u0628\u0647 \u0628\u0639\u0636 \u0627\u0644\u0623\u062E\u0637\u0627\u0621 \u0641\u064A ''\u062E\u0635\u0627\u0626\u0635 \u0627\u0644\u0646\u0645\u0637'' +prefixItems = \u0644\u0645 \u064A\u062A\u0645 \u0627\u0644\u0639\u062B\u0648\u0631 \u0639\u0644\u0649 \u0623\u062F\u0627\u0629 \u0627\u0644\u062A\u062D\u0642\u0642 \u0641\u064A \u0647\u0630\u0627 \u0627\u0644\u0641\u0647\u0631\u0633 +properties = \u064A\u0648\u062C\u062F \u062E\u0637\u0623 \u0641\u064A ''\u0627\u0644\u062E\u0635\u0627\u0626\u0635'' +propertyNames = \u0627\u0633\u0645 \u0627\u0644\u062E\u0627\u0635\u064A\u0629 ''{0}'' \u063A\u064A\u0631 \u0635\u0627\u0644\u062D: {1} +readOnly = \u0647\u0648 \u062D\u0642\u0644 \u0644\u0644\u0642\u0631\u0627\u0621\u0629 \u0641\u0642\u0637\u060C \u0648\u0644\u0627 \u064A\u0645\u0643\u0646 \u062A\u063A\u064A\u064A\u0631\u0647 +required = \u0627\u0644\u062E\u0627\u0635\u064A\u0629 \u0627\u0644\u0645\u0637\u0644\u0648\u0628\u0629 ''{0}'' \u063A\u064A\u0631 \u0645\u0648\u062C\u0648\u062F\u0629 +type = \u062A\u0645 \u0627\u0644\u0639\u062B\u0648\u0631 \u0639\u0644\u0649 {0}\u060C \u0648\u0627\u0644\u0645\u062A\u0648\u0642\u0639 \u0647\u0648 {1}. +unevaluatedItems = \u0644\u0645 \u064A\u062A\u0645 \u062A\u0642\u064A\u064A\u0645 \u0627\u0644\u0641\u0647\u0631\u0633 ''{0}'' \u0648\u0644\u0627 \u064A\u0633\u0645\u062D \u0627\u0644\u0645\u062E\u0637\u0637 \u0628\u0627\u0644\u0639\u0646\u0627\u0635\u0631 \u063A\u064A\u0631 \u0627\u0644\u0645\u0642\u064A\u064E\u0651\u0645\u0629 +unevaluatedProperties = \u0627\u0644\u062E\u0627\u0635\u064A\u0629 ''{0}'' \u0644\u0645 \u064A\u062A\u0645 \u062A\u0642\u064A\u064A\u0645\u0647\u0627 \u0648\u0644\u0627 \u064A\u0633\u0645\u062D \u0627\u0644\u0645\u062E\u0637\u0637 \u0628\u0627\u0644\u062E\u0635\u0627\u0626\u0635 \u063A\u064A\u0631 \u0627\u0644\u0645\u0642\u064A\u064E\u0651\u0645\u0629 +unionType = \u062A\u0645 \u0627\u0644\u0639\u062B\u0648\u0631 \u0639\u0644\u0649 {0}\u060C \u0648\u0627\u0644\u0645\u062A\u0648\u0642\u0639 \u0647\u0648 {1}. +uniqueItems = \u064A\u062C\u0628 \u0623\u0646 \u062A\u062D\u062A\u0648\u064A \u0639\u0644\u0649 \u0639\u0646\u0627\u0635\u0631 \u0641\u0631\u064A\u062F\u0629 \u0641\u0642\u0637 \u0641\u064A \u0627\u0644\u0645\u0635\u0641\u0648\u0641\u0629 +writeOnly = \u0647\u0648 \u062D\u0642\u0644 \u0644\u0644\u0643\u062A\u0627\u0628\u0629 \u0641\u0642\u0637\u060C \u0648\u0644\u0627 \u064A\u0645\u0643\u0646 \u0623\u0646 \u064A\u0638\u0647\u0631 \u0641\u064A \u0627\u0644\u0628\u064A\u0627\u0646\u0627\u062A +contentEncoding = \u0644\u0627 \u064A\u0637\u0627\u0628\u0642 \u062A\u0631\u0645\u064A\u0632 \u0627\u0644\u0645\u062D\u062A\u0648\u0649 {0} +contentMediaType = \u0644\u064A\u0633 \u0645\u062D\u062A\u0648\u0649 \u062E\u0627\u0635\u064B\u0627 \u0628\u064A diff --git a/src/main/resources/jsv-messages_cs.properties b/src/main/resources/jsv-messages_cs.properties index 49088a932..d6b35668c 100644 --- a/src/main/resources/jsv-messages_cs.properties +++ b/src/main/resources/jsv-messages_cs.properties @@ -1,70 +1,70 @@ -$ref = {0}: obsahuje chybu s ''refs'' -additionalItems = {0}: index ''{1}'' není ve schématu definován a schéma nepovoluje dal\u0161í polo\u017Eky -additionalProperties = {0}: vlastnost ''{1}'' není ve schématu definována a schéma neumo\u017E\u0148uje dal\u0161í vlastnosti -allOf = {0}: musí být platné pro v\u0161echna schémata {1} -anyOf = {0}: musí být platné pro kterékoli ze schémat {1} -const = {0}: musí být konstantní hodnota ''{1}'' -contains = {0}: neobsahuje prvek, který pro\u0161el t\u011Bmito ov\u011B\u0159eními: {2} -contains.max = {0}: musí obsahovat nejvý\u0161e {1} prvk\u016F, které projdou t\u011Bmito ov\u011B\u0159eními: {2} -contains.min = {0}: musí obsahovat alespo\u0148 {1} prvk\u016F, které projdou t\u011Bmito ov\u011B\u0159eními: {2} -dependencies = {0}: obsahuje chybu se závislostmi {1} -dependentRequired = {0}: má chyb\u011Bjící vlastnost ''{1}'', která je závislá povinná, proto\u017Ee ''{2}'' je p\u0159ítomen -dependentSchemas = {0}: obsahuje chybu s dependentSchemas {1} -enum = {0}: nemá hodnotu ve vý\u010Dtu {1} -exclusiveMaximum = {0}: musí mít exkluzivní maximální hodnotu {1} -exclusiveMinimum = {0}: musí mít exkluzivní minimální hodnotu {1} -false = {0}: schéma pro ''{1}'' je nepravdivé -format = {0}: neodpovídá vzoru {1} {2} -format.date = {0}: neodpovídá vzoru {1} musí být platné plné datum RFC 3339 -format.date-time = {0}: neodpovídá vzoru {1} musí být platné datum a \u010Das RFC 3339 -format.duration = {0}: neodpovídá vzoru {1}, musí mít platnou dobu trvání ISO 8601 -format.email = {0}: neodpovídá vzoru {1} musí být platná po\u0161tovní schránka RFC 5321 -format.ipv4 = {0}: neodpovídá vzoru {1} musí být platná IP adresa RFC 2673 -format.ipv6 = {0}: neodpovídá vzoru {1} musí být platná IP adresa RFC 4291 -format.idn-email = {0}: neodpovídá vzoru {1} musí být platná po\u0161tovní schránka RFC 6531 -format.idn-hostname = {0}: neodpovídá vzoru {1}, musí být platným internacionalizovaným názvem hostitele RFC 5890 -format.iri = {0}: neodpovídá vzoru {1} musí být platný RFC 3987 IRI -format.iri-reference = {0}: neodpovídá vzoru {1} musí být platný RFC 3987 IRI-reference -format.uri = {0}: neodpovídá vzoru {1} musí být platný RFC 3986 URI -format.uri-reference = {0}: neodpovídá vzoru {1} musí být platný RFC 3986 URI odkaz -format.uri-template = {0}: neodpovídá vzoru {1} musí být platná \u0161ablona URI RFC 6570 -format.uuid = {0}: neodpovídá vzoru {1} musí být platný RFC 4122 UUID -format.regex = {0}: neodpovídá vzoru {1} musí být platný regulární výraz ECMA-262 -format.time = {0}: neodpovídá vzoru {1} musí být platný \u010Das RFC 3339 -format.hostname = {0}: neodpovídá vzoru {1} musí být platný název hostitele RFC 1123 -format.json-pointer = {0}: neodpovídá vzoru {1} musí být platný RFC 6901 JSON ukazatel -format.relative-json-pointer = {0}: neodpovídá vzoru {1} musí být platný IETF relativní ukazatel JSON -format.unknown = {0}: má neznámý formát ''{1}'' -id = {0}: ''{1}'' není platný {2} -items = {0}: index ''{1}'' není ve schématu definován a schéma neumo\u017E\u0148uje dal\u0161í polo\u017Eky -maxContains = {0}: musí být nezáporné celé \u010Díslo v {1} -maxItems = {0}: musí mít maximáln\u011B {1} polo\u017Eek, ale nalezeno {2} -maxLength = {0}: musí mít maximáln\u011B {1} znak\u016F -maxProperties = {0}: musí mít maximáln\u011B {1} vlastností -maximum = {0}: musí mít maximální hodnotu {1} -minContains = {0}: musí být nezáporné celé \u010Díslo v {1} -minContainsVsMaxContains = {0}: minContains musí být men\u0161í nebo roven maxContains v {1} -minItems = {0}: musí mít alespo\u0148 {1} polo\u017Eek, ale nalezeno {2} -minLength = {0}: musí mít alespo\u0148 {1} znak\u016F -minProperties = {0}: musí mít alespo\u0148 {1} vlastností -minimum = {0}: musí mít minimální hodnotu {1} -multipleOf = {0}: musí být násobkem {1} -not = {0}: nesmí být platné pro schéma {1} -notAllowed = {0}: vlastnost ''{1}'' není povolena, ale je v datech -oneOf = {0}: musí být platné pro jedno a pouze jedno schéma, ale {1} jsou platné -oneOf.indexes = {0}: musí být platné pro jedno a pouze jedno schéma, ale {1} jsou platné s indexy ''{2}'' -pattern = {0}: neodpovídá vzoru regulárního výrazu {1} -patternProperties = {0}: obsahuje n\u011Bjakou chybu s ''vlastnostmi vzoru'' -prefixItems = {0}: v tomto indexu nebyl nalezen \u017Eádný validátor -properties = {0}: obsahuje chybu s ''vlastnosti'' -propertyNames = {0}: název vlastnosti ''{1}'' není platný: {2} -readOnly = {0}: je pole pouze pro \u010Dtení, nelze jej zm\u011Bnit -required = {0}: po\u017Eadovaná vlastnost ''{1}'' nebyla nalezena -type = {0}: nalezeno {1}, o\u010Dekáváno {2} -unevaluatedItems = {0}: index ''{1}'' není vyhodnocen a schéma nepovoluje neohodnocené polo\u017Eky -unevaluatedProperties = {0}: vlastnost ''{1}'' není vyhodnocena a schéma nepovoluje neohodnocené vlastnosti -unionType = {0}: nalezeno {1}, o\u010Dekáváno {2} -uniqueItems = {0}: musí mít v poli pouze jedine\u010Dné polo\u017Eky -writeOnly = {0}: je pole pouze pro zápis, nem\u016F\u017Ee se objevit v datech -contentEncoding = {0}: neodpovídá kódování obsahu {1} -contentMediaType = {0}: není obsah já +$ref = obsahuje chybu s ''refs'' +additionalItems = index ''{0}'' není ve schématu definován a schéma nepovoluje dal\u0161í polo\u017Eky +additionalProperties = vlastnost ''{0}'' není ve schématu definována a schéma neumo\u017E\u0148uje dal\u0161í vlastnosti +allOf = musí být platné pro v\u0161echna schémata {0} +anyOf = musí být platné pro kterékoli ze schémat {0} +const = musí být konstantní hodnota ''{0}'' +contains = neobsahuje prvek, který pro\u0161el t\u011Bmito ov\u011B\u0159eními: {1} +contains.max = musí obsahovat nejvý\u0161e {0} prvk\u016F, které projdou t\u011Bmito ov\u011B\u0159eními: {1} +contains.min = musí obsahovat alespo\u0148 {0} prvk\u016F, které projdou t\u011Bmito ov\u011B\u0159eními: {1} +dependencies = obsahuje chybu se závislostmi {0} +dependentRequired = má chyb\u011Bjící vlastnost ''{0}'', která je závislá povinná, proto\u017Ee ''{1}'' je p\u0159ítomen +dependentSchemas = obsahuje chybu s dependentSchemas {0} +enum = nemá hodnotu ve vý\u010Dtu {0} +exclusiveMaximum = musí mít exkluzivní maximální hodnotu {0} +exclusiveMinimum = musí mít exkluzivní minimální hodnotu {0} +false = schéma pro ''{0}'' je nepravdivé +format = neodpovídá vzoru {0} +format.date = neodpovídá vzoru {0} musí být platné plné datum RFC 3339 +format.date-time = neodpovídá vzoru {0} musí být platné datum a \u010Das RFC 3339 +format.duration = neodpovídá vzoru {0}, musí mít platnou dobu trvání ISO 8601 +format.email = neodpovídá vzoru {0} musí být platná po\u0161tovní schránka RFC 5321 +format.ipv4 = neodpovídá vzoru {0} musí být platná IP adresa RFC 2673 +format.ipv6 = neodpovídá vzoru {0} musí být platná IP adresa RFC 4291 +format.idn-email = neodpovídá vzoru {0} musí být platná po\u0161tovní schránka RFC 6531 +format.idn-hostname = neodpovídá vzoru {0}, musí být platným internacionalizovaným názvem hostitele RFC 5890 +format.iri = neodpovídá vzoru {0} musí být platný RFC 3987 IRI +format.iri-reference = neodpovídá vzoru {0} musí být platný RFC 3987 IRI-reference +format.uri = neodpovídá vzoru {0} musí být platný RFC 3986 URI +format.uri-reference = neodpovídá vzoru {0} musí být platný RFC 3986 URI odkaz +format.uri-template = neodpovídá vzoru {0} musí být platná \u0161ablona URI RFC 6570 +format.uuid = neodpovídá vzoru {0} musí být platný RFC 4122 UUID +format.regex = neodpovídá vzoru {0} musí být platný regulární výraz ECMA-262 +format.time = neodpovídá vzoru {0} musí být platný \u010Das RFC 3339 +format.hostname = neodpovídá vzoru {0} musí být platný název hostitele RFC 1123 +format.json-pointer = neodpovídá vzoru {0} musí být platný RFC 6901 JSON ukazatel +format.relative-json-pointer = neodpovídá vzoru {0} musí být platný IETF relativní ukazatel JSON +format.unknown = má neznámý formát ''{0}'' +id = ''{0}'' není platný {1} +items = index ''{0}'' není ve schématu definován a schéma neumo\u017E\u0148uje dal\u0161í polo\u017Eky +maxContains = musí být nezáporné celé \u010Díslo v {0} +maxItems = musí mít maximáln\u011B {0} polo\u017Eek, ale nalezeno {1} +maxLength = musí mít maximáln\u011B {0} znak\u016F +maxProperties = musí mít maximáln\u011B {0} vlastností +maximum = musí mít maximální hodnotu {0} +minContains = musí být nezáporné celé \u010Díslo v {0} +minContainsVsMaxContains = minContains musí být men\u0161í nebo roven maxContains v {0} +minItems = musí mít alespo\u0148 {0} polo\u017Eek, ale nalezeno {1} +minLength = musí mít alespo\u0148 {0} znak\u016F +minProperties = musí mít alespo\u0148 {0} vlastností +minimum = musí mít minimální hodnotu {0} +multipleOf = musí být násobkem {0} +not = nesmí být platné pro schéma {0} +notAllowed = vlastnost ''{0}'' není povolena, ale je v datech +oneOf = musí být platné pro jedno a pouze jedno schéma, ale {0} jsou platné +oneOf.indexes = musí být platné pro jedno a pouze jedno schéma, ale {0} jsou platné s indexy ''{1}'' +pattern = neodpovídá vzoru regulárního výrazu {0} +patternProperties = obsahuje n\u011Bjakou chybu s ''vlastnostmi vzoru'' +prefixItems = v tomto indexu nebyl nalezen \u017Eádný validátor +properties = obsahuje chybu s ''vlastnosti'' +propertyNames = název vlastnosti ''{0}'' není platný: {1} +readOnly = je pole pouze pro \u010Dtení, nelze jej zm\u011Bnit +required = po\u017Eadovaná vlastnost ''{0}'' nebyla nalezena +type = nalezeno {0}, o\u010Dekáváno {1} +unevaluatedItems = index ''{0}'' není vyhodnocen a schéma nepovoluje neohodnocené polo\u017Eky +unevaluatedProperties = vlastnost ''{0}'' není vyhodnocena a schéma nepovoluje neohodnocené vlastnosti +unionType = nalezeno {0}, o\u010Dekáváno {1} +uniqueItems = musí mít v poli pouze jedine\u010Dné polo\u017Eky +writeOnly = je pole pouze pro zápis, nem\u016F\u017Ee se objevit v datech +contentEncoding = neodpovídá kódování obsahu {0} +contentMediaType = není obsah já diff --git a/src/main/resources/jsv-messages_da.properties b/src/main/resources/jsv-messages_da.properties index 458269d9d..f1eaa1375 100644 --- a/src/main/resources/jsv-messages_da.properties +++ b/src/main/resources/jsv-messages_da.properties @@ -1,70 +1,70 @@ -$ref = {0}: har en fejl med ''refs'' -additionalItems = {0}: indeks ''{1}'' er ikke defineret i skemaet, og skemaet tillader ikke yderligere elementer -additionalProperties = {0}: egenskaben ''{1}'' er ikke defineret i skemaet, og skemaet tillader ikke yderligere egenskaber -allOf = {0}: skal være gyldig for alle skemaerne {1} -anyOf = {0}: skal være gyldig for et hvilket som helst af skemaerne {1} -const = {0}: skal være den konstante værdi ''{1}'' -contains = {0}: indeholder ikke et element, der består disse valideringer: {2} -contains.max = {0}: må højst indeholde {1} element(er), der består disse valideringer: {2} -contains.min = {0}: skal indeholde mindst {1} element(er), der består disse valideringer: {2} -dependencies = {0}: har en fejl med afhængigheder {1} -dependentRequired = {0}: har en manglende egenskab ''{1}'', som er afhængig påkrævet, fordi ''{2}'' er til stede -dependentSchemas = {0}: har en fejl med dependentSchemas {1} -enum = {0}: har ikke en værdi i opregningen {1} -exclusiveMaximum = {0}: skal have en eksklusiv maksimumværdi på {1} -exclusiveMinimum = {0}: skal have en eksklusiv minimumsværdi på {1} -false = {0}: skemaet for ''{1}'' er falsk -format = {0}: matcher ikke {1}-mønsteret {2} -format.date = {0}: matcher ikke {1}-mønsteret skal være en gyldig RFC 3339 fuld-dato -format.date-time = {0}: matcher ikke {1}-mønsteret skal være en gyldig RFC 3339 dato-tid -format.duration = {0}: matcher ikke {1}-mønsteret skal være en gyldig ISO 8601-varighed -format.email = {0}: matcher ikke {1}-mønsteret skal være en gyldig RFC 5321-postkasse -format.ipv4 = {0}: matcher ikke {1}-mønsteret skal være en gyldig RFC 2673 IP-adresse -format.ipv6 = {0}: matcher ikke {1}-mønsteret skal være en gyldig RFC 4291 IP-adresse -format.idn-email = {0}: matcher ikke {1}-mønsteret skal være en gyldig RFC 6531-postkasse -format.idn-hostname = {0}: matcher ikke {1}-mønsteret skal være et gyldigt RFC 5890 internationaliseret værtsnavn -format.iri = {0}: matcher ikke {1}-mønsteret skal være en gyldig RFC 3987 IRI -format.iri-reference = {0}: matcher ikke {1}-mønsteret skal være en gyldig RFC 3987 IRI-reference -format.uri = {0}: matcher ikke {1}-mønsteret skal være en gyldig RFC 3986 URI -format.uri-reference = {0}: matcher ikke {1}-mønsteret skal være en gyldig RFC 3986 URI-reference -format.uri-template = {0}: matcher ikke {1}-mønsteret skal være en gyldig RFC 6570 URI-skabelon -format.uuid = {0}: matcher ikke {1}-mønsteret skal være et gyldigt RFC 4122 UUID -format.regex = {0}: matcher ikke {1}-mønsteret skal være et gyldigt ECMA-262 regulært udtryk -format.time = {0}: matcher ikke {1}-mønsteret skal være en gyldig RFC 3339-tid -format.hostname = {0}: matcher ikke {1}-mønsteret skal være et gyldigt RFC 1123-værtsnavn -format.json-pointer = {0}: matcher ikke {1}-mønsteret skal være en gyldig RFC 6901 JSON-peger -format.relative-json-pointer = {0}: matcher ikke {1}-mønsteret skal være en gyldig IETF Relativ JSON-peger -format.unknown = {0}: har et ukendt format ''{1}'' -id = {0}: ''{1}'' er ikke en gyldig {2} -items = {0}: indeks ''{1}'' er ikke defineret i skemaet, og skemaet tillader ikke yderligere elementer -maxContains = {0}: skal være et ikke-negativt heltal i {1} -maxItems = {0}: må højst have {1} varer, men fundet {2} -maxLength = {0}: må højst være på {1} tegn -maxProperties = {0}: må højst have {1} egenskaber -maximum = {0}: skal have en maksimal værdi på {1} -minContains = {0}: skal være et ikke-negativt heltal i {1} -minContainsVsMaxContains = {0}: minContains skal være mindre end eller lig med maxContains i {1} -minItems = {0}: skal have mindst {1} elementer, men fundet {2} -minLength = {0}: skal være mindst {1} tegn lang -minProperties = {0}: skal have mindst {1} egenskaber -minimum = {0}: skal have en minimumsværdi på {1} -multipleOf = {0}: skal være multiplum af {1} -not = {0}: må ikke være gyldig for skemaet {1} -notAllowed = {0}: egenskaben ''{1}'' er ikke tilladt, men den er i dataene -oneOf = {0}: skal være gyldig for ét og kun ét skema, men {1} er gyldige -oneOf.indexes = {0}: skal være gyldig for ét og kun ét skema, men {1} er gyldige med indekser ''{2}'' -pattern = {0}: matcher ikke regex-mønsteret {1} -patternProperties = {0}: har en fejl med ''mønsteregenskaber'' -prefixItems = {0}: ingen validator fundet i dette indeks -properties = {0}: har en fejl med ''egenskaber'' -propertyNames = {0}: Ejendommen ''{1}'' navn er ikke gyldigt: {2} -readOnly = {0}: er et skrivebeskyttet felt, det kan ikke ændres -required = {0}: påkrævet egenskab ''{1}'' blev ikke fundet -type = {0}: {1} fundet, {2} forventet -unevaluatedItems = {0}: indeks ''{1}'' evalueres ikke, og skemaet tillader ikke uevaluerede elementer -unevaluatedProperties = {0}: egenskaben ''{1}'' evalueres ikke, og skemaet tillader ikke uevaluerede egenskaber -unionType = {0}: {1} fundet, {2} forventet -uniqueItems = {0}: må kun have unikke elementer i arrayet -writeOnly = {0}: er et skrivebeskyttet felt, det kan ikke vises i dataene -contentEncoding = {0}: matcher ikke indholdskodning {1} -contentMediaType = {0}: er ikke et indholds mig +$ref = har en fejl med ''refs'' +additionalItems = indeks ''{0}'' er ikke defineret i skemaet, og skemaet tillader ikke yderligere elementer +additionalProperties = egenskaben ''{0}'' er ikke defineret i skemaet, og skemaet tillader ikke yderligere egenskaber +allOf = skal være gyldig for alle skemaerne {0} +anyOf = skal være gyldig for et hvilket som helst af skemaerne {0} +const = skal være den konstante værdi ''{0}'' +contains = indeholder ikke et element, der består disse valideringer: {1} +contains.max = må højst indeholde {0} element(er), der består disse valideringer: {1} +contains.min = skal indeholde mindst {0} element(er), der består disse valideringer: {1} +dependencies = har en fejl med afhængigheder {0} +dependentRequired = har en manglende egenskab ''{0}'', som er afhængig påkrævet, fordi ''{1}'' er til stede +dependentSchemas = har en fejl med dependentSchemas {0} +enum = har ikke en værdi i opregningen {0} +exclusiveMaximum = skal have en eksklusiv maksimumværdi på {0} +exclusiveMinimum = skal have en eksklusiv minimumsværdi på {0} +false = skemaet for ''{0}'' er falsk +format = matcher ikke {0}-mønsteret +format.date = matcher ikke {0}-mønsteret skal være en gyldig RFC 3339 fuld-dato +format.date-time = matcher ikke {0}-mønsteret skal være en gyldig RFC 3339 dato-tid +format.duration = matcher ikke {0}-mønsteret skal være en gyldig ISO 8601-varighed +format.email = matcher ikke {0}-mønsteret skal være en gyldig RFC 5321-postkasse +format.ipv4 = matcher ikke {0}-mønsteret skal være en gyldig RFC 2673 IP-adresse +format.ipv6 = matcher ikke {0}-mønsteret skal være en gyldig RFC 4291 IP-adresse +format.idn-email = matcher ikke {0}-mønsteret skal være en gyldig RFC 6531-postkasse +format.idn-hostname = matcher ikke {0}-mønsteret skal være et gyldigt RFC 5890 internationaliseret værtsnavn +format.iri = matcher ikke {0}-mønsteret skal være en gyldig RFC 3987 IRI +format.iri-reference = matcher ikke {0}-mønsteret skal være en gyldig RFC 3987 IRI-reference +format.uri = matcher ikke {0}-mønsteret skal være en gyldig RFC 3986 URI +format.uri-reference = matcher ikke {0}-mønsteret skal være en gyldig RFC 3986 URI-reference +format.uri-template = matcher ikke {0}-mønsteret skal være en gyldig RFC 6570 URI-skabelon +format.uuid = matcher ikke {0}-mønsteret skal være et gyldigt RFC 4122 UUID +format.regex = matcher ikke {0}-mønsteret skal være et gyldigt ECMA-262 regulært udtryk +format.time = matcher ikke {0}-mønsteret skal være en gyldig RFC 3339-tid +format.hostname = matcher ikke {0}-mønsteret skal være et gyldigt RFC 1123-værtsnavn +format.json-pointer = matcher ikke {0}-mønsteret skal være en gyldig RFC 6901 JSON-peger +format.relative-json-pointer = matcher ikke {0}-mønsteret skal være en gyldig IETF Relativ JSON-peger +format.unknown = har et ukendt format ''{0}'' +id = ''{0}'' er ikke en gyldig {1} +items = indeks ''{0}'' er ikke defineret i skemaet, og skemaet tillader ikke yderligere elementer +maxContains = skal være et ikke-negativt heltal i {0} +maxItems = må højst have {0} varer, men fundet {1} +maxLength = må højst være på {0} tegn +maxProperties = må højst have {0} egenskaber +maximum = skal have en maksimal værdi på {0} +minContains = skal være et ikke-negativt heltal i {0} +minContainsVsMaxContains = minContains skal være mindre end eller lig med maxContains i {0} +minItems = skal have mindst {0} elementer, men fundet {1} +minLength = skal være mindst {0} tegn lang +minProperties = skal have mindst {0} egenskaber +minimum = skal have en minimumsværdi på {0} +multipleOf = skal være multiplum af {0} +not = må ikke være gyldig for skemaet {0} +notAllowed = egenskaben ''{0}'' er ikke tilladt, men den er i dataene +oneOf = skal være gyldig for ét og kun ét skema, men {0} er gyldige +oneOf.indexes = skal være gyldig for ét og kun ét skema, men {0} er gyldige med indekser ''{1}'' +pattern = matcher ikke regex-mønsteret {0} +patternProperties = har en fejl med ''mønsteregenskaber'' +prefixItems = ingen validator fundet i dette indeks +properties = har en fejl med ''egenskaber'' +propertyNames = Ejendommen ''{0}'' navn er ikke gyldigt: {1} +readOnly = er et skrivebeskyttet felt, det kan ikke ændres +required = påkrævet egenskab ''{0}'' blev ikke fundet +type = {0} fundet, {1} forventet +unevaluatedItems = indeks ''{0}'' evalueres ikke, og skemaet tillader ikke uevaluerede elementer +unevaluatedProperties = egenskaben ''{0}'' evalueres ikke, og skemaet tillader ikke uevaluerede egenskaber +unionType = {0} fundet, {1} forventet +uniqueItems = må kun have unikke elementer i arrayet +writeOnly = er et skrivebeskyttet felt, det kan ikke vises i dataene +contentEncoding = matcher ikke indholdskodning {0} +contentMediaType = er ikke et indholds mig diff --git a/src/main/resources/jsv-messages_de.properties b/src/main/resources/jsv-messages_de.properties index 13d280605..7eae3b691 100644 --- a/src/main/resources/jsv-messages_de.properties +++ b/src/main/resources/jsv-messages_de.properties @@ -1,70 +1,70 @@ -$ref = {0}: hat einen Fehler mit ''refs'' -additionalItems = {0}: Index \u201E{1}\u201C ist im Schema nicht definiert und das Schema lässt keine zusätzlichen Elemente zu -additionalProperties = {0}: Eigenschaft ''{1}'' ist im Schema nicht definiert und das Schema lässt keine zusätzlichen Eigenschaften zu -allOf = {0}: muss für alle Schemas {1} gültig sein -anyOf = {0}: muss für eines der Schemas {1} gültig sein -const = {0}: muss der konstante Wert ''{1}'' sein -contains = {0}: enthält kein Element, das diese Validierungen besteht: {2} -contains.max = {0}: muss höchstens {1} Elemente enthalten, die diese Validierungen bestehen: {2} -contains.min = {0}: muss mindestens {1} Elemente enthalten, die diese Validierungen bestehen: {2} -dependencies = {0}: Es liegt ein Fehler mit den Abhängigkeiten {1} vor. -dependentRequired = {0}: Es fehlt eine Eigenschaft \u201E{1}\u201C, die abhängig ist, da \u201E{2}\u201C vorhanden ist -dependentSchemas = {0}: Es liegt ein Fehler mit dependenceSchemas {1} vor. -enum = {0}: hat keinen Wert in der Aufzählung {1} -exclusiveMaximum = {0}: muss einen exklusiven Maximalwert von {1} haben -exclusiveMinimum = {0}: muss einen exklusiven Mindestwert von {1} haben -false = {0}: Schema für ''{1}'' ist falsch -format = {0}: entspricht nicht dem Muster {1} {2} -format.date = {0}: stimmt nicht mit dem {1}-Muster überein, muss ein gültiges RFC 3339-Volldatum sein -format.date-time = {0}: entspricht nicht dem {1}-Muster. Es muss sich um ein gültiges RFC 3339-Datum/Uhrzeit-Format handeln -format.duration = {0}: stimmt nicht mit dem {1}-Muster überein, muss eine gültige ISO 8601-Dauer sein -format.email = {0}: entspricht nicht dem {1}-Muster. Es muss sich um ein gültiges RFC 5321-Postfach handeln -format.ipv4 = {0}: entspricht nicht dem {1}-Muster. Es muss sich um eine gültige RFC 2673-IP-Adresse handeln -format.ipv6 = {0}: entspricht nicht dem {1}-Muster. Es muss sich um eine gültige RFC 4291-IP-Adresse handeln -format.idn-email = {0}: entspricht nicht dem {1}-Muster. Es muss sich um ein gültiges RFC 6531-Postfach handeln -format.idn-hostname = {0}: entspricht nicht dem {1}-Muster. Es muss sich um einen gültigen internationalisierten RFC 5890-Hostnamen handeln -format.iri = {0}: entspricht nicht dem {1}-Muster, muss ein gültiger RFC 3987 IRI sein -format.iri-reference = {0}: entspricht nicht dem {1}-Muster muss eine gültige RFC 3987 IRI-Referenz sein -format.uri = {0}: entspricht nicht dem {1}-Muster muss ein gültiger RFC 3986-URI sein -format.uri-reference = {0}: stimmt nicht mit dem {1}-Muster überein, muss eine gültige RFC 3986-URI-Referenz sein -format.uri-template = {0}: entspricht nicht dem {1}-Muster. Es muss sich um eine gültige RFC 6570-URI-Vorlage handeln -format.uuid = {0}: stimmt nicht mit dem {1}-Muster überein, muss eine gültige RFC 4122-UUID sein -format.regex = {0}: entspricht nicht dem Muster {1} muss ein gültiger regulärer ECMA-262-Ausdruck sein -format.time = {0}: entspricht nicht dem {1}-Muster muss eine gültige RFC 3339-Zeit sein -format.hostname = {0}: entspricht nicht dem {1}-Muster. Es muss sich um einen gültigen RFC 1123-Hostnamen handeln -format.json-pointer = {0}: stimmt nicht mit dem {1}-Muster überein, muss ein gültiger RFC 6901-JSON-Zeiger sein -format.relative-json-pointer = {0}: stimmt nicht mit dem {1}-Muster überein, muss ein gültiger relativer IETF-JSON-Zeiger sein -format.unknown = {0}: hat ein unbekanntes Format ''{1}'' -id = {0}: ''{1}'' ist kein gültiger {2} -items = {0}: Index ''{1}'' ist im Schema nicht definiert und das Schema lässt keine zusätzlichen Elemente zu -maxContains = {0}: muss eine nicht negative Ganzzahl in {1} sein -maxItems = {0}: muss höchstens {1} Elemente haben, aber {2} gefunden -maxLength = {0}: darf höchstens {1} Zeichen lang sein -maxProperties = {0}: darf höchstens {1} Eigenschaften haben -maximum = {0}: muss einen Maximalwert von {1} haben -minContains = {0}: muss eine nicht negative Ganzzahl in {1} sein -minContainsVsMaxContains = {0}: minContains muss kleiner oder gleich maxContains in {1} sein -minItems = {0}: muss mindestens {1} Elemente haben, aber {2} gefunden -minLength = {0}: muss mindestens {1} Zeichen lang sein -minProperties = {0}: muss mindestens {1} Eigenschaften haben -minimum = {0}: muss einen Mindestwert von {1} haben -multipleOf = {0}: muss ein Vielfaches von {1} sein -not = {0}: darf für das Schema {1} nicht gültig sein -notAllowed = {0}: Eigenschaft ''{1}'' ist nicht zulässig, befindet sich aber in den Daten -oneOf = {0}: muss für ein und nur ein Schema gültig sein, aber {1} sind gültig -oneOf.indexes = {0}: muss für ein und nur ein Schema gültig sein, aber {1} sind mit den Indizes \u201E{2}\u201C gültig. -pattern = {0}: stimmt nicht mit dem Regex-Muster {1} überein -patternProperties = {0}: Es liegt ein Fehler mit den \u201EMustereigenschaften\u201C vor. -prefixItems = {0}: Bei diesem Index wurde kein Validator gefunden -properties = {0}: Es liegt ein Fehler mit \u201EProperties\u201C vor. -propertyNames = {0}: Der Name der Eigenschaft \u201E{1}\u201C ist ungültig: {2} -readOnly = {0}: ist ein schreibgeschütztes Feld, es kann nicht geändert werden -required = {0}: erforderliche Eigenschaft ''{1}'' nicht gefunden -type = {0}: {1} gefunden, {2} erwartet -unevaluatedItems = {0}: Index ''{1}'' wird nicht ausgewertet und das Schema lässt keine nicht ausgewerteten Elemente zu -unevaluatedProperties = {0}: Eigenschaft ''{1}'' wird nicht ausgewertet und das Schema lässt keine nicht ausgewerteten Eigenschaften zu -unionType = {0}: {1} gefunden, {2} erwartet -uniqueItems = {0}: Das Array darf nur eindeutige Elemente enthalten -writeOnly = {0}: ist ein schreibgeschütztes Feld, es kann nicht in den Daten erscheinen -contentEncoding = {0}: stimmt nicht mit der Inhaltskodierung {1} überein -contentMediaType = {0}: ist kein Inhalt für mich +$ref = hat einen Fehler mit ''refs'' +additionalItems = Index \u201E{0}\u201C ist im Schema nicht definiert und das Schema lässt keine zusätzlichen Elemente zu +additionalProperties = Eigenschaft ''{0}'' ist im Schema nicht definiert und das Schema lässt keine zusätzlichen Eigenschaften zu +allOf = muss für alle Schemas {0} gültig sein +anyOf = muss für eines der Schemas {0} gültig sein +const = muss der konstante Wert ''{0}'' sein +contains = enthält kein Element, das diese Validierungen besteht: {1} +contains.max = muss höchstens {0} Elemente enthalten, die diese Validierungen bestehen: {1} +contains.min = muss mindestens {0} Elemente enthalten, die diese Validierungen bestehen: {1} +dependencies = Es liegt ein Fehler mit den Abhängigkeiten {0} vor. +dependentRequired = Es fehlt eine Eigenschaft \u201E{0}\u201C, die abhängig ist, da \u201E{1}\u201C vorhanden ist +dependentSchemas = Es liegt ein Fehler mit dependenceSchemas {0} vor. +enum = hat keinen Wert in der Aufzählung {0} +exclusiveMaximum = muss einen exklusiven Maximalwert von {0} haben +exclusiveMinimum = muss einen exklusiven Mindestwert von {0} haben +false = Schema für ''{0}'' ist falsch +format = entspricht nicht dem Muster {0} +format.date = stimmt nicht mit dem {0}-Muster überein, muss ein gültiges RFC 3339-Volldatum sein +format.date-time = entspricht nicht dem {0}-Muster. Es muss sich um ein gültiges RFC 3339-Datum/Uhrzeit-Format handeln +format.duration = stimmt nicht mit dem {0}-Muster überein, muss eine gültige ISO 8601-Dauer sein +format.email = entspricht nicht dem {0}-Muster. Es muss sich um ein gültiges RFC 5321-Postfach handeln +format.ipv4 = entspricht nicht dem {0}-Muster. Es muss sich um eine gültige RFC 2673-IP-Adresse handeln +format.ipv6 = entspricht nicht dem {0}-Muster. Es muss sich um eine gültige RFC 4291-IP-Adresse handeln +format.idn-email = entspricht nicht dem {0}-Muster. Es muss sich um ein gültiges RFC 6531-Postfach handeln +format.idn-hostname = entspricht nicht dem {0}-Muster. Es muss sich um einen gültigen internationalisierten RFC 5890-Hostnamen handeln +format.iri = entspricht nicht dem {0}-Muster, muss ein gültiger RFC 3987 IRI sein +format.iri-reference = entspricht nicht dem {0}-Muster muss eine gültige RFC 3987 IRI-Referenz sein +format.uri = entspricht nicht dem {0}-Muster muss ein gültiger RFC 3986-URI sein +format.uri-reference = stimmt nicht mit dem {0}-Muster überein, muss eine gültige RFC 3986-URI-Referenz sein +format.uri-template = entspricht nicht dem {0}-Muster. Es muss sich um eine gültige RFC 6570-URI-Vorlage handeln +format.uuid = stimmt nicht mit dem {0}-Muster überein, muss eine gültige RFC 4122-UUID sein +format.regex = entspricht nicht dem Muster {0} muss ein gültiger regulärer ECMA-262-Ausdruck sein +format.time = entspricht nicht dem {0}-Muster muss eine gültige RFC 3339-Zeit sein +format.hostname = entspricht nicht dem {0}-Muster. Es muss sich um einen gültigen RFC 1123-Hostnamen handeln +format.json-pointer = stimmt nicht mit dem {0}-Muster überein, muss ein gültiger RFC 6901-JSON-Zeiger sein +format.relative-json-pointer = stimmt nicht mit dem {0}-Muster überein, muss ein gültiger relativer IETF-JSON-Zeiger sein +format.unknown = hat ein unbekanntes Format ''{0}'' +id = ''{0}'' ist kein gültiger {1} +items = Index ''{0}'' ist im Schema nicht definiert und das Schema lässt keine zusätzlichen Elemente zu +maxContains = muss eine nicht negative Ganzzahl in {0} sein +maxItems = muss höchstens {0} Elemente haben, aber {1} gefunden +maxLength = darf höchstens {0} Zeichen lang sein +maxProperties = darf höchstens {0} Eigenschaften haben +maximum = muss einen Maximalwert von {0} haben +minContains = muss eine nicht negative Ganzzahl in {0} sein +minContainsVsMaxContains = minContains muss kleiner oder gleich maxContains in {0} sein +minItems = muss mindestens {0} Elemente haben, aber {1} gefunden +minLength = muss mindestens {0} Zeichen lang sein +minProperties = muss mindestens {0} Eigenschaften haben +minimum = muss einen Mindestwert von {0} haben +multipleOf = muss ein Vielfaches von {0} sein +not = darf für das Schema {0} nicht gültig sein +notAllowed = Eigenschaft ''{0}'' ist nicht zulässig, befindet sich aber in den Daten +oneOf = muss für ein und nur ein Schema gültig sein, aber {0} sind gültig +oneOf.indexes = muss für ein und nur ein Schema gültig sein, aber {0} sind mit den Indizes \u201E{1}\u201C gültig. +pattern = stimmt nicht mit dem Regex-Muster {0} überein +patternProperties = Es liegt ein Fehler mit den \u201EMustereigenschaften\u201C vor. +prefixItems = Bei diesem Index wurde kein Validator gefunden +properties = Es liegt ein Fehler mit \u201EProperties\u201C vor. +propertyNames = Der Name der Eigenschaft \u201E{0}\u201C ist ungültig: {1} +readOnly = ist ein schreibgeschütztes Feld, es kann nicht geändert werden +required = erforderliche Eigenschaft ''{0}'' nicht gefunden +type = {0} gefunden, {1} erwartet +unevaluatedItems = Index ''{0}'' wird nicht ausgewertet und das Schema lässt keine nicht ausgewerteten Elemente zu +unevaluatedProperties = Eigenschaft ''{0}'' wird nicht ausgewertet und das Schema lässt keine nicht ausgewerteten Eigenschaften zu +unionType = {0} gefunden, {1} erwartet +uniqueItems = Das Array darf nur eindeutige Elemente enthalten +writeOnly = ist ein schreibgeschütztes Feld, es kann nicht in den Daten erscheinen +contentEncoding = stimmt nicht mit der Inhaltskodierung {0} überein +contentMediaType = ist kein Inhalt für mich diff --git a/src/main/resources/jsv-messages_es.properties b/src/main/resources/jsv-messages_es.properties index 44dbff7b5..18a08cf9f 100644 --- a/src/main/resources/jsv-messages_es.properties +++ b/src/main/resources/jsv-messages_es.properties @@ -1,70 +1,70 @@ -$ref = {0}: tiene un error con las 'referencias' -additionalItems = {0}: el \u00edndice ''{1}'' no est\u00e1 definido en el esquema y el esquema no permite elementos adicionales -additionalProperties = {0}: la propiedad ''{1}'' no est\u00e1 definida en el esquema y el esquema no permite propiedades adicionales -allOf = {0}: debe ser v\u00e1lido para todos los esquemas {1} -anyOf = {0}: debe ser v\u00e1lido para cualquiera de los esquemas {1} -const = {0}: debe ser el valor constante ''{1}'' -contains = {0}: no contiene un elemento que cumpla estas validaciones: {2} -contains.max = {0}: debe contener como m\u00e1ximo {1} elemento(s) que cumpla(n) estas validaciones: {2} -contains.min = {0}: debe contener al menos {1} elemento(s) que cumpla(n) estas validaciones: {2} -dependencies = {0}: tiene un error con las dependencias {1} -dependentRequired = {0}: tiene una propiedad faltante ''{1}'' que es dependiente y requerida porque ''{2}'' est\u00e1 presente -dependentSchemas = {0}: tiene un error con dependentSchemas {1} -enum = {0}: no tiene un valor en la enumeraci\u00f3n {1} -exclusiveMaximum = {0}: debe tener un valor m\u00e1ximo exclusivo de {1} -exclusiveMinimum = {0}: debe tener un valor m\u00ednimo exclusivo de {1} -false = {0}: el esquema para ''{1}'' es falso -format = {0}: no coincide con el patr\u00f3n {1} {2} -format.date = {0}: no coincide con el patr\u00f3n {1}; debe ser un RFC 3339 con fecha completa v\u00e1lido -format.date-time = {0}: no coincide con el patr\u00f3n {1}; debe ser un RFC 3339 con fecha y hora v\u00e1lido -format.duration = {0}: no coincide con el patr\u00f3n {1}; debe ser un ISO 8601 de duraci\u00f3n v\u00e1lido -format.email = {0}: no coincide con el patr\u00f3n {1}; debe ser un RFC 5321 de buz\u00f3n de correo v\u00e1lido -format.ipv4 = {0}: no coincide con el patr\u00f3n {1}; debe ser un RFC 2673 de direcci\u00f3n IP v\u00e1lido -format.ipv6 = {0}: no coincide con el patr\u00f3n {1}; debe ser un RFC 4291 de direcci\u00f3n IP v\u00e1lido -format.idn-email = {0}: no coincide con el patr\u00f3n {1}; debe ser un RFC 6531 de buz\u00f3n de correo v\u00e1lido -format.idn-hostname = {0}: no coincide con el patr\u00f3n {1}; debe ser un RFC 5890 de nombre de host internacionalizado v\u00e1lido -format.iri = {0}: no coincide con el patr\u00f3n {1}; debe ser un RFC 3987 de IRI v\u00e1lido -format.iri-reference = {0}: no coincide con el patr\u00f3n {1}; debe ser un RFC 3987 de referencia IRI v\u00e1lido -format.uri = {0}: no coincide con el patr\u00f3n {1}; debe ser un RFC 3986 de URI v\u00e1lido -format.uri-reference = {0}: no coincide con el patr\u00f3n {1}; debe ser un RFC 3986 de referencia URI v\u00e1lido -format.uri-template = {0}: no coincide con el patr\u00f3n {1}; debe ser un RFC 6570 de plantilla de URI v\u00e1lido -format.uuid = {0}: no coincide con el patr\u00f3n {1}; debe ser un RFC 4122 de UUID v\u00e1lido -format.regex = {0}: no coincide con el patr\u00f3n {1}; debe ser una expresi\u00f3n regular ECMA-262 v\u00e1lida -format.time = {0}: no coincide con el patr\u00f3n {1}; debe ser un RFC 3339 con hora v\u00e1lido -format.hostname = {0}: no coincide con el patr\u00f3n {1}; debe ser un RFC 1123 de nombre de host v\u00e1lido -format.json-pointer = {0}: no coincide con el patr\u00f3n {1}; debe ser un RFC 6901 de puntero JSON v\u00e1lido -format.relative-json-pointer = {0}: no coincide con el patr\u00f3n {1}; debe ser un IETF relativo de puntero JSON v\u00e1lido -format.unknown = {0}: tiene un formato desconocido ''{1}'' -id = {0}: ''{1}'' no es un v\u00e1lido {2} -items = {0}: el \u00edndice ''{1}'' no est\u00e1 definido en el esquema y el esquema no permite elementos adicionales -maxContains = {0}: debe ser un entero no negativo en {1} -maxItems = {0}: debe tener como m\u00e1ximo {1} elementos, pero se encontraron {2} -maxLength = {0}: debe tener como m\u00e1ximo {1} caracteres -maxProperties = {0}: debe tener como m\u00e1ximo {1} propiedades -maximum = {0}: debe tener un valor m\u00e1ximo de {1} -minContains = {0}: debe ser un entero no negativo en {1} -minContainsVsMaxContains = {0}: minContains debe ser menor o igual a maxContains en {1} -minItems = {0}: debe tener al menos {1} elementos, pero se encontraron {2} -minLength = {0}: debe tener al menos {1} caracteres -minProperties = {0}: debe tener al menos {1} propiedades -minimum = {0}: debe tener un valor m\u00ednimo de {1} -multipleOf = {0}: debe ser m\u00faltiplo de {1} -not = {0}: no debe ser v\u00e1lido para el esquema {1} -notAllowed = {0}: la propiedad ''{1}'' no est\u00e1 permitida, pero est\u00e1 en los datos -oneOf = {0}: debe ser v\u00e1lido para uno y solo un esquema, pero {1} son v\u00e1lidos -oneOf.indexes = {0}: debe ser v\u00e1lido para uno y solo un esquema, pero {1} son v\u00e1lidos con los \u00edndices ''{2}'' -pattern = {0}: no coincide con el patr\u00f3n regex {1} -patternProperties = {0}: tiene algunos errores con las 'propiedades del patr\u00f3n' -prefixItems = {0}: no se encuentra ning\u00fan elemento de validaci\u00f3n en este \u00edndice -properties = {0}: tiene un error con las 'propiedades' -propertyNames = {0}: el nombre ''{1}'' de la propiedad no es v\u00e1lido: {2} -readOnly = {0}: no puede cambiarse, ya que es un campo de solo lectura -required = {0}: no se encontr\u00f3 la propiedad requerida ''{1}'' -type = {0}: se encontraron {1}, se preve\u00edan {2} -unevaluatedItems = {0}: el \u00edndice ''{1}'' no est\u00e1 evaluado y el esquema no permite elementos que no hayan sido evaluados -unevaluatedProperties = {0}: la propiedad ''{1}'' no est\u00e1 evaluada y el esquema no permite propiedades que no hayan sido evaluadas -unionType = {0}: se encontraron {1}, se preve\u00edan {2} -uniqueItems = {0}: debe tener solo elementos \u00fanicos en la matriz -writeOnly = {0}: es un campo de solo lectura, no puede aparecer en los datos -contentEncoding = {0}: no coincide con la codificaci\u00f3n de contenido {1} -contentMediaType = {0}: no es un tipo de medios de contenido +$ref = tiene un error con las 'referencias' +additionalItems = el \u00edndice ''{0}'' no est\u00e1 definido en el esquema y el esquema no permite elementos adicionales +additionalProperties = la propiedad ''{0}'' no est\u00e1 definida en el esquema y el esquema no permite propiedades adicionales +allOf = debe ser v\u00e1lido para todos los esquemas {0} +anyOf = debe ser v\u00e1lido para cualquiera de los esquemas {0} +const = debe ser el valor constante ''{0}'' +contains = no contiene un elemento que cumpla estas validaciones: {1} +contains.max = debe contener como m\u00e1ximo {0} elemento(s) que cumpla(n) estas validaciones: {1} +contains.min = debe contener al menos {0} elemento(s) que cumpla(n) estas validaciones: {1} +dependencies = tiene un error con las dependencias {0} +dependentRequired = tiene una propiedad faltante ''{0}'' que es dependiente y requerida porque ''{1}'' est\u00e1 presente +dependentSchemas = tiene un error con dependentSchemas {0} +enum = no tiene un valor en la enumeraci\u00f3n {0} +exclusiveMaximum = debe tener un valor m\u00e1ximo exclusivo de {0} +exclusiveMinimum = debe tener un valor m\u00ednimo exclusivo de {0} +false = el esquema para ''{0}'' es falso +format = no coincide con el patr\u00f3n {0} +format.date = no coincide con el patr\u00f3n {0}; debe ser un RFC 3339 con fecha completa v\u00e1lido +format.date-time = no coincide con el patr\u00f3n {0}; debe ser un RFC 3339 con fecha y hora v\u00e1lido +format.duration = no coincide con el patr\u00f3n {0}; debe ser un ISO 8601 de duraci\u00f3n v\u00e1lido +format.email = no coincide con el patr\u00f3n {0}; debe ser un RFC 5321 de buz\u00f3n de correo v\u00e1lido +format.ipv4 = no coincide con el patr\u00f3n {0}; debe ser un RFC 2673 de direcci\u00f3n IP v\u00e1lido +format.ipv6 = no coincide con el patr\u00f3n {0}; debe ser un RFC 4291 de direcci\u00f3n IP v\u00e1lido +format.idn-email = no coincide con el patr\u00f3n {0}; debe ser un RFC 6531 de buz\u00f3n de correo v\u00e1lido +format.idn-hostname = no coincide con el patr\u00f3n {0}; debe ser un RFC 5890 de nombre de host internacionalizado v\u00e1lido +format.iri = no coincide con el patr\u00f3n {0}; debe ser un RFC 3987 de IRI v\u00e1lido +format.iri-reference = no coincide con el patr\u00f3n {0}; debe ser un RFC 3987 de referencia IRI v\u00e1lido +format.uri = no coincide con el patr\u00f3n {0}; debe ser un RFC 3986 de URI v\u00e1lido +format.uri-reference = no coincide con el patr\u00f3n {0}; debe ser un RFC 3986 de referencia URI v\u00e1lido +format.uri-template = no coincide con el patr\u00f3n {0}; debe ser un RFC 6570 de plantilla de URI v\u00e1lido +format.uuid = no coincide con el patr\u00f3n {0}; debe ser un RFC 4122 de UUID v\u00e1lido +format.regex = no coincide con el patr\u00f3n {0}; debe ser una expresi\u00f3n regular ECMA-262 v\u00e1lida +format.time = no coincide con el patr\u00f3n {0}; debe ser un RFC 3339 con hora v\u00e1lido +format.hostname = no coincide con el patr\u00f3n {0}; debe ser un RFC 1123 de nombre de host v\u00e1lido +format.json-pointer = no coincide con el patr\u00f3n {0}; debe ser un RFC 6901 de puntero JSON v\u00e1lido +format.relative-json-pointer = no coincide con el patr\u00f3n {0}; debe ser un IETF relativo de puntero JSON v\u00e1lido +format.unknown = tiene un formato desconocido ''{0}'' +id = ''{0}'' no es un v\u00e1lido {1} +items = el \u00edndice ''{0}'' no est\u00e1 definido en el esquema y el esquema no permite elementos adicionales +maxContains = debe ser un entero no negativo en {0} +maxItems = debe tener como m\u00e1ximo {0} elementos, pero se encontraron {1} +maxLength = debe tener como m\u00e1ximo {0} caracteres +maxProperties = debe tener como m\u00e1ximo {0} propiedades +maximum = debe tener un valor m\u00e1ximo de {0} +minContains = debe ser un entero no negativo en {0} +minContainsVsMaxContains = minContains debe ser menor o igual a maxContains en {0} +minItems = debe tener al menos {0} elementos, pero se encontraron {1} +minLength = debe tener al menos {0} caracteres +minProperties = debe tener al menos {0} propiedades +minimum = debe tener un valor m\u00ednimo de {0} +multipleOf = debe ser m\u00faltiplo de {0} +not = no debe ser v\u00e1lido para el esquema {0} +notAllowed = la propiedad ''{0}'' no est\u00e1 permitida, pero est\u00e1 en los datos +oneOf = debe ser v\u00e1lido para uno y solo un esquema, pero {0} son v\u00e1lidos +oneOf.indexes = debe ser v\u00e1lido para uno y solo un esquema, pero {0} son v\u00e1lidos con los \u00edndices ''{1}'' +pattern = no coincide con el patr\u00f3n regex {0} +patternProperties = tiene algunos errores con las 'propiedades del patr\u00f3n' +prefixItems = no se encuentra ning\u00fan elemento de validaci\u00f3n en este \u00edndice +properties = tiene un error con las 'propiedades' +propertyNames = el nombre ''{0}'' de la propiedad no es v\u00e1lido: {1} +readOnly = no puede cambiarse, ya que es un campo de solo lectura +required = no se encontr\u00f3 la propiedad requerida ''{0}'' +type = se encontraron {0}, se preve\u00edan {1} +unevaluatedItems = el \u00edndice ''{0}'' no est\u00e1 evaluado y el esquema no permite elementos que no hayan sido evaluados +unevaluatedProperties = la propiedad ''{0}'' no est\u00e1 evaluada y el esquema no permite propiedades que no hayan sido evaluadas +unionType = se encontraron {0}, se preve\u00edan {1} +uniqueItems = debe tener solo elementos \u00fanicos en la matriz +writeOnly = es un campo de solo lectura, no puede aparecer en los datos +contentEncoding = no coincide con la codificaci\u00f3n de contenido {0} +contentMediaType = no es un tipo de medios de contenido diff --git a/src/main/resources/jsv-messages_fa.properties b/src/main/resources/jsv-messages_fa.properties index d8a1ff726..aa62ea930 100644 --- a/src/main/resources/jsv-messages_fa.properties +++ b/src/main/resources/jsv-messages_fa.properties @@ -1,70 +1,70 @@ -$ref = {0}: \u062F\u0627\u0631\u0627\u06CC \u062E\u0637\u0627 \u0628\u0627 "refs" \u0627\u0633\u062A -additionalItems = {0}: \u0646\u0645\u0627\u06CC\u0647 ''{1}'' \u062F\u0631 \u0627\u06CC\u0646 \u0637\u0631\u062D \u062A\u0639\u0631\u06CC\u0641 \u0646\u0634\u062F\u0647 \u0627\u0633\u062A \u0648 \u0637\u0631\u062D \u0645\u0648\u0627\u0631\u062F \u0627\u0636\u0627\u0641\u06CC \u0631\u0627 \u0645\u062C\u0627\u0632 \u0646\u0645\u06CC\u200C\u062F\u0627\u0646\u062F -additionalProperties = {0}: \u062E\u0627\u0635\u06CC\u062A ''{1}'' \u062F\u0631 \u0637\u0631\u062D \u062A\u0639\u0631\u06CC\u0641 \u0646\u0634\u062F\u0647 \u0627\u0633\u062A \u0648 \u0627\u06CC\u0646 \u0637\u0631\u062D \u0648\u06CC\u0698\u06AF\u06CC \u0647\u0627\u06CC \u0627\u0636\u0627\u0641\u06CC \u0631\u0627 \u0627\u062C\u0627\u0632\u0647 \u0646\u0645\u06CC \u062F\u0647\u062F -allOf = {0}: \u0628\u0627\u06CC\u062F \u0628\u0631\u0627\u06CC \u0647\u0645\u0647 \u0637\u0631\u062D\u0648\u0627\u0631\u0647 \u0647\u0627 \u0645\u0639\u062A\u0628\u0631 \u0628\u0627\u0634\u062F {1} -anyOf = {0}: \u0628\u0627\u06CC\u062F \u0628\u0631\u0627\u06CC \u0647\u0631 \u06CC\u06A9 \u0627\u0632 \u0637\u0631\u062D\u0648\u0627\u0631\u0647 \u0647\u0627 \u0645\u0639\u062A\u0628\u0631 \u0628\u0627\u0634\u062F {1} -const = {0}: \u0628\u0627\u06CC\u062F \u0645\u0642\u062F\u0627\u0631 \u062B\u0627\u0628\u062A "{1}" \u0628\u0627\u0634\u062F -contains = {0}: \u062D\u0627\u0648\u06CC \u0639\u0646\u0635\u0631\u06CC \u0646\u06CC\u0633\u062A \u06A9\u0647 \u0627\u06CC\u0646 \u0627\u0639\u062A\u0628\u0627\u0631\u0633\u0646\u062C\u06CC \u0647\u0627 \u0631\u0627 \u067E\u0627\u0633 \u06A9\u0646\u062F: {2} -contains.max = {0}: \u0628\u0627\u06CC\u062F \u062D\u062F\u0627\u06A9\u062B\u0631 \u062D\u0627\u0648\u06CC {1} \u0639\u0646\u0635\u0631 (\u0647\u0627) \u0628\u0627\u0634\u062F \u06A9\u0647 \u0627\u06CC\u0646 \u0627\u0639\u062A\u0628\u0627\u0631\u0633\u0646\u062C\u06CC \u0647\u0627 \u0631\u0627 \u067E\u0627\u0633 \u0645\u06CC \u06A9\u0646\u062F: {2} -contains.min = {0}: \u0628\u0627\u06CC\u062F \u062D\u062F\u0627\u0642\u0644 \u0634\u0627\u0645\u0644 {1} \u0639\u0646\u0635\u0631 (\u0647\u0627) \u0628\u0627\u0634\u062F \u06A9\u0647 \u0627\u06CC\u0646 \u0627\u0639\u062A\u0628\u0627\u0631\u0633\u0646\u062C\u06CC \u0647\u0627 \u0631\u0627 \u0628\u06AF\u0630\u0631\u0627\u0646\u062F: {2} -dependencies = {0}: \u062F\u0627\u0631\u0627\u06CC \u06CC\u06A9 \u062E\u0637\u0627 \u062F\u0631 \u0648\u0627\u0628\u0633\u062A\u06AF\u06CC {1} -dependentRequired = {0}: \u062F\u0627\u0631\u0627\u06CC \u06CC\u06A9 \u0648\u06CC\u0698\u06AF\u06CC \u06AF\u0645 \u0634\u062F\u0647 "{1}" \u0627\u0633\u062A \u06A9\u0647 \u0628\u0647 \u062F\u0644\u06CC\u0644 \u0648\u062C\u0648\u062F "{2}" \u0648\u0627\u0628\u0633\u062A\u0647 \u0627\u0633\u062A -dependentSchemas = {0}: \u062F\u0627\u0631\u0627\u06CC \u062E\u0637\u0627 \u0628\u0627 dependentSchemas {1} -enum = {0}: \u0645\u0642\u062F\u0627\u0631\u06CC \u062F\u0631 \u0634\u0645\u0627\u0631\u0634 {1} \u0646\u062F\u0627\u0631\u062F -exclusiveMaximum = {0}: \u0628\u0627\u06CC\u062F \u062D\u062F\u0627\u06A9\u062B\u0631 \u0645\u0642\u062F\u0627\u0631 \u0627\u0646\u062D\u0635\u0627\u0631\u06CC {1} \u062F\u0627\u0634\u062A\u0647 \u0628\u0627\u0634\u062F -exclusiveMinimum = {0}: \u0628\u0627\u06CC\u062F \u062D\u062F\u0627\u0642\u0644 \u0645\u0642\u062F\u0627\u0631 \u0627\u0646\u062D\u0635\u0627\u0631\u06CC {1} \u062F\u0627\u0634\u062A\u0647 \u0628\u0627\u0634\u062F -false = {0}: \u0637\u0631\u062D\u0648\u0627\u0631\u0647 ''{1}'' \u0646\u0627\u062F\u0631\u0633\u062A \u0627\u0633\u062A -format = {0}: \u0628\u0627 \u0627\u0644\u06AF\u0648\u06CC {1} {2} \u0645\u0637\u0627\u0628\u0642\u062A \u0646\u062F\u0627\u0631\u062F -format.date = {0}: \u0628\u0627 \u0627\u0644\u06AF\u0648\u06CC {1} \u0645\u0637\u0627\u0628\u0642\u062A \u0646\u062F\u0627\u0631\u062F \u0628\u0627\u06CC\u062F \u062A\u0627\u0631\u06CC\u062E \u06A9\u0627\u0645\u0644 RFC 3339 \u0645\u0639\u062A\u0628\u0631 \u0628\u0627\u0634\u062F -format.date-time = {0}: \u0628\u0627 \u0627\u0644\u06AF\u0648\u06CC {1} \u0645\u0637\u0627\u0628\u0642\u062A \u0646\u062F\u0627\u0631\u062F \u0628\u0627\u06CC\u062F \u062A\u0627\u0631\u06CC\u062E \u0648 \u0632\u0645\u0627\u0646 RFC 3339 \u0645\u0639\u062A\u0628\u0631 \u0628\u0627\u0634\u062F -format.duration = {0}: \u0628\u0627 \u0627\u0644\u06AF\u0648\u06CC {1} \u0645\u0637\u0627\u0628\u0642\u062A \u0646\u062F\u0627\u0631\u062F \u0628\u0627\u06CC\u062F \u0645\u062F\u062A \u0632\u0645\u0627\u0646 ISO 8601 \u0645\u0639\u062A\u0628\u0631 \u0628\u0627\u0634\u062F -format.email = {0}: \u0628\u0627 \u0627\u0644\u06AF\u0648\u06CC {1} \u0645\u0637\u0627\u0628\u0642\u062A \u0646\u062F\u0627\u0631\u062F \u0628\u0627\u06CC\u062F \u06CC\u06A9 \u0635\u0646\u062F\u0648\u0642 \u067E\u0633\u062A\u06CC RFC 5321 \u0645\u0639\u062A\u0628\u0631 \u0628\u0627\u0634\u062F -format.ipv4 = {0}: \u0628\u0627 \u0627\u0644\u06AF\u0648\u06CC {1} \u0645\u0637\u0627\u0628\u0642\u062A \u0646\u062F\u0627\u0631\u062F \u0628\u0627\u06CC\u062F \u06CC\u06A9 \u0622\u062F\u0631\u0633 IP \u0645\u0639\u062A\u0628\u0631 RFC 2673 \u0628\u0627\u0634\u062F -format.ipv6 = {0}: \u0628\u0627 \u0627\u0644\u06AF\u0648\u06CC {1} \u0645\u0637\u0627\u0628\u0642\u062A \u0646\u062F\u0627\u0631\u062F \u0628\u0627\u06CC\u062F \u06CC\u06A9 \u0622\u062F\u0631\u0633 IP \u0645\u0639\u062A\u0628\u0631 RFC 4291 \u0628\u0627\u0634\u062F -format.idn-email = {0}: \u0628\u0627 \u0627\u0644\u06AF\u0648\u06CC {1} \u0645\u0637\u0627\u0628\u0642\u062A \u0646\u062F\u0627\u0631\u062F \u0628\u0627\u06CC\u062F \u06CC\u06A9 \u0635\u0646\u062F\u0648\u0642 \u067E\u0633\u062A\u06CC RFC 6531 \u0645\u0639\u062A\u0628\u0631 \u0628\u0627\u0634\u062F -format.idn-hostname = {0}: \u0628\u0627 \u0627\u0644\u06AF\u0648\u06CC {1} \u0645\u0637\u0627\u0628\u0642\u062A \u0646\u062F\u0627\u0631\u062F \u0628\u0627\u06CC\u062F \u06CC\u06A9 \u0646\u0627\u0645 \u0645\u06CC\u0632\u0628\u0627\u0646 \u0628\u06CC\u0646 \u0627\u0644\u0645\u0644\u0644\u06CC \u0634\u062F\u0647 \u0645\u0639\u062A\u0628\u0631 RFC 5890 \u0628\u0627\u0634\u062F. -format.iri = {0}: \u0628\u0627 \u0627\u0644\u06AF\u0648\u06CC {1} \u0645\u0637\u0627\u0628\u0642\u062A \u0646\u062F\u0627\u0631\u062F \u0628\u0627\u06CC\u062F \u06CC\u06A9 RFC 3987 IRI \u0645\u0639\u062A\u0628\u0631 \u0628\u0627\u0634\u062F -format.iri-reference = {0}: \u0628\u0627 \u0627\u0644\u06AF\u0648\u06CC {1} \u0645\u0637\u0627\u0628\u0642\u062A \u0646\u062F\u0627\u0631\u062F \u0628\u0627\u06CC\u062F \u0645\u0631\u062C\u0639 \u0645\u0639\u062A\u0628\u0631 RFC 3987 IRI \u0628\u0627\u0634\u062F -format.uri = {0}: \u0628\u0627 \u0627\u0644\u06AF\u0648\u06CC {1} \u0645\u0637\u0627\u0628\u0642\u062A \u0646\u062F\u0627\u0631\u062F \u0628\u0627\u06CC\u062F \u06CC\u06A9 URI RFC 3986 \u0645\u0639\u062A\u0628\u0631 \u0628\u0627\u0634\u062F -format.uri-reference = {0}: \u0628\u0627 \u0627\u0644\u06AF\u0648\u06CC {1} \u0645\u0637\u0627\u0628\u0642\u062A \u0646\u062F\u0627\u0631\u062F \u0628\u0627\u06CC\u062F \u06CC\u06A9 \u0645\u0631\u062C\u0639 URI RFC 3986 \u0645\u0639\u062A\u0628\u0631 \u0628\u0627\u0634\u062F -format.uri-template = {0}: \u0628\u0627 \u0627\u0644\u06AF\u0648\u06CC {1} \u0645\u0637\u0627\u0628\u0642\u062A \u0646\u062F\u0627\u0631\u062F \u0628\u0627\u06CC\u062F \u06CC\u06A9 \u0627\u0644\u06AF\u0648\u06CC URI RFC 6570 \u0645\u0639\u062A\u0628\u0631 \u0628\u0627\u0634\u062F -format.uuid = {0}: \u0628\u0627 \u0627\u0644\u06AF\u0648\u06CC {1} \u0645\u0637\u0627\u0628\u0642\u062A \u0646\u062F\u0627\u0631\u062F \u0628\u0627\u06CC\u062F \u06CC\u06A9 UUID RFC 4122 \u0645\u0639\u062A\u0628\u0631 \u0628\u0627\u0634\u062F -format.regex = {0}: \u0628\u0627 \u0627\u0644\u06AF\u0648\u06CC {1} \u0645\u0637\u0627\u0628\u0642\u062A \u0646\u062F\u0627\u0631\u062F \u0628\u0627\u06CC\u062F \u06CC\u06A9 \u0639\u0628\u0627\u0631\u062A \u0645\u0646\u0638\u0645 ECMA-262 \u0645\u0639\u062A\u0628\u0631 \u0628\u0627\u0634\u062F -format.time = {0}: \u0628\u0627 \u0627\u0644\u06AF\u0648\u06CC {1} \u0645\u0637\u0627\u0628\u0642\u062A \u0646\u062F\u0627\u0631\u062F \u0628\u0627\u06CC\u062F \u0632\u0645\u0627\u0646 \u0645\u0639\u062A\u0628\u0631 RFC 3339 \u0628\u0627\u0634\u062F -format.hostname = {0}: \u0628\u0627 \u0627\u0644\u06AF\u0648\u06CC {1} \u0645\u0637\u0627\u0628\u0642\u062A \u0646\u062F\u0627\u0631\u062F \u0628\u0627\u06CC\u062F \u06CC\u06A9 \u0646\u0627\u0645 \u0645\u06CC\u0632\u0628\u0627\u0646 \u0645\u0639\u062A\u0628\u0631 RFC 1123 \u0628\u0627\u0634\u062F -format.json-pointer = {0}: \u0628\u0627 \u0627\u0644\u06AF\u0648\u06CC {1} \u0645\u0637\u0627\u0628\u0642\u062A \u0646\u062F\u0627\u0631\u062F \u0628\u0627\u06CC\u062F RFC 6901 JSON Pointer \u0645\u0639\u062A\u0628\u0631 \u0628\u0627\u0634\u062F -format.relative-json-pointer = {0}: \u0628\u0627 \u0627\u0644\u06AF\u0648\u06CC {1} \u0645\u0637\u0627\u0628\u0642\u062A \u0646\u062F\u0627\u0631\u062F \u0628\u0627\u06CC\u062F \u06CC\u06A9 \u0646\u0634\u0627\u0646\u06AF\u0631 JSON \u0646\u0633\u0628\u06CC IETF \u0645\u0639\u062A\u0628\u0631 \u0628\u0627\u0634\u062F -format.unknown = {0}: \u062F\u0627\u0631\u0627\u06CC \u0642\u0627\u0644\u0628 \u0646\u0627\u0634\u0646\u0627\u062E\u062A\u0647 ''{1}'' -id = {0}: "{1}" \u06CC\u06A9 {2} \u0645\u0639\u062A\u0628\u0631 \u0646\u06CC\u0633\u062A -items = {0}: \u0646\u0645\u0627\u06CC\u0647 ''{1}'' \u062F\u0631 \u0637\u0631\u062D \u062A\u0639\u0631\u06CC\u0641 \u0646\u0634\u062F\u0647 \u0627\u0633\u062A \u0648 \u0637\u0631\u062D \u0645\u0648\u0627\u0631\u062F \u0627\u0636\u0627\u0641\u06CC \u0631\u0627 \u0645\u062C\u0627\u0632 \u0646\u0645\u06CC \u06A9\u0646\u062F -maxContains = {0}: \u0628\u0627\u06CC\u062F \u06CC\u06A9 \u0639\u062F\u062F \u0635\u062D\u06CC\u062D \u063A\u06CC\u0631 \u0645\u0646\u0641\u06CC \u062F\u0631 {1} \u0628\u0627\u0634\u062F -maxItems = {0}: \u0628\u0627\u06CC\u062F \u062D\u062F\u0627\u06A9\u062B\u0631 {1} \u0645\u0648\u0631\u062F \u062F\u0627\u0634\u062A\u0647 \u0628\u0627\u0634\u062F \u0627\u0645\u0627 {2} \u06CC\u0627\u0641\u062A \u0634\u0648\u062F -maxLength = {0}: \u0628\u0627\u06CC\u062F \u062D\u062F\u0627\u06A9\u062B\u0631 {1} \u06A9\u0627\u0631\u0627\u06A9\u062A\u0631 \u0628\u0627\u0634\u062F -maxProperties = {0}: \u0628\u0627\u06CC\u062F \u062D\u062F\u0627\u06A9\u062B\u0631 {1} \u0648\u06CC\u0698\u06AF\u06CC \u062F\u0627\u0634\u062A\u0647 \u0628\u0627\u0634\u062F -maximum = {0}: \u0628\u0627\u06CC\u062F \u062D\u062F\u0627\u06A9\u062B\u0631 \u0645\u0642\u062F\u0627\u0631 {1} \u062F\u0627\u0634\u062A\u0647 \u0628\u0627\u0634\u062F -minContains = {0}: \u0628\u0627\u06CC\u062F \u06CC\u06A9 \u0639\u062F\u062F \u0635\u062D\u06CC\u062D \u063A\u06CC\u0631 \u0645\u0646\u0641\u06CC \u062F\u0631 {1} \u0628\u0627\u0634\u062F -minContainsVsMaxContains = {0}: minContains \u0628\u0627\u06CC\u062F \u06A9\u0645\u062A\u0631 \u06CC\u0627 \u0645\u0633\u0627\u0648\u06CC maxContains \u062F\u0631 {1} -minItems = {0}: \u0628\u0627\u06CC\u062F \u062D\u062F\u0627\u0642\u0644 {1} \u0645\u0648\u0631\u062F \u062F\u0627\u0634\u062A\u0647 \u0628\u0627\u0634\u062F \u0627\u0645\u0627 {2} \u067E\u06CC\u062F\u0627 \u0634\u062F\u0647 \u0628\u0627\u0634\u062F -minLength = {0}: \u0628\u0627\u06CC\u062F \u062D\u062F\u0627\u0642\u0644 {1} \u06A9\u0627\u0631\u0627\u06A9\u062A\u0631 \u0628\u0627\u0634\u062F -minProperties = {0}: \u0628\u0627\u06CC\u062F \u062D\u062F\u0627\u0642\u0644 {1} \u0648\u06CC\u0698\u06AF\u06CC \u062F\u0627\u0634\u062A\u0647 \u0628\u0627\u0634\u062F -minimum = {0}: \u0628\u0627\u06CC\u062F \u062D\u062F\u0627\u0642\u0644 \u0645\u0642\u062F\u0627\u0631 {1} \u062F\u0627\u0634\u062A\u0647 \u0628\u0627\u0634\u062F -multipleOf = {0}: \u0628\u0627\u06CC\u062F \u0645\u0636\u0631\u0628 {1} \u0628\u0627\u0634\u062F -not = {0}: \u0646\u0628\u0627\u06CC\u062F \u0628\u0631\u0627\u06CC \u0637\u0631\u062D\u0648\u0627\u0631\u0647 \u0645\u0639\u062A\u0628\u0631 \u0628\u0627\u0634\u062F {1} -notAllowed = {0}: \u0648\u06CC\u0698\u06AF\u06CC "{1}" \u0645\u062C\u0627\u0632 \u0646\u06CC\u0633\u062A \u0627\u0645\u0627 \u062F\u0631 \u062F\u0627\u062F\u0647 \u0647\u0627 \u0648\u062C\u0648\u062F \u062F\u0627\u0631\u062F -oneOf = {0}: \u0628\u0627\u06CC\u062F \u0628\u0631\u0627\u06CC \u06CC\u06A9 \u0648 \u062A\u0646\u0647\u0627 \u06CC\u06A9 \u0637\u0631\u062D\u0648\u0627\u0631\u0647 \u0645\u0639\u062A\u0628\u0631 \u0628\u0627\u0634\u062F\u060C \u0627\u0645\u0627 {1} \u0645\u0639\u062A\u0628\u0631 \u0647\u0633\u062A\u0646\u062F -oneOf.indexes = {0}: \u0628\u0627\u06CC\u062F \u0628\u0631\u0627\u06CC \u06CC\u06A9 \u0648 \u062A\u0646\u0647\u0627 \u06CC\u06A9 \u0637\u0631\u062D\u0648\u0627\u0631\u0647 \u0645\u0639\u062A\u0628\u0631 \u0628\u0627\u0634\u062F\u060C \u0627\u0645\u0627 {1} \u0628\u0627 \u0646\u0645\u0627\u06CC\u0647 \u0647\u0627\u06CC ''{2}'' \u0645\u0639\u062A\u0628\u0631 \u0647\u0633\u062A\u0646\u062F -pattern = {0}: \u0628\u0627 \u0627\u0644\u06AF\u0648\u06CC regex \u0645\u0637\u0627\u0628\u0642\u062A \u0646\u062F\u0627\u0631\u062F {1} -patternProperties = {0}: \u062F\u0627\u0631\u0627\u06CC \u0645\u0642\u062F\u0627\u0631\u06CC \u062E\u0637\u0627 \u0628\u0627 "\u062E\u0648\u0627\u0635 \u0627\u0644\u06AF\u0648" \u0627\u0633\u062A -prefixItems = {0}: \u0647\u06CC\u0686 \u0627\u0639\u062A\u0628\u0627\u0631\u0633\u0646\u062C\u06CC \u062F\u0631 \u0627\u06CC\u0646 \u0641\u0647\u0631\u0633\u062A \u06CC\u0627\u0641\u062A \u0646\u0634\u062F -properties = {0}: \u062F\u0627\u0631\u0627\u06CC \u06CC\u06A9 \u062E\u0637\u0627 \u0628\u0627 "properties" \u0627\u0633\u062A -propertyNames = {0}: \u0646\u0627\u0645 \u0648\u06CC\u0698\u06AF\u06CC ''{1}'' \u0645\u0639\u062A\u0628\u0631 \u0646\u06CC\u0633\u062A: {2} -readOnly = {0}: \u06CC\u06A9 \u0641\u06CC\u0644\u062F \u0641\u0642\u0637 \u062E\u0648\u0627\u0646\u062F\u0646\u06CC \u0627\u0633\u062A\u060C \u0646\u0645\u06CC \u062A\u0648\u0627\u0646 \u0622\u0646 \u0631\u0627 \u062A\u063A\u06CC\u06CC\u0631 \u062F\u0627\u062F -required = {0}: \u0648\u06CC\u0698\u06AF\u06CC \u0645\u0648\u0631\u062F \u0646\u06CC\u0627\u0632 ''{1}'' \u06CC\u0627\u0641\u062A \u0646\u0634\u062F -type = {0}: {1} \u06CC\u0627\u0641\u062A \u0634\u062F\u060C {2} \u0645\u0648\u0631\u062F \u0627\u0646\u062A\u0638\u0627\u0631 \u0628\u0648\u062F -unevaluatedItems = {0}: \u0646\u0645\u0627\u06CC\u0647 ''{1}'' \u0627\u0631\u0632\u06CC\u0627\u0628\u06CC \u0646\u0645\u06CC \u0634\u0648\u062F \u0648 \u0637\u0631\u062D\u0648\u0627\u0631\u0647 \u0645\u0648\u0627\u0631\u062F \u0627\u0631\u0632\u06CC\u0627\u0628\u06CC \u0646\u0634\u062F\u0647 \u0631\u0627 \u0645\u062C\u0627\u0632 \u0646\u0645\u06CC \u062F\u0627\u0646\u062F -unevaluatedProperties = {0}: \u0648\u06CC\u0698\u06AF\u06CC ''{1}'' \u0627\u0631\u0632\u06CC\u0627\u0628\u06CC \u0646\u0645\u06CC \u0634\u0648\u062F \u0648 \u0627\u06CC\u0646 \u0637\u0631\u062D \u0648\u06CC\u0698\u06AF\u06CC \u0647\u0627\u06CC \u0627\u0631\u0632\u06CC\u0627\u0628\u06CC \u0646\u0634\u062F\u0647 \u0631\u0627 \u0627\u062C\u0627\u0632\u0647 \u0646\u0645\u06CC \u062F\u0647\u062F -unionType = {0}: {1} \u06CC\u0627\u0641\u062A \u0634\u062F\u060C {2} \u0645\u0648\u0631\u062F \u0627\u0646\u062A\u0638\u0627\u0631 \u0628\u0648\u062F -uniqueItems = {0}: \u0628\u0627\u06CC\u062F \u0641\u0642\u0637 \u0645\u0648\u0627\u0631\u062F \u0645\u0646\u062D\u0635\u0631 \u0628\u0647 \u0641\u0631\u062F \u062F\u0631 \u0622\u0631\u0627\u06CC\u0647 \u062F\u0627\u0634\u062A\u0647 \u0628\u0627\u0634\u062F -writeOnly = {0}: \u06CC\u06A9 \u0641\u06CC\u0644\u062F \u0641\u0642\u0637 \u0646\u0648\u0634\u062A\u0646\u06CC \u0627\u0633\u062A\u060C \u0646\u0645\u06CC \u062A\u0648\u0627\u0646\u062F \u062F\u0631 \u062F\u0627\u062F\u0647 \u0647\u0627 \u0638\u0627\u0647\u0631 \u0634\u0648\u062F -contentEncoding = {0}: \u0628\u0627 \u06A9\u062F\u06AF\u0630\u0627\u0631\u06CC \u0645\u062D\u062A\u0648\u0627 \u0645\u0637\u0627\u0628\u0642\u062A \u0646\u062F\u0627\u0631\u062F {1} -contentMediaType = {0}: \u06CC\u06A9 \u0645\u062D\u062A\u0648\u0627\u06CC \u0645\u0646 \u0646\u06CC\u0633\u062A +$ref = \u062F\u0627\u0631\u0627\u06CC \u062E\u0637\u0627 \u0628\u0627 "refs" \u0627\u0633\u062A +additionalItems = \u0646\u0645\u0627\u06CC\u0647 ''{0}'' \u062F\u0631 \u0627\u06CC\u0646 \u0637\u0631\u062D \u062A\u0639\u0631\u06CC\u0641 \u0646\u0634\u062F\u0647 \u0627\u0633\u062A \u0648 \u0637\u0631\u062D \u0645\u0648\u0627\u0631\u062F \u0627\u0636\u0627\u0641\u06CC \u0631\u0627 \u0645\u062C\u0627\u0632 \u0646\u0645\u06CC\u200C\u062F\u0627\u0646\u062F +additionalProperties = \u062E\u0627\u0635\u06CC\u062A ''{0}'' \u062F\u0631 \u0637\u0631\u062D \u062A\u0639\u0631\u06CC\u0641 \u0646\u0634\u062F\u0647 \u0627\u0633\u062A \u0648 \u0627\u06CC\u0646 \u0637\u0631\u062D \u0648\u06CC\u0698\u06AF\u06CC \u0647\u0627\u06CC \u0627\u0636\u0627\u0641\u06CC \u0631\u0627 \u0627\u062C\u0627\u0632\u0647 \u0646\u0645\u06CC \u062F\u0647\u062F +allOf = \u0628\u0627\u06CC\u062F \u0628\u0631\u0627\u06CC \u0647\u0645\u0647 \u0637\u0631\u062D\u0648\u0627\u0631\u0647 \u0647\u0627 \u0645\u0639\u062A\u0628\u0631 \u0628\u0627\u0634\u062F {0} +anyOf = \u0628\u0627\u06CC\u062F \u0628\u0631\u0627\u06CC \u0647\u0631 \u06CC\u06A9 \u0627\u0632 \u0637\u0631\u062D\u0648\u0627\u0631\u0647 \u0647\u0627 \u0645\u0639\u062A\u0628\u0631 \u0628\u0627\u0634\u062F {0} +const = \u0628\u0627\u06CC\u062F \u0645\u0642\u062F\u0627\u0631 \u062B\u0627\u0628\u062A "{0}" \u0628\u0627\u0634\u062F +contains = \u062D\u0627\u0648\u06CC \u0639\u0646\u0635\u0631\u06CC \u0646\u06CC\u0633\u062A \u06A9\u0647 \u0627\u06CC\u0646 \u0627\u0639\u062A\u0628\u0627\u0631\u0633\u0646\u062C\u06CC \u0647\u0627 \u0631\u0627 \u067E\u0627\u0633 \u06A9\u0646\u062F: {1} +contains.max = \u0628\u0627\u06CC\u062F \u062D\u062F\u0627\u06A9\u062B\u0631 \u062D\u0627\u0648\u06CC {0} \u0639\u0646\u0635\u0631 (\u0647\u0627) \u0628\u0627\u0634\u062F \u06A9\u0647 \u0627\u06CC\u0646 \u0627\u0639\u062A\u0628\u0627\u0631\u0633\u0646\u062C\u06CC \u0647\u0627 \u0631\u0627 \u067E\u0627\u0633 \u0645\u06CC \u06A9\u0646\u062F: {1} +contains.min = \u0628\u0627\u06CC\u062F \u062D\u062F\u0627\u0642\u0644 \u0634\u0627\u0645\u0644 {0} \u0639\u0646\u0635\u0631 (\u0647\u0627) \u0628\u0627\u0634\u062F \u06A9\u0647 \u0627\u06CC\u0646 \u0627\u0639\u062A\u0628\u0627\u0631\u0633\u0646\u062C\u06CC \u0647\u0627 \u0631\u0627 \u0628\u06AF\u0630\u0631\u0627\u0646\u062F: {1} +dependencies = \u062F\u0627\u0631\u0627\u06CC \u06CC\u06A9 \u062E\u0637\u0627 \u062F\u0631 \u0648\u0627\u0628\u0633\u062A\u06AF\u06CC {0} +dependentRequired = \u062F\u0627\u0631\u0627\u06CC \u06CC\u06A9 \u0648\u06CC\u0698\u06AF\u06CC \u06AF\u0645 \u0634\u062F\u0647 "{0}" \u0627\u0633\u062A \u06A9\u0647 \u0628\u0647 \u062F\u0644\u06CC\u0644 \u0648\u062C\u0648\u062F "{1}" \u0648\u0627\u0628\u0633\u062A\u0647 \u0627\u0633\u062A +dependentSchemas = \u062F\u0627\u0631\u0627\u06CC \u062E\u0637\u0627 \u0628\u0627 dependentSchemas {0} +enum = \u0645\u0642\u062F\u0627\u0631\u06CC \u062F\u0631 \u0634\u0645\u0627\u0631\u0634 {0} \u0646\u062F\u0627\u0631\u062F +exclusiveMaximum = \u0628\u0627\u06CC\u062F \u062D\u062F\u0627\u06A9\u062B\u0631 \u0645\u0642\u062F\u0627\u0631 \u0627\u0646\u062D\u0635\u0627\u0631\u06CC {0} \u062F\u0627\u0634\u062A\u0647 \u0628\u0627\u0634\u062F +exclusiveMinimum = \u0628\u0627\u06CC\u062F \u062D\u062F\u0627\u0642\u0644 \u0645\u0642\u062F\u0627\u0631 \u0627\u0646\u062D\u0635\u0627\u0631\u06CC {0} \u062F\u0627\u0634\u062A\u0647 \u0628\u0627\u0634\u062F +false = \u0637\u0631\u062D\u0648\u0627\u0631\u0647 ''{0}'' \u0646\u0627\u062F\u0631\u0633\u062A \u0627\u0633\u062A +format = \u0628\u0627 \u0627\u0644\u06AF\u0648\u06CC {0} \u0645\u0637\u0627\u0628\u0642\u062A \u0646\u062F\u0627\u0631\u062F +format.date = \u0628\u0627 \u0627\u0644\u06AF\u0648\u06CC {0} \u0645\u0637\u0627\u0628\u0642\u062A \u0646\u062F\u0627\u0631\u062F \u0628\u0627\u06CC\u062F \u062A\u0627\u0631\u06CC\u062E \u06A9\u0627\u0645\u0644 RFC 3339 \u0645\u0639\u062A\u0628\u0631 \u0628\u0627\u0634\u062F +format.date-time = \u0628\u0627 \u0627\u0644\u06AF\u0648\u06CC {0} \u0645\u0637\u0627\u0628\u0642\u062A \u0646\u062F\u0627\u0631\u062F \u0628\u0627\u06CC\u062F \u062A\u0627\u0631\u06CC\u062E \u0648 \u0632\u0645\u0627\u0646 RFC 3339 \u0645\u0639\u062A\u0628\u0631 \u0628\u0627\u0634\u062F +format.duration = \u0628\u0627 \u0627\u0644\u06AF\u0648\u06CC {0} \u0645\u0637\u0627\u0628\u0642\u062A \u0646\u062F\u0627\u0631\u062F \u0628\u0627\u06CC\u062F \u0645\u062F\u062A \u0632\u0645\u0627\u0646 ISO 8601 \u0645\u0639\u062A\u0628\u0631 \u0628\u0627\u0634\u062F +format.email = \u0628\u0627 \u0627\u0644\u06AF\u0648\u06CC {0} \u0645\u0637\u0627\u0628\u0642\u062A \u0646\u062F\u0627\u0631\u062F \u0628\u0627\u06CC\u062F \u06CC\u06A9 \u0635\u0646\u062F\u0648\u0642 \u067E\u0633\u062A\u06CC RFC 5321 \u0645\u0639\u062A\u0628\u0631 \u0628\u0627\u0634\u062F +format.ipv4 = \u0628\u0627 \u0627\u0644\u06AF\u0648\u06CC {0} \u0645\u0637\u0627\u0628\u0642\u062A \u0646\u062F\u0627\u0631\u062F \u0628\u0627\u06CC\u062F \u06CC\u06A9 \u0622\u062F\u0631\u0633 IP \u0645\u0639\u062A\u0628\u0631 RFC 2673 \u0628\u0627\u0634\u062F +format.ipv6 = \u0628\u0627 \u0627\u0644\u06AF\u0648\u06CC {0} \u0645\u0637\u0627\u0628\u0642\u062A \u0646\u062F\u0627\u0631\u062F \u0628\u0627\u06CC\u062F \u06CC\u06A9 \u0622\u062F\u0631\u0633 IP \u0645\u0639\u062A\u0628\u0631 RFC 4291 \u0628\u0627\u0634\u062F +format.idn-email = \u0628\u0627 \u0627\u0644\u06AF\u0648\u06CC {0} \u0645\u0637\u0627\u0628\u0642\u062A \u0646\u062F\u0627\u0631\u062F \u0628\u0627\u06CC\u062F \u06CC\u06A9 \u0635\u0646\u062F\u0648\u0642 \u067E\u0633\u062A\u06CC RFC 6531 \u0645\u0639\u062A\u0628\u0631 \u0628\u0627\u0634\u062F +format.idn-hostname = \u0628\u0627 \u0627\u0644\u06AF\u0648\u06CC {0} \u0645\u0637\u0627\u0628\u0642\u062A \u0646\u062F\u0627\u0631\u062F \u0628\u0627\u06CC\u062F \u06CC\u06A9 \u0646\u0627\u0645 \u0645\u06CC\u0632\u0628\u0627\u0646 \u0628\u06CC\u0646 \u0627\u0644\u0645\u0644\u0644\u06CC \u0634\u062F\u0647 \u0645\u0639\u062A\u0628\u0631 RFC 5890 \u0628\u0627\u0634\u062F. +format.iri = \u0628\u0627 \u0627\u0644\u06AF\u0648\u06CC {0} \u0645\u0637\u0627\u0628\u0642\u062A \u0646\u062F\u0627\u0631\u062F \u0628\u0627\u06CC\u062F \u06CC\u06A9 RFC 3987 IRI \u0645\u0639\u062A\u0628\u0631 \u0628\u0627\u0634\u062F +format.iri-reference = \u0628\u0627 \u0627\u0644\u06AF\u0648\u06CC {0} \u0645\u0637\u0627\u0628\u0642\u062A \u0646\u062F\u0627\u0631\u062F \u0628\u0627\u06CC\u062F \u0645\u0631\u062C\u0639 \u0645\u0639\u062A\u0628\u0631 RFC 3987 IRI \u0628\u0627\u0634\u062F +format.uri = \u0628\u0627 \u0627\u0644\u06AF\u0648\u06CC {0} \u0645\u0637\u0627\u0628\u0642\u062A \u0646\u062F\u0627\u0631\u062F \u0628\u0627\u06CC\u062F \u06CC\u06A9 URI RFC 3986 \u0645\u0639\u062A\u0628\u0631 \u0628\u0627\u0634\u062F +format.uri-reference = \u0628\u0627 \u0627\u0644\u06AF\u0648\u06CC {0} \u0645\u0637\u0627\u0628\u0642\u062A \u0646\u062F\u0627\u0631\u062F \u0628\u0627\u06CC\u062F \u06CC\u06A9 \u0645\u0631\u062C\u0639 URI RFC 3986 \u0645\u0639\u062A\u0628\u0631 \u0628\u0627\u0634\u062F +format.uri-template = \u0628\u0627 \u0627\u0644\u06AF\u0648\u06CC {0} \u0645\u0637\u0627\u0628\u0642\u062A \u0646\u062F\u0627\u0631\u062F \u0628\u0627\u06CC\u062F \u06CC\u06A9 \u0627\u0644\u06AF\u0648\u06CC URI RFC 6570 \u0645\u0639\u062A\u0628\u0631 \u0628\u0627\u0634\u062F +format.uuid = \u0628\u0627 \u0627\u0644\u06AF\u0648\u06CC {0} \u0645\u0637\u0627\u0628\u0642\u062A \u0646\u062F\u0627\u0631\u062F \u0628\u0627\u06CC\u062F \u06CC\u06A9 UUID RFC 4122 \u0645\u0639\u062A\u0628\u0631 \u0628\u0627\u0634\u062F +format.regex = \u0628\u0627 \u0627\u0644\u06AF\u0648\u06CC {0} \u0645\u0637\u0627\u0628\u0642\u062A \u0646\u062F\u0627\u0631\u062F \u0628\u0627\u06CC\u062F \u06CC\u06A9 \u0639\u0628\u0627\u0631\u062A \u0645\u0646\u0638\u0645 ECMA-262 \u0645\u0639\u062A\u0628\u0631 \u0628\u0627\u0634\u062F +format.time = \u0628\u0627 \u0627\u0644\u06AF\u0648\u06CC {0} \u0645\u0637\u0627\u0628\u0642\u062A \u0646\u062F\u0627\u0631\u062F \u0628\u0627\u06CC\u062F \u0632\u0645\u0627\u0646 \u0645\u0639\u062A\u0628\u0631 RFC 3339 \u0628\u0627\u0634\u062F +format.hostname = \u0628\u0627 \u0627\u0644\u06AF\u0648\u06CC {0} \u0645\u0637\u0627\u0628\u0642\u062A \u0646\u062F\u0627\u0631\u062F \u0628\u0627\u06CC\u062F \u06CC\u06A9 \u0646\u0627\u0645 \u0645\u06CC\u0632\u0628\u0627\u0646 \u0645\u0639\u062A\u0628\u0631 RFC 1123 \u0628\u0627\u0634\u062F +format.json-pointer = \u0628\u0627 \u0627\u0644\u06AF\u0648\u06CC {0} \u0645\u0637\u0627\u0628\u0642\u062A \u0646\u062F\u0627\u0631\u062F \u0628\u0627\u06CC\u062F RFC 6901 JSON Pointer \u0645\u0639\u062A\u0628\u0631 \u0628\u0627\u0634\u062F +format.relative-json-pointer = \u0628\u0627 \u0627\u0644\u06AF\u0648\u06CC {0} \u0645\u0637\u0627\u0628\u0642\u062A \u0646\u062F\u0627\u0631\u062F \u0628\u0627\u06CC\u062F \u06CC\u06A9 \u0646\u0634\u0627\u0646\u06AF\u0631 JSON \u0646\u0633\u0628\u06CC IETF \u0645\u0639\u062A\u0628\u0631 \u0628\u0627\u0634\u062F +format.unknown = \u062F\u0627\u0631\u0627\u06CC \u0642\u0627\u0644\u0628 \u0646\u0627\u0634\u0646\u0627\u062E\u062A\u0647 ''{0}'' +id = "{0}" \u06CC\u06A9 {1} \u0645\u0639\u062A\u0628\u0631 \u0646\u06CC\u0633\u062A +items = \u0646\u0645\u0627\u06CC\u0647 ''{0}'' \u062F\u0631 \u0637\u0631\u062D \u062A\u0639\u0631\u06CC\u0641 \u0646\u0634\u062F\u0647 \u0627\u0633\u062A \u0648 \u0637\u0631\u062D \u0645\u0648\u0627\u0631\u062F \u0627\u0636\u0627\u0641\u06CC \u0631\u0627 \u0645\u062C\u0627\u0632 \u0646\u0645\u06CC \u06A9\u0646\u062F +maxContains = \u0628\u0627\u06CC\u062F \u06CC\u06A9 \u0639\u062F\u062F \u0635\u062D\u06CC\u062D \u063A\u06CC\u0631 \u0645\u0646\u0641\u06CC \u062F\u0631 {0} \u0628\u0627\u0634\u062F +maxItems = \u0628\u0627\u06CC\u062F \u062D\u062F\u0627\u06A9\u062B\u0631 {0} \u0645\u0648\u0631\u062F \u062F\u0627\u0634\u062A\u0647 \u0628\u0627\u0634\u062F \u0627\u0645\u0627 {1} \u06CC\u0627\u0641\u062A \u0634\u0648\u062F +maxLength = \u0628\u0627\u06CC\u062F \u062D\u062F\u0627\u06A9\u062B\u0631 {0} \u06A9\u0627\u0631\u0627\u06A9\u062A\u0631 \u0628\u0627\u0634\u062F +maxProperties = \u0628\u0627\u06CC\u062F \u062D\u062F\u0627\u06A9\u062B\u0631 {0} \u0648\u06CC\u0698\u06AF\u06CC \u062F\u0627\u0634\u062A\u0647 \u0628\u0627\u0634\u062F +maximum = \u0628\u0627\u06CC\u062F \u062D\u062F\u0627\u06A9\u062B\u0631 \u0645\u0642\u062F\u0627\u0631 {0} \u062F\u0627\u0634\u062A\u0647 \u0628\u0627\u0634\u062F +minContains = \u0628\u0627\u06CC\u062F \u06CC\u06A9 \u0639\u062F\u062F \u0635\u062D\u06CC\u062D \u063A\u06CC\u0631 \u0645\u0646\u0641\u06CC \u062F\u0631 {0} \u0628\u0627\u0634\u062F +minContainsVsMaxContains = minContains \u0628\u0627\u06CC\u062F \u06A9\u0645\u062A\u0631 \u06CC\u0627 \u0645\u0633\u0627\u0648\u06CC maxContains \u062F\u0631 {0} +minItems = \u0628\u0627\u06CC\u062F \u062D\u062F\u0627\u0642\u0644 {0} \u0645\u0648\u0631\u062F \u062F\u0627\u0634\u062A\u0647 \u0628\u0627\u0634\u062F \u0627\u0645\u0627 {1} \u067E\u06CC\u062F\u0627 \u0634\u062F\u0647 \u0628\u0627\u0634\u062F +minLength = \u0628\u0627\u06CC\u062F \u062D\u062F\u0627\u0642\u0644 {0} \u06A9\u0627\u0631\u0627\u06A9\u062A\u0631 \u0628\u0627\u0634\u062F +minProperties = \u0628\u0627\u06CC\u062F \u062D\u062F\u0627\u0642\u0644 {0} \u0648\u06CC\u0698\u06AF\u06CC \u062F\u0627\u0634\u062A\u0647 \u0628\u0627\u0634\u062F +minimum = \u0628\u0627\u06CC\u062F \u062D\u062F\u0627\u0642\u0644 \u0645\u0642\u062F\u0627\u0631 {0} \u062F\u0627\u0634\u062A\u0647 \u0628\u0627\u0634\u062F +multipleOf = \u0628\u0627\u06CC\u062F \u0645\u0636\u0631\u0628 {0} \u0628\u0627\u0634\u062F +not = \u0646\u0628\u0627\u06CC\u062F \u0628\u0631\u0627\u06CC \u0637\u0631\u062D\u0648\u0627\u0631\u0647 \u0645\u0639\u062A\u0628\u0631 \u0628\u0627\u0634\u062F {0} +notAllowed = \u0648\u06CC\u0698\u06AF\u06CC "{0}" \u0645\u062C\u0627\u0632 \u0646\u06CC\u0633\u062A \u0627\u0645\u0627 \u062F\u0631 \u062F\u0627\u062F\u0647 \u0647\u0627 \u0648\u062C\u0648\u062F \u062F\u0627\u0631\u062F +oneOf = \u0628\u0627\u06CC\u062F \u0628\u0631\u0627\u06CC \u06CC\u06A9 \u0648 \u062A\u0646\u0647\u0627 \u06CC\u06A9 \u0637\u0631\u062D\u0648\u0627\u0631\u0647 \u0645\u0639\u062A\u0628\u0631 \u0628\u0627\u0634\u062F\u060C \u0627\u0645\u0627 {0} \u0645\u0639\u062A\u0628\u0631 \u0647\u0633\u062A\u0646\u062F +oneOf.indexes = \u0628\u0627\u06CC\u062F \u0628\u0631\u0627\u06CC \u06CC\u06A9 \u0648 \u062A\u0646\u0647\u0627 \u06CC\u06A9 \u0637\u0631\u062D\u0648\u0627\u0631\u0647 \u0645\u0639\u062A\u0628\u0631 \u0628\u0627\u0634\u062F\u060C \u0627\u0645\u0627 {0} \u0628\u0627 \u0646\u0645\u0627\u06CC\u0647 \u0647\u0627\u06CC ''{1}'' \u0645\u0639\u062A\u0628\u0631 \u0647\u0633\u062A\u0646\u062F +pattern = \u0628\u0627 \u0627\u0644\u06AF\u0648\u06CC regex \u0645\u0637\u0627\u0628\u0642\u062A \u0646\u062F\u0627\u0631\u062F {0} +patternProperties = \u062F\u0627\u0631\u0627\u06CC \u0645\u0642\u062F\u0627\u0631\u06CC \u062E\u0637\u0627 \u0628\u0627 "\u062E\u0648\u0627\u0635 \u0627\u0644\u06AF\u0648" \u0627\u0633\u062A +prefixItems = \u0647\u06CC\u0686 \u0627\u0639\u062A\u0628\u0627\u0631\u0633\u0646\u062C\u06CC \u062F\u0631 \u0627\u06CC\u0646 \u0641\u0647\u0631\u0633\u062A \u06CC\u0627\u0641\u062A \u0646\u0634\u062F +properties = \u062F\u0627\u0631\u0627\u06CC \u06CC\u06A9 \u062E\u0637\u0627 \u0628\u0627 "properties" \u0627\u0633\u062A +propertyNames = \u0646\u0627\u0645 \u0648\u06CC\u0698\u06AF\u06CC ''{0}'' \u0645\u0639\u062A\u0628\u0631 \u0646\u06CC\u0633\u062A: {1} +readOnly = \u06CC\u06A9 \u0641\u06CC\u0644\u062F \u0641\u0642\u0637 \u062E\u0648\u0627\u0646\u062F\u0646\u06CC \u0627\u0633\u062A\u060C \u0646\u0645\u06CC \u062A\u0648\u0627\u0646 \u0622\u0646 \u0631\u0627 \u062A\u063A\u06CC\u06CC\u0631 \u062F\u0627\u062F +required = \u0648\u06CC\u0698\u06AF\u06CC \u0645\u0648\u0631\u062F \u0646\u06CC\u0627\u0632 ''{0}'' \u06CC\u0627\u0641\u062A \u0646\u0634\u062F +type = {0} \u06CC\u0627\u0641\u062A \u0634\u062F\u060C {1} \u0645\u0648\u0631\u062F \u0627\u0646\u062A\u0638\u0627\u0631 \u0628\u0648\u062F +unevaluatedItems = \u0646\u0645\u0627\u06CC\u0647 ''{0}'' \u0627\u0631\u0632\u06CC\u0627\u0628\u06CC \u0646\u0645\u06CC \u0634\u0648\u062F \u0648 \u0637\u0631\u062D\u0648\u0627\u0631\u0647 \u0645\u0648\u0627\u0631\u062F \u0627\u0631\u0632\u06CC\u0627\u0628\u06CC \u0646\u0634\u062F\u0647 \u0631\u0627 \u0645\u062C\u0627\u0632 \u0646\u0645\u06CC \u062F\u0627\u0646\u062F +unevaluatedProperties = \u0648\u06CC\u0698\u06AF\u06CC ''{0}'' \u0627\u0631\u0632\u06CC\u0627\u0628\u06CC \u0646\u0645\u06CC \u0634\u0648\u062F \u0648 \u0627\u06CC\u0646 \u0637\u0631\u062D \u0648\u06CC\u0698\u06AF\u06CC \u0647\u0627\u06CC \u0627\u0631\u0632\u06CC\u0627\u0628\u06CC \u0646\u0634\u062F\u0647 \u0631\u0627 \u0627\u062C\u0627\u0632\u0647 \u0646\u0645\u06CC \u062F\u0647\u062F +unionType = {0} \u06CC\u0627\u0641\u062A \u0634\u062F\u060C {1} \u0645\u0648\u0631\u062F \u0627\u0646\u062A\u0638\u0627\u0631 \u0628\u0648\u062F +uniqueItems = \u0628\u0627\u06CC\u062F \u0641\u0642\u0637 \u0645\u0648\u0627\u0631\u062F \u0645\u0646\u062D\u0635\u0631 \u0628\u0647 \u0641\u0631\u062F \u062F\u0631 \u0622\u0631\u0627\u06CC\u0647 \u062F\u0627\u0634\u062A\u0647 \u0628\u0627\u0634\u062F +writeOnly = \u06CC\u06A9 \u0641\u06CC\u0644\u062F \u0641\u0642\u0637 \u0646\u0648\u0634\u062A\u0646\u06CC \u0627\u0633\u062A\u060C \u0646\u0645\u06CC \u062A\u0648\u0627\u0646\u062F \u062F\u0631 \u062F\u0627\u062F\u0647 \u0647\u0627 \u0638\u0627\u0647\u0631 \u0634\u0648\u062F +contentEncoding = \u0628\u0627 \u06A9\u062F\u06AF\u0630\u0627\u0631\u06CC \u0645\u062D\u062A\u0648\u0627 \u0645\u0637\u0627\u0628\u0642\u062A \u0646\u062F\u0627\u0631\u062F {0} +contentMediaType = \u06CC\u06A9 \u0645\u062D\u062A\u0648\u0627\u06CC \u0645\u0646 \u0646\u06CC\u0633\u062A diff --git a/src/main/resources/jsv-messages_fi.properties b/src/main/resources/jsv-messages_fi.properties index a6498eb14..7c21d02c0 100644 --- a/src/main/resources/jsv-messages_fi.properties +++ b/src/main/resources/jsv-messages_fi.properties @@ -1,70 +1,70 @@ -$ref = {0}: siinä on virhe "viittauksilla" -additionalItems = {0}: hakemistoa ''{1}'' ei ole määritetty skeemassa, eikä skeema salli lisäkohteita -additionalProperties = {0}: ominaisuutta ''{1}'' ei ole määritetty skeemassa, eikä skeema salli lisäominaisuuksia -allOf = {0}: täytyy olla voimassa kaikissa malleissa {1} -anyOf = {0}: täytyy olla kelvollinen mille tahansa skeemalle {1} -const = {0}: on oltava vakioarvo ''{1}'' -contains = {0}: ei sisällä elementtiä, joka läpäisee seuraavat tarkistukset: {2} -contains.max = {0}: saa sisältää enintään {1} elementtiä, jotka läpäisevät nämä tarkistukset: {2} -contains.min = {0}: sisältää vähintään {1} elementtiä, jotka läpäisevät nämä tarkistukset: {2} -dependencies = {0}: siinä on virhe riippuvuuksien {1} kanssa -dependentRequired = {0}: puuttuu ominaisuus "{1}", joka on riippuvainen, koska "{2}" on läsnä -dependentSchemas = {0}: sisältää virheen dependentSchemasissa {1} -enum = {0}: sillä ei ole arvoa luettelossa {1} -exclusiveMaximum = {0}: eksklusiivisen enimmäisarvon on oltava {1} -exclusiveMinimum = {0}: on oltava yksinomainen vähimmäisarvo {1} -false = {0}: kaava kohteelle ''{1}'' on epätosi -format = {0}: ei vastaa mallia {1} {2} -format.date = {0}: ei vastaa mallia {1}, ja sen on oltava kelvollinen RFC 3339:n täysi päivämäärä -format.date-time = {0}: ei vastaa mallia {1}, ja sen on oltava kelvollinen RFC 3339 päivämäärä-aika -format.duration = {0}: ei vastaa mallia {1}. Sen on oltava kelvollinen ISO 8601 -kesto -format.email = {0}: ei vastaa mallia {1}. Sen on oltava kelvollinen RFC 5321 -postilaatikko -format.ipv4 = {0}: ei vastaa mallia {1}. Sen on oltava kelvollinen RFC 2673 IP-osoite -format.ipv6 = {0}: ei vastaa mallia {1}, ja sen on oltava kelvollinen RFC 4291 IP-osoite -format.idn-email = {0}: ei vastaa mallia {1}. Sen on oltava kelvollinen RFC 6531 -postilaatikko -format.idn-hostname = {0}: ei vastaa mallia {1}. Sen on oltava kelvollinen RFC 5890:n kansainvälistetty isäntänimi -format.iri = {0}: ei vastaa mallia {1}, ja sen on oltava kelvollinen RFC 3987 IRI -format.iri-reference = {0}: ei vastaa {1}-mallia, on oltava kelvollinen RFC 3987 IRI-viite -format.uri = {0}: ei vastaa mallia {1}, ja sen on oltava kelvollinen RFC 3986 URI -format.uri-reference = {0}: ei vastaa {1}-mallia, täytyy olla kelvollinen RFC 3986 URI-viite -format.uri-template = {0}: ei vastaa mallia {1}. Sen on oltava kelvollinen RFC 6570 URI-malli -format.uuid = {0}: ei vastaa mallia {1}. Sen on oltava kelvollinen RFC 4122 UUID -format.regex = {0}: ei vastaa mallia {1}. Sen on oltava kelvollinen ECMA-262-säännöllinen lauseke -format.time = {0}: ei vastaa mallia {1}, sen on oltava kelvollinen RFC 3339 -aika -format.hostname = {0}: ei vastaa mallia {1}. Sen on oltava kelvollinen RFC 1123 -isäntänimi -format.json-pointer = {0}: ei vastaa mallia {1}. Sen on oltava kelvollinen RFC 6901 JSON-osoitin -format.relative-json-pointer = {0}: ei vastaa mallia {1}. Sen on oltava kelvollinen IETF:n suhteellinen JSON-osoitin -format.unknown = {0}: sillä on tuntematon muoto ''{1}'' -id = {0}: ''{1}'' ei ole kelvollinen {2} -items = {0}: hakemistoa ''{1}'' ei ole määritetty skeemassa, eikä skeema salli lisäkohteita -maxContains = {0}: täytyy olla ei-negatiivinen kokonaisluku ryhmässä {1} -maxItems = {0}: saa olla enintään {1} kohdetta, mutta löytyi {2} -maxLength = {0}: saa olla enintään {1} merkkiä pitkä -maxProperties = {0}: saa olla enintään {1} ominaisuutta -maximum = {0}: maksimiarvon on oltava {1} -minContains = {0}: täytyy olla ei-negatiivinen kokonaisluku ryhmässä {1} -minContainsVsMaxContains = {0}: minContains on pienempi tai yhtä suuri kuin maxContains kohteessa {1} -minItems = {0}: on oltava vähintään {1} kohdetta, mutta löydetty {2} -minLength = {0}: on oltava vähintään {1} merkkiä pitkä -minProperties = {0}: on oltava vähintään {1} ominaisuutta -minimum = {0}: vähimmäisarvon on oltava {1} -multipleOf = {0}: täytyy olla {1}:n kerrannainen -not = {0}: ei saa olla kelvollinen kaavalle {1} -notAllowed = {0}: ominaisuus ''{1}'' ei ole sallittu, mutta se on tiedoissa -oneOf = {0}: täytyy olla voimassa vain yhdelle skeemalle, mutta {1} ovat kelvollisia -oneOf.indexes = {0}: täytyy olla voimassa vain yhdelle skeemalle, mutta {1} ovat kelvollisia indeksien ''{2}'' kanssa -pattern = {0}: ei vastaa säännöllisen lausekkeen mallia {1} -patternProperties = {0}: siinä on virhe komennolla "pattern properties" -prefixItems = {0}: tästä hakemistosta ei löytynyt vahvistusta -properties = {0}: sisältää virheen ominaisuuksissa -propertyNames = {0}: ominaisuuden ''{1}'' nimi ei kelpaa: {2} -readOnly = {0}: on vain luku -kenttä, sitä ei voi muuttaa -required = {0}: vaadittua ominaisuutta ''{1}'' ei löydy -type = {0}: {1} löydetty, {2} odotettu -unevaluatedItems = {0}: hakemistoa ''{1}'' ei arvioida, eikä skeema salli arvioimattomia kohteita -unevaluatedProperties = {0}: ominaisuutta ''{1}'' ei arvioida ja skeema ei salli arvioimattomia ominaisuuksia -unionType = {0}: {1} löydetty, {2} odotettu -uniqueItems = {0}: taulukossa saa olla vain yksilöllisiä kohteita -writeOnly = {0}: on vain kirjoituskenttä, se ei voi näkyä tiedoissa -contentEncoding = {0}: ei vastaa sisällön koodausta {1} -contentMediaType = {0}: ei ole sisältöni +$ref = siinä on virhe "viittauksilla" +additionalItems = hakemistoa ''{0}'' ei ole määritetty skeemassa, eikä skeema salli lisäkohteita +additionalProperties = ominaisuutta ''{0}'' ei ole määritetty skeemassa, eikä skeema salli lisäominaisuuksia +allOf = täytyy olla voimassa kaikissa malleissa {0} +anyOf = täytyy olla kelvollinen mille tahansa skeemalle {0} +const = on oltava vakioarvo ''{0}'' +contains = ei sisällä elementtiä, joka läpäisee seuraavat tarkistukset: {1} +contains.max = saa sisältää enintään {0} elementtiä, jotka läpäisevät nämä tarkistukset: {1} +contains.min = sisältää vähintään {0} elementtiä, jotka läpäisevät nämä tarkistukset: {1} +dependencies = siinä on virhe riippuvuuksien {0} kanssa +dependentRequired = puuttuu ominaisuus "{0}", joka on riippuvainen, koska "{1}" on läsnä +dependentSchemas = sisältää virheen dependentSchemasissa {0} +enum = sillä ei ole arvoa luettelossa {0} +exclusiveMaximum = eksklusiivisen enimmäisarvon on oltava {0} +exclusiveMinimum = on oltava yksinomainen vähimmäisarvo {0} +false = kaava kohteelle ''{0}'' on epätosi +format = ei vastaa mallia {0} +format.date = ei vastaa mallia {0}, ja sen on oltava kelvollinen RFC 3339:n täysi päivämäärä +format.date-time = ei vastaa mallia {0}, ja sen on oltava kelvollinen RFC 3339 päivämäärä-aika +format.duration = ei vastaa mallia {0}. Sen on oltava kelvollinen ISO 8601 -kesto +format.email = ei vastaa mallia {0}. Sen on oltava kelvollinen RFC 5321 -postilaatikko +format.ipv4 = ei vastaa mallia {0}. Sen on oltava kelvollinen RFC 2673 IP-osoite +format.ipv6 = ei vastaa mallia {0}, ja sen on oltava kelvollinen RFC 4291 IP-osoite +format.idn-email = ei vastaa mallia {0}. Sen on oltava kelvollinen RFC 6531 -postilaatikko +format.idn-hostname = ei vastaa mallia {0}. Sen on oltava kelvollinen RFC 5890:n kansainvälistetty isäntänimi +format.iri = ei vastaa mallia {0}, ja sen on oltava kelvollinen RFC 3987 IRI +format.iri-reference = ei vastaa {0}-mallia, on oltava kelvollinen RFC 3987 IRI-viite +format.uri = ei vastaa mallia {0}, ja sen on oltava kelvollinen RFC 3986 URI +format.uri-reference = ei vastaa {0}-mallia, täytyy olla kelvollinen RFC 3986 URI-viite +format.uri-template = ei vastaa mallia {0}. Sen on oltava kelvollinen RFC 6570 URI-malli +format.uuid = ei vastaa mallia {0}. Sen on oltava kelvollinen RFC 4122 UUID +format.regex = ei vastaa mallia {0}. Sen on oltava kelvollinen ECMA-262-säännöllinen lauseke +format.time = ei vastaa mallia {0}, sen on oltava kelvollinen RFC 3339 -aika +format.hostname = ei vastaa mallia {0}. Sen on oltava kelvollinen RFC 1123 -isäntänimi +format.json-pointer = ei vastaa mallia {0}. Sen on oltava kelvollinen RFC 6901 JSON-osoitin +format.relative-json-pointer = ei vastaa mallia {0}. Sen on oltava kelvollinen IETF:n suhteellinen JSON-osoitin +format.unknown = sillä on tuntematon muoto ''{0}'' +id = ''{0}'' ei ole kelvollinen {1} +items = hakemistoa ''{0}'' ei ole määritetty skeemassa, eikä skeema salli lisäkohteita +maxContains = täytyy olla ei-negatiivinen kokonaisluku ryhmässä {0} +maxItems = saa olla enintään {0} kohdetta, mutta löytyi {1} +maxLength = saa olla enintään {0} merkkiä pitkä +maxProperties = saa olla enintään {0} ominaisuutta +maximum = maksimiarvon on oltava {0} +minContains = täytyy olla ei-negatiivinen kokonaisluku ryhmässä {0} +minContainsVsMaxContains = minContains on pienempi tai yhtä suuri kuin maxContains kohteessa {0} +minItems = on oltava vähintään {0} kohdetta, mutta löydetty {1} +minLength = on oltava vähintään {0} merkkiä pitkä +minProperties = on oltava vähintään {0} ominaisuutta +minimum = vähimmäisarvon on oltava {0} +multipleOf = täytyy olla {0}:n kerrannainen +not = ei saa olla kelvollinen kaavalle {0} +notAllowed = ominaisuus ''{0}'' ei ole sallittu, mutta se on tiedoissa +oneOf = täytyy olla voimassa vain yhdelle skeemalle, mutta {0} ovat kelvollisia +oneOf.indexes = täytyy olla voimassa vain yhdelle skeemalle, mutta {0} ovat kelvollisia indeksien ''{1}'' kanssa +pattern = ei vastaa säännöllisen lausekkeen mallia {0} +patternProperties = siinä on virhe komennolla "pattern properties" +prefixItems = tästä hakemistosta ei löytynyt vahvistusta +properties = sisältää virheen ominaisuuksissa +propertyNames = ominaisuuden ''{0}'' nimi ei kelpaa: {1} +readOnly = on vain luku -kenttä, sitä ei voi muuttaa +required = vaadittua ominaisuutta ''{0}'' ei löydy +type = {0} löydetty, {1} odotettu +unevaluatedItems = hakemistoa ''{0}'' ei arvioida, eikä skeema salli arvioimattomia kohteita +unevaluatedProperties = ominaisuutta ''{0}'' ei arvioida ja skeema ei salli arvioimattomia ominaisuuksia +unionType = {0} löydetty, {1} odotettu +uniqueItems = taulukossa saa olla vain yksilöllisiä kohteita +writeOnly = on vain kirjoituskenttä, se ei voi näkyä tiedoissa +contentEncoding = ei vastaa sisällön koodausta {0} +contentMediaType = ei ole sisältöni diff --git a/src/main/resources/jsv-messages_fr.properties b/src/main/resources/jsv-messages_fr.properties index aff459ef4..e3cb7668b 100644 --- a/src/main/resources/jsv-messages_fr.properties +++ b/src/main/resources/jsv-messages_fr.properties @@ -1,70 +1,70 @@ -$ref = {0}: il y a une erreur avec ''refs'' -additionalItems = {0}: l''index ''{1}'' n''est pas défini dans le schéma et le schéma n''autorise pas les éléments supplémentaires -additionalProperties = {0}: la propriété ''{1}'' n''est pas définie dans le schéma et le schéma n''autorise pas de propriétés supplémentaires -allOf = {0}: doit être valide pour tous les schémas {1} -anyOf = {0}: doit être valide pour l''un des schémas {1} -const = {0}: doit être la valeur constante ''{1}'' -contains = {0}: ne contient aucun élément qui réussit ces validations : {2} -contains.max = {0}: doit contenir au plus {1} élément(s) qui réussissent ces validations : {2} -contains.min = {0}: doit contenir au moins {1} élément(s) qui réussissent ces validations : {2} -dependencies = {0}: il y a une erreur avec les dépendances {1} -dependentRequired = {0}: a une propriété manquante « {1} » qui est dépendante requise car « {2} » est présente -dependentSchemas = {0}: il y a une erreur avecdependentSchemas {1} -enum = {0}: n''a pas de valeur dans l''énumération {1} -exclusiveMaximum = {0}: doit avoir une valeur maximale exclusive de {1} -exclusiveMinimum = {0}: doit avoir une valeur minimale exclusive de {1} -false = {0}: le schéma de ''{1}'' est faux -format = {0}: ne correspond pas au modèle {1} {2} -format.date = {0}: ne correspond pas au modèle {1} doit être une date complète RFC 3339 valide -format.date-time = {0}: ne correspond pas au modèle {1} doit être une date-heure RFC 3339 valide -format.duration = {0}: ne correspond pas au modèle {1} doit être une durée ISO 8601 valide -format.email = {0}: ne correspond pas au modèle {1} doit être une boîte aux lettres RFC 5321 valide -format.ipv4 = {0}: ne correspond pas au modèle {1} doit être une adresse IP RFC 2673 valide -format.ipv6 = {0}: ne correspond pas au modèle {1} doit être une adresse IP RFC 4291 valide -format.idn-email = {0}: ne correspond pas au modèle {1} doit être une boîte aux lettres RFC 6531 valide -format.idn-hostname = {0}: ne correspond pas au modèle {1} doit être un nom d''hôte internationalisé RFC 5890 valide -format.iri = {0}: ne correspond pas au modèle {1} doit être un IRI RFC 3987 valide -format.iri-reference = {0}: ne correspond pas au modèle {1} doit être une référence IRI RFC 3987 valide -format.uri = {0}: ne correspond pas au modèle {1} doit être un URI RFC 3986 valide -format.uri-reference = {0}: ne correspond pas au modèle {1} doit être une référence URI RFC 3986 valide -format.uri-template = {0}: ne correspond pas au modèle {1} doit être un modèle d''URI RFC 6570 valide -format.uuid = {0}: ne correspond pas au modèle {1} doit être un UUID RFC 4122 valide -format.regex = {0}: ne correspond pas au modèle {1} doit être une expression régulière ECMA-262 valide -format.time = {0}: ne correspond pas au modèle {1} doit être une heure RFC 3339 valide -format.hostname = {0}: ne correspond pas au modèle {1} doit être un nom d''hôte RFC 1123 valide -format.json-pointer = {0}: ne correspond pas au modèle {1} doit être un pointeur JSON RFC 6901 valide -format.relative-json-pointer = {0}: ne correspond pas au modèle {1} doit être un pointeur JSON relatif IETF valide -format.unknown = {0}: a un format inconnu ''{1}'' -id = {0}: ''{1}'' n''est pas un {2} valide -items = {0}: l''index ''{1}'' n''est pas défini dans le schéma et le schéma n''autorise pas d''éléments supplémentaires -maxContains = {0}: doit être un entier non négatif dans {1} -maxItems = {0}: doit contenir au plus {1} éléments mais trouvé {2} -maxLength = {0}: doit contenir au plus {1} caractères -maxProperties = {0}: doit avoir au plus {1} propriétés -maximum = {0}: doit avoir une valeur maximale de {1} -minContains = {0}: doit être un entier non négatif dans {1} -minContainsVsMaxContains = {0}: minContains doit être inférieur ou égal à maxContains dans {1} -minItems = {0}: doit avoir au moins {1} éléments mais trouvé {2} -minLength = {0}: doit contenir au moins {1} caractères -minProperties = {0}: doit avoir au moins {1} propriétés -minimum = {0}: doit avoir une valeur minimale de {1} -multipleOf = {0}: doit être un multiple de {1} -not = {0}: ne doit pas être valide pour le schéma {1} -notAllowed = {0}: la propriété ''{1}'' n''est pas autorisée mais elle est dans les données -oneOf = {0}: doit être valide pour un et un seul schéma, mais {1} sont valides -oneOf.indexes = {0}: doit être valide pour un et un seul schéma, mais {1} sont valides avec les index ''{2}'' -pattern = {0}: ne correspond pas au modèle d''expression régulière {1} -patternProperties = {0}: il y a une erreur avec les « propriétés du modèle » -prefixItems = {0}: aucun validateur trouvé à cet index -properties = {0}: il y a une erreur avec « propriétés » -propertyNames = {0}: le nom de la propriété ''{1}'' n''est pas valide : {2} -readOnly = {0}: est un champ en lecture seule, il ne peut pas être modifié -required = {0}: propriété requise ''{1}'' introuvable -type = {0}: {1} trouvé, {2} attendu -unevaluatedItems = {0}: l''index ''{1}'' n''est pas évalué et le schéma n''autorise pas les éléments non évalués -unevaluatedProperties = {0}: la propriété ''{1}'' n''est pas évaluée et le schéma n''autorise pas les propriétés non évaluées -unionType = {0}: {1} trouvé, {2} attendu -uniqueItems = {0}: ne doit avoir que des éléments uniques dans le tableau -writeOnly = {0}: est un champ en écriture seule, il ne peut pas apparaître dans les données -contentEncoding = {0}: ne correspond pas à l''encodage du contenu {1} -contentMediaType = {0}: n''est pas un contenu moi +$ref = il y a une erreur avec ''refs'' +additionalItems = l''index ''{0}'' n''est pas défini dans le schéma et le schéma n''autorise pas les éléments supplémentaires +additionalProperties = la propriété ''{0}'' n''est pas définie dans le schéma et le schéma n''autorise pas de propriétés supplémentaires +allOf = doit être valide pour tous les schémas {0} +anyOf = doit être valide pour l''un des schémas {0} +const = doit être la valeur constante ''{0}'' +contains = ne contient aucun élément qui réussit ces validations : {1} +contains.max = doit contenir au plus {0} élément(s) qui réussissent ces validations : {1} +contains.min = doit contenir au moins {0} élément(s) qui réussissent ces validations : {1} +dependencies = il y a une erreur avec les dépendances {0} +dependentRequired = a une propriété manquante « {0} » qui est dépendante requise car « {1} » est présente +dependentSchemas = il y a une erreur avecdependentSchemas {0} +enum = n''a pas de valeur dans l''énumération {0} +exclusiveMaximum = doit avoir une valeur maximale exclusive de {0} +exclusiveMinimum = doit avoir une valeur minimale exclusive de {0} +false = le schéma de ''{0}'' est faux +format = ne correspond pas au modèle {0} +format.date = ne correspond pas au modèle {0} doit être une date complète RFC 3339 valide +format.date-time = ne correspond pas au modèle {0} doit être une date-heure RFC 3339 valide +format.duration = ne correspond pas au modèle {0} doit être une durée ISO 8601 valide +format.email = ne correspond pas au modèle {0} doit être une boîte aux lettres RFC 5321 valide +format.ipv4 = ne correspond pas au modèle {0} doit être une adresse IP RFC 2673 valide +format.ipv6 = ne correspond pas au modèle {0} doit être une adresse IP RFC 4291 valide +format.idn-email = ne correspond pas au modèle {0} doit être une boîte aux lettres RFC 6531 valide +format.idn-hostname = ne correspond pas au modèle {0} doit être un nom d''hôte internationalisé RFC 5890 valide +format.iri = ne correspond pas au modèle {0} doit être un IRI RFC 3987 valide +format.iri-reference = ne correspond pas au modèle {0} doit être une référence IRI RFC 3987 valide +format.uri = ne correspond pas au modèle {0} doit être un URI RFC 3986 valide +format.uri-reference = ne correspond pas au modèle {0} doit être une référence URI RFC 3986 valide +format.uri-template = ne correspond pas au modèle {0} doit être un modèle d''URI RFC 6570 valide +format.uuid = ne correspond pas au modèle {0} doit être un UUID RFC 4122 valide +format.regex = ne correspond pas au modèle {0} doit être une expression régulière ECMA-262 valide +format.time = ne correspond pas au modèle {0} doit être une heure RFC 3339 valide +format.hostname = ne correspond pas au modèle {0} doit être un nom d''hôte RFC 1123 valide +format.json-pointer = ne correspond pas au modèle {0} doit être un pointeur JSON RFC 6901 valide +format.relative-json-pointer = ne correspond pas au modèle {0} doit être un pointeur JSON relatif IETF valide +format.unknown = a un format inconnu ''{0}'' +id = ''{0}'' n''est pas un {1} valide +items = l''index ''{0}'' n''est pas défini dans le schéma et le schéma n''autorise pas d''éléments supplémentaires +maxContains = doit être un entier non négatif dans {0} +maxItems = doit contenir au plus {0} éléments mais trouvé {1} +maxLength = doit contenir au plus {0} caractères +maxProperties = doit avoir au plus {0} propriétés +maximum = doit avoir une valeur maximale de {0} +minContains = doit être un entier non négatif dans {0} +minContainsVsMaxContains = minContains doit être inférieur ou égal à maxContains dans {0} +minItems = doit avoir au moins {0} éléments mais trouvé {1} +minLength = doit contenir au moins {0} caractères +minProperties = doit avoir au moins {0} propriétés +minimum = doit avoir une valeur minimale de {0} +multipleOf = doit être un multiple de {0} +not = ne doit pas être valide pour le schéma {0} +notAllowed = la propriété ''{0}'' n''est pas autorisée mais elle est dans les données +oneOf = doit être valide pour un et un seul schéma, mais {0} sont valides +oneOf.indexes = doit être valide pour un et un seul schéma, mais {0} sont valides avec les index ''{1}'' +pattern = ne correspond pas au modèle d''expression régulière {0} +patternProperties = il y a une erreur avec les « propriétés du modèle » +prefixItems = aucun validateur trouvé à cet index +properties = il y a une erreur avec « propriétés » +propertyNames = le nom de la propriété ''{0}'' n''est pas valide : {1} +readOnly = est un champ en lecture seule, il ne peut pas être modifié +required = propriété requise ''{0}'' introuvable +type = {0} trouvé, {1} attendu +unevaluatedItems = l''index ''{0}'' n''est pas évalué et le schéma n''autorise pas les éléments non évalués +unevaluatedProperties = la propriété ''{0}'' n''est pas évaluée et le schéma n''autorise pas les propriétés non évaluées +unionType = {0} trouvé, {1} attendu +uniqueItems = ne doit avoir que des éléments uniques dans le tableau +writeOnly = est un champ en écriture seule, il ne peut pas apparaître dans les données +contentEncoding = ne correspond pas à l''encodage du contenu {0} +contentMediaType = n''est pas un contenu moi diff --git a/src/main/resources/jsv-messages_he.properties b/src/main/resources/jsv-messages_he.properties index d33a29473..4626eced6 100644 --- a/src/main/resources/jsv-messages_he.properties +++ b/src/main/resources/jsv-messages_he.properties @@ -1,70 +1,70 @@ -$ref = {0}: \u05D9\u05E9 \u05E9\u05D2\u05D9\u05D0\u05D4 \u05E2\u05DD ''refs'' -additionalItems = {0}: \u05D0\u05D9\u05E0\u05D3\u05E7\u05E1 ''{1}'' \u05D0\u05D9\u05E0\u05D5 \u05DE\u05D5\u05D2\u05D3\u05E8 \u05D1\u05E1\u05DB\u05D9\u05DE\u05D4 \u05D5\u05D4\u05E1\u05DB\u05D9\u05DE\u05D4 \u05D0\u05D9\u05E0\u05D4 \u05DE\u05D0\u05E4\u05E9\u05E8\u05EA \u05E4\u05E8\u05D9\u05D8\u05D9\u05DD \u05E0\u05D5\u05E1\u05E4\u05D9\u05DD -additionalProperties = {0}: \u05D4\u05DE\u05D0\u05E4\u05D9\u05D9\u05DF ''{1}'' \u05D0\u05D9\u05E0\u05D5 \u05DE\u05D5\u05D2\u05D3\u05E8 \u05D1\u05E1\u05DB\u05D9\u05DE\u05D4 \u05D5\u05D4\u05E1\u05DB\u05D9\u05DE\u05D4 \u05D0\u05D9\u05E0\u05D4 \u05DE\u05D0\u05E4\u05E9\u05E8\u05EA \u05DE\u05D0\u05E4\u05D9\u05D9\u05E0\u05D9\u05DD \u05E0\u05D5\u05E1\u05E4\u05D9\u05DD -allOf = {0}: \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05D7\u05D5\u05E7\u05D9 \u05DC\u05DB\u05DC \u05D4\u05E1\u05DB\u05DE\u05D5\u05EA {1} -anyOf = {0}: \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05D7\u05D5\u05E7\u05D9 \u05DC\u05DB\u05DC \u05D0\u05D7\u05EA \u05DE\u05D4\u05E1\u05DB\u05D9\u05DE\u05D5\u05EA {1} -const = {0}: \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05D4\u05E2\u05E8\u05DA \u05D4\u05E7\u05D1\u05D5\u05E2 ''{1}'' -contains = {0}: \u05D0\u05D9\u05E0\u05D5 \u05DE\u05DB\u05D9\u05DC \u05E8\u05DB\u05D9\u05D1 \u05E9\u05E2\u05D5\u05D1\u05E8 \u05D0\u05EA \u05D4\u05D0\u05D9\u05DE\u05D5\u05EA\u05D9\u05DD \u05D4\u05D1\u05D0\u05D9\u05DD: {2} -contains.max = {0}: \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05DB\u05D9\u05DC \u05DC\u05DB\u05DC \u05D4\u05D9\u05D5\u05EA\u05E8 {1} \u05E8\u05DB\u05D9\u05D1\u05D9\u05DD \u05E9\u05E2\u05D5\u05D1\u05E8\u05D9\u05DD \u05D0\u05D9\u05DE\u05D5\u05EA\u05D9\u05DD \u05D0\u05DC\u05D4: {2} -contains.min = {0}: \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05DB\u05D9\u05DC \u05DC\u05E4\u05D7\u05D5\u05EA {1} \u05E8\u05DB\u05D9\u05D1\u05D9\u05DD \u05E9\u05E2\u05D5\u05D1\u05E8\u05D9\u05DD \u05D0\u05D9\u05DE\u05D5\u05EA\u05D9\u05DD \u05D0\u05DC\u05D4: {2} -dependencies = {0}: \u05D9\u05E9 \u05E9\u05D2\u05D9\u05D0\u05D4 \u05E2\u05DD \u05EA\u05DC\u05D5\u05D9\u05D5\u05EA {1} -dependentRequired = {0}: \u05D7\u05E1\u05E8 \u05DE\u05D0\u05E4\u05D9\u05D9\u05DF ''{1}'' \u05D0\u05E9\u05E8 \u05D3\u05E8\u05D5\u05E9 \u05EA\u05DC\u05D5\u05D9 \u05DB\u05D9 ''{2}'' \u05E7\u05D9\u05D9\u05DD -dependentSchemas = {0}: \u05D9\u05E9 \u05E9\u05D2\u05D9\u05D0\u05D4 \u05E2\u05DD dependentSchemas {1} -enum = {0}: \u05D0\u05D9\u05DF \u05E2\u05E8\u05DA \u05D1\u05E1\u05E4\u05D9\u05E8\u05D4 {1} -exclusiveMaximum = {0}: \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05D1\u05E2\u05DC \u05E2\u05E8\u05DA \u05DE\u05E7\u05E1\u05D9\u05DE\u05DC\u05D9 \u05D1\u05DC\u05E2\u05D3\u05D9 \u05E9\u05DC {1} -exclusiveMinimum = {0}: \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05D1\u05E2\u05DC \u05E2\u05E8\u05DA \u05DE\u05D9\u05E0\u05D9\u05DE\u05DC\u05D9 \u05D1\u05DC\u05E2\u05D3\u05D9 \u05E9\u05DC {1} -false = {0}: \u05D4\u05E1\u05DB\u05D9\u05DE\u05D4 \u05E2\u05D1\u05D5\u05E8 ''{1}'' \u05D4\u05D9\u05D0 \u05E9\u05E7\u05E8 -format = {0}: \u05D0\u05D9\u05E0\u05D5 \u05EA\u05D5\u05D0\u05DD \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA {1} {2} -format.date = {0}: \u05D0\u05D9\u05E0\u05D5 \u05EA\u05D5\u05D0\u05DD \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA {1} \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05EA\u05D0\u05E8\u05D9\u05DA \u05DE\u05DC\u05D0 RFC 3339 \u05D7\u05D5\u05E7\u05D9 -format.date-time = {0}: \u05D0\u05D9\u05E0\u05D5 \u05EA\u05D5\u05D0\u05DD \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA {1} \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA RFC 3339 \u05EA\u05D0\u05E8\u05D9\u05DA-\u05E9\u05E2\u05D4 \u05D7\u05D5\u05E7\u05D9 -format.duration = {0}: \u05D0\u05D9\u05E0\u05D5 \u05EA\u05D5\u05D0\u05DD \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA {1} \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05DE\u05E9\u05DA ISO 8601 \u05D7\u05D5\u05E7\u05D9 -format.email = {0}: \u05D0\u05D9\u05E0\u05D5 \u05EA\u05D5\u05D0\u05DD \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA {1} \u05D7\u05D9\u05D9\u05D1\u05EA \u05DC\u05D4\u05D9\u05D5\u05EA \u05EA\u05D9\u05D1\u05EA \u05D3\u05D5\u05D0\u05E8 RFC 5321 \u05D7\u05D5\u05E7\u05D9\u05EA -format.ipv4 = {0}: \u05D0\u05D9\u05E0\u05D5 \u05EA\u05D5\u05D0\u05DD \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA {1} \u05D7\u05D9\u05D9\u05D1\u05EA \u05DC\u05D4\u05D9\u05D5\u05EA \u05DB\u05EA\u05D5\u05D1\u05EA IP \u05D7\u05D5\u05E7\u05D9\u05EA \u05E9\u05DC RFC 2673 -format.ipv6 = {0}: \u05D0\u05D9\u05E0\u05D5 \u05EA\u05D5\u05D0\u05DD \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA {1} \u05D7\u05D9\u05D9\u05D1\u05EA \u05DC\u05D4\u05D9\u05D5\u05EA \u05DB\u05EA\u05D5\u05D1\u05EA IP \u05D7\u05D5\u05E7\u05D9\u05EA \u05E9\u05DC RFC 4291 -format.idn-email = {0}: \u05D0\u05D9\u05E0\u05D5 \u05EA\u05D5\u05D0\u05DD \u05DC\u05D3\u05E4\u05D5\u05E1 {1} \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05EA\u05D9\u05D1\u05EA \u05D3\u05D5\u05D0\u05E8 RFC 6531 \u05D7\u05D5\u05E7\u05D9\u05EA -format.idn-hostname = {0}: \u05D0\u05D9\u05E0\u05D5 \u05EA\u05D5\u05D0\u05DD \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA {1} \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05E9\u05DD \u05DE\u05D0\u05E8\u05D7 \u05D7\u05D5\u05E7\u05D9 RFC 5890 \u05D1\u05D9\u05E0\u05DC\u05D0\u05D5\u05DE\u05D9 -format.iri = {0}: \u05D0\u05D9\u05E0\u05D5 \u05EA\u05D5\u05D0\u05DD \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA {1} \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA RFC 3987 IRI \u05D7\u05D5\u05E7\u05D9 -format.iri-reference = {0}: \u05D0\u05D9\u05E0\u05D5 \u05EA\u05D5\u05D0\u05DD \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA {1} \u05D7\u05D9\u05D9\u05D1\u05EA \u05DC\u05D4\u05D9\u05D5\u05EA \u05D4\u05E4\u05E0\u05D9\u05D4 \u05D7\u05D5\u05E7\u05D9\u05EA \u05E9\u05DC RFC 3987 IRI -format.uri = {0}: \u05D0\u05D9\u05E0\u05D5 \u05EA\u05D5\u05D0\u05DD \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA {1} \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA RFC 3986 URI \u05D7\u05D5\u05E7\u05D9 -format.uri-reference = {0}: \u05D0\u05D9\u05E0\u05D5 \u05EA\u05D5\u05D0\u05DD \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA {1} \u05D7\u05D9\u05D9\u05D1\u05EA \u05DC\u05D4\u05D9\u05D5\u05EA \u05D4\u05E4\u05E0\u05D9\u05D4 \u05D7\u05D5\u05E7\u05D9\u05EA \u05E9\u05DC RFC 3986 URI -format.uri-template = {0}: \u05D0\u05D9\u05E0\u05D5 \u05EA\u05D5\u05D0\u05DD \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA {1} \u05D7\u05D9\u05D9\u05D1\u05EA \u05DC\u05D4\u05D9\u05D5\u05EA \u05EA\u05D1\u05E0\u05D9\u05EA URI \u05D7\u05D5\u05E7\u05D9\u05EA \u05E9\u05DC RFC 6570 -format.uuid = {0}: \u05D0\u05D9\u05E0\u05D5 \u05EA\u05D5\u05D0\u05DD \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA {1} \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA RFC 4122 UUID \u05D7\u05D5\u05E7\u05D9 -format.regex = {0}: \u05D0\u05D9\u05E0\u05D5 \u05EA\u05D5\u05D0\u05DD \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA {1} \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05D1\u05D9\u05D8\u05D5\u05D9 \u05E8\u05D2\u05D5\u05DC\u05E8\u05D9 \u05D7\u05D5\u05E7\u05D9 ECMA-262 -format.time = {0}: \u05D0\u05D9\u05E0\u05D5 \u05EA\u05D5\u05D0\u05DD \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA {1} \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05D6\u05DE\u05DF RFC 3339 \u05D7\u05D5\u05E7\u05D9 -format.hostname = {0}: \u05D0\u05D9\u05E0\u05D5 \u05EA\u05D5\u05D0\u05DD \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA {1} \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05E9\u05DD \u05DE\u05D0\u05E8\u05D7 RFC 1123 \u05D7\u05D5\u05E7\u05D9 -format.json-pointer = {0}: \u05D0\u05D9\u05E0\u05D5 \u05EA\u05D5\u05D0\u05DD \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA {1} \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05DE\u05E6\u05D1\u05D9\u05E2 RFC 6901 JSON \u05D7\u05D5\u05E7\u05D9 -format.relative-json-pointer = {0}: \u05D0\u05D9\u05E0\u05D5 \u05EA\u05D5\u05D0\u05DD \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA {1} \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05DE\u05E6\u05D1\u05D9\u05E2 JSON \u05D9\u05D7\u05E1\u05D9 \u05E9\u05DC IETF \u05D7\u05D5\u05E7\u05D9 -format.unknown = {0}: \u05D9\u05E9 \u05E4\u05D5\u05E8\u05DE\u05D8 \u05DC\u05D0 \u05D9\u05D3\u05D5\u05E2 ''{1}'' -id = {0}: ''{1}'' \u05D0\u05D9\u05E0\u05D5 {2} \u05D7\u05D5\u05E7\u05D9 -items = {0}: \u05D0\u05D9\u05E0\u05D3\u05E7\u05E1 ''{1}'' \u05D0\u05D9\u05E0\u05D5 \u05DE\u05D5\u05D2\u05D3\u05E8 \u05D1\u05E1\u05DB\u05D9\u05DE\u05D4 \u05D5\u05D4\u05E1\u05DB\u05D9\u05DE\u05D4 \u05D0\u05D9\u05E0\u05D4 \u05DE\u05D0\u05E4\u05E9\u05E8\u05EA \u05E4\u05E8\u05D9\u05D8\u05D9\u05DD \u05E0\u05D5\u05E1\u05E4\u05D9\u05DD -maxContains = {0}: \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05DE\u05E1\u05E4\u05E8 \u05E9\u05DC\u05DD \u05DC\u05D0 \u05E9\u05DC\u05D9\u05DC\u05D9 \u05D1-{1} -maxItems = {0}: \u05D7\u05D9\u05D9\u05D1 \u05DC\u05DB\u05DC\u05D5\u05DC \u05DC\u05DB\u05DC \u05D4\u05D9\u05D5\u05EA\u05E8 {1} \u05E4\u05E8\u05D9\u05D8\u05D9\u05DD \u05D0\u05DA \u05E0\u05DE\u05E6\u05D0\u05D5 {2} -maxLength = {0}: \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05D1\u05D0\u05D5\u05E8\u05DA \u05E9\u05DC {1} \u05EA\u05D5\u05D5\u05D9\u05DD \u05DC\u05DB\u05DC \u05D4\u05D9\u05D5\u05EA\u05E8 -maxProperties = {0}: \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05DC\u05DB\u05DC \u05D4\u05D9\u05D5\u05EA\u05E8 {1} \u05DE\u05D0\u05E4\u05D9\u05D9\u05E0\u05D9\u05DD -maximum = {0}: \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05D1\u05E2\u05DC \u05E2\u05E8\u05DA \u05DE\u05E7\u05E1\u05D9\u05DE\u05DC\u05D9 \u05E9\u05DC {1} -minContains = {0}: \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05DE\u05E1\u05E4\u05E8 \u05E9\u05DC\u05DD \u05DC\u05D0 \u05E9\u05DC\u05D9\u05DC\u05D9 \u05D1-{1} -minContainsVsMaxContains = {0}: minContains \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05E7\u05D8\u05DF \u05D0\u05D5 \u05E9\u05D5\u05D5\u05D4 \u05DC-maxContains \u05D1-{1} -minItems = {0}: \u05D7\u05D9\u05D9\u05D1 \u05DC\u05DB\u05DC\u05D5\u05DC \u05DC\u05E4\u05D7\u05D5\u05EA {1} \u05E4\u05E8\u05D9\u05D8\u05D9\u05DD \u05D0\u05DA \u05E0\u05DE\u05E6\u05D0\u05D5 {2} -minLength = {0}: \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05D1\u05D0\u05D5\u05E8\u05DA \u05E9\u05DC \u05DC\u05E4\u05D7\u05D5\u05EA {1} \u05EA\u05D5\u05D5\u05D9\u05DD -minProperties = {0}: \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05DC\u05E4\u05D7\u05D5\u05EA {1} \u05DE\u05D0\u05E4\u05D9\u05D9\u05E0\u05D9\u05DD -minimum = {0}: \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05D1\u05E2\u05DC \u05E2\u05E8\u05DA \u05DE\u05D9\u05E0\u05D9\u05DE\u05DC\u05D9 \u05E9\u05DC {1} -multipleOf = {0}: \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05DB\u05E4\u05D5\u05DC\u05D4 \u05E9\u05DC {1} -not = {0}: \u05DC\u05D0 \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05D7\u05D5\u05E7\u05D9 \u05DC\u05E1\u05DB\u05D9\u05DE\u05D4 {1} -notAllowed = {0}: \u05D4\u05DE\u05D0\u05E4\u05D9\u05D9\u05DF ''{1}'' \u05D0\u05D9\u05E0\u05D5 \u05DE\u05D5\u05EA\u05E8 \u05D0\u05DA \u05D4\u05D5\u05D0 \u05E0\u05DE\u05E6\u05D0 \u05D1\u05E0\u05EA\u05D5\u05E0\u05D9\u05DD -oneOf = {0}: \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05D7\u05D5\u05E7\u05D9 \u05DC\u05E1\u05DB\u05D9\u05DE\u05D4 \u05D0\u05D7\u05EA \u05D5\u05D9\u05D7\u05D9\u05D3\u05D4, \u05D0\u05D1\u05DC {1} \u05D7\u05D5\u05E7\u05D9\u05D9\u05DD -oneOf.indexes = {0}: \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05D7\u05D5\u05E7\u05D9 \u05DC\u05E1\u05DB\u05D9\u05DE\u05D4 \u05D0\u05D7\u05EA \u05D5\u05D9\u05D7\u05D9\u05D3\u05D4, \u05D0\u05D1\u05DC {1} \u05EA\u05E7\u05E4\u05D9\u05DD \u05E2\u05DD \u05D4\u05D0\u05D9\u05E0\u05D3\u05E7\u05E1\u05D9\u05DD ''{2}'' -pattern = {0}: \u05D0\u05D9\u05E0\u05D5 \u05EA\u05D5\u05D0\u05DD \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA \u05D4\u05D1\u05D9\u05D8\u05D5\u05D9 \u05D4\u05E8\u05D2\u05D5\u05DC\u05E8\u05D9 {1} -patternProperties = {0}: \u05D9\u05E9 \u05E9\u05D2\u05D9\u05D0\u05D4 \u05DB\u05DC\u05E9\u05D4\u05D9 \u05E2\u05DD ''\u05DE\u05D0\u05E4\u05D9\u05D9\u05E0\u05D9 \u05D3\u05E4\u05D5\u05E1'' -prefixItems = {0}: \u05DC\u05D0 \u05E0\u05DE\u05E6\u05D0 \u05DE\u05D0\u05DE\u05EA \u05D1\u05D0\u05D9\u05E0\u05D3\u05E7\u05E1 \u05D6\u05D4 -properties = {0}: \u05D9\u05E9 \u05E9\u05D2\u05D9\u05D0\u05D4 \u05E2\u05DD ''\u05DE\u05D0\u05E4\u05D9\u05D9\u05E0\u05D9\u05DD'' -propertyNames = {0}: \u05E9\u05DD \u05D4\u05E0\u05DB\u05E1 ''{1}'' \u05D0\u05D9\u05E0\u05D5 \u05D7\u05D5\u05E7\u05D9: {2} -readOnly = {0}: \u05D4\u05D5\u05D0 \u05E9\u05D3\u05D4 \u05DC\u05E7\u05E8\u05D9\u05D0\u05D4 \u05D1\u05DC\u05D1\u05D3, \u05DC\u05D0 \u05E0\u05D9\u05EA\u05DF \u05DC\u05E9\u05E0\u05D5\u05EA \u05D0\u05D5\u05EA\u05D5 -required = {0}: \u05D4\u05DE\u05D0\u05E4\u05D9\u05D9\u05DF \u05D4\u05E0\u05D3\u05E8\u05E9 ''{1}'' \u05DC\u05D0 \u05E0\u05DE\u05E6\u05D0 -type = {0}: {1} \u05E0\u05DE\u05E6\u05D0, {2} \u05E6\u05E4\u05D5\u05D9 -unevaluatedItems = {0}: \u05D4\u05D0\u05D9\u05E0\u05D3\u05E7\u05E1 ''{1}'' \u05D0\u05D9\u05E0\u05D5 \u05DE\u05D5\u05E2\u05E8\u05DA \u05D5\u05D4\u05E1\u05DB\u05D9\u05DE\u05D4 \u05D0\u05D9\u05E0\u05D4 \u05DE\u05D0\u05E4\u05E9\u05E8\u05EA \u05E4\u05E8\u05D9\u05D8\u05D9\u05DD \u05DC\u05DC\u05D0 \u05D4\u05E2\u05E8\u05DB\u05D4 -unevaluatedProperties = {0}: \u05D4\u05DE\u05D0\u05E4\u05D9\u05D9\u05DF ''{1}'' \u05D0\u05D9\u05E0\u05D5 \u05DE\u05D5\u05E2\u05E8\u05DA \u05D5\u05D4\u05E1\u05DB\u05D9\u05DE\u05D4 \u05D0\u05D9\u05E0\u05D4 \u05DE\u05D0\u05E4\u05E9\u05E8\u05EA \u05DE\u05D0\u05E4\u05D9\u05D9\u05E0\u05D9\u05DD \u05DC\u05DC\u05D0 \u05D4\u05E2\u05E8\u05DB\u05D4 -unionType = {0}: {1} \u05E0\u05DE\u05E6\u05D0, {2} \u05E6\u05E4\u05D5\u05D9 -uniqueItems = {0}: \u05D7\u05D9\u05D9\u05D1\u05D9\u05DD \u05DC\u05DB\u05DC\u05D5\u05DC \u05E8\u05E7 \u05E4\u05E8\u05D9\u05D8\u05D9\u05DD \u05D9\u05D9\u05D7\u05D5\u05D3\u05D9\u05D9\u05DD \u05D1\u05DE\u05E2\u05E8\u05DA -writeOnly = {0}: \u05D4\u05D5\u05D0 \u05E9\u05D3\u05D4 \u05DC\u05DB\u05EA\u05D9\u05D1\u05D4 \u05D1\u05DC\u05D1\u05D3, \u05D4\u05D5\u05D0 \u05DC\u05D0 \u05D9\u05DB\u05D5\u05DC \u05DC\u05D4\u05D5\u05E4\u05D9\u05E2 \u05D1\u05E0\u05EA\u05D5\u05E0\u05D9\u05DD -contentEncoding = {0}: \u05D0\u05D9\u05E0\u05D5 \u05EA\u05D5\u05D0\u05DD \u05D0\u05EA \u05E7\u05D9\u05D3\u05D5\u05D3 \u05D4\u05EA\u05D5\u05DB\u05DF {1} -contentMediaType = {0}: \u05D0\u05D9\u05E0\u05D5 \u05EA\u05D5\u05DB\u05DF \u05D0\u05E0\u05D9 +$ref = \u05D9\u05E9 \u05E9\u05D2\u05D9\u05D0\u05D4 \u05E2\u05DD ''refs'' +additionalItems = \u05D0\u05D9\u05E0\u05D3\u05E7\u05E1 ''{0}'' \u05D0\u05D9\u05E0\u05D5 \u05DE\u05D5\u05D2\u05D3\u05E8 \u05D1\u05E1\u05DB\u05D9\u05DE\u05D4 \u05D5\u05D4\u05E1\u05DB\u05D9\u05DE\u05D4 \u05D0\u05D9\u05E0\u05D4 \u05DE\u05D0\u05E4\u05E9\u05E8\u05EA \u05E4\u05E8\u05D9\u05D8\u05D9\u05DD \u05E0\u05D5\u05E1\u05E4\u05D9\u05DD +additionalProperties = \u05D4\u05DE\u05D0\u05E4\u05D9\u05D9\u05DF ''{0}'' \u05D0\u05D9\u05E0\u05D5 \u05DE\u05D5\u05D2\u05D3\u05E8 \u05D1\u05E1\u05DB\u05D9\u05DE\u05D4 \u05D5\u05D4\u05E1\u05DB\u05D9\u05DE\u05D4 \u05D0\u05D9\u05E0\u05D4 \u05DE\u05D0\u05E4\u05E9\u05E8\u05EA \u05DE\u05D0\u05E4\u05D9\u05D9\u05E0\u05D9\u05DD \u05E0\u05D5\u05E1\u05E4\u05D9\u05DD +allOf = \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05D7\u05D5\u05E7\u05D9 \u05DC\u05DB\u05DC \u05D4\u05E1\u05DB\u05DE\u05D5\u05EA {0} +anyOf = \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05D7\u05D5\u05E7\u05D9 \u05DC\u05DB\u05DC \u05D0\u05D7\u05EA \u05DE\u05D4\u05E1\u05DB\u05D9\u05DE\u05D5\u05EA {0} +const = \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05D4\u05E2\u05E8\u05DA \u05D4\u05E7\u05D1\u05D5\u05E2 ''{0}'' +contains = \u05D0\u05D9\u05E0\u05D5 \u05DE\u05DB\u05D9\u05DC \u05E8\u05DB\u05D9\u05D1 \u05E9\u05E2\u05D5\u05D1\u05E8 \u05D0\u05EA \u05D4\u05D0\u05D9\u05DE\u05D5\u05EA\u05D9\u05DD \u05D4\u05D1\u05D0\u05D9\u05DD: {1} +contains.max = \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05DB\u05D9\u05DC \u05DC\u05DB\u05DC \u05D4\u05D9\u05D5\u05EA\u05E8 {0} \u05E8\u05DB\u05D9\u05D1\u05D9\u05DD \u05E9\u05E2\u05D5\u05D1\u05E8\u05D9\u05DD \u05D0\u05D9\u05DE\u05D5\u05EA\u05D9\u05DD \u05D0\u05DC\u05D4: {1} +contains.min = \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05DB\u05D9\u05DC \u05DC\u05E4\u05D7\u05D5\u05EA {0} \u05E8\u05DB\u05D9\u05D1\u05D9\u05DD \u05E9\u05E2\u05D5\u05D1\u05E8\u05D9\u05DD \u05D0\u05D9\u05DE\u05D5\u05EA\u05D9\u05DD \u05D0\u05DC\u05D4: {1} +dependencies = \u05D9\u05E9 \u05E9\u05D2\u05D9\u05D0\u05D4 \u05E2\u05DD \u05EA\u05DC\u05D5\u05D9\u05D5\u05EA {0} +dependentRequired = \u05D7\u05E1\u05E8 \u05DE\u05D0\u05E4\u05D9\u05D9\u05DF ''{0}'' \u05D0\u05E9\u05E8 \u05D3\u05E8\u05D5\u05E9 \u05EA\u05DC\u05D5\u05D9 \u05DB\u05D9 ''{1}'' \u05E7\u05D9\u05D9\u05DD +dependentSchemas = \u05D9\u05E9 \u05E9\u05D2\u05D9\u05D0\u05D4 \u05E2\u05DD dependentSchemas {0} +enum = \u05D0\u05D9\u05DF \u05E2\u05E8\u05DA \u05D1\u05E1\u05E4\u05D9\u05E8\u05D4 {0} +exclusiveMaximum = \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05D1\u05E2\u05DC \u05E2\u05E8\u05DA \u05DE\u05E7\u05E1\u05D9\u05DE\u05DC\u05D9 \u05D1\u05DC\u05E2\u05D3\u05D9 \u05E9\u05DC {0} +exclusiveMinimum = \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05D1\u05E2\u05DC \u05E2\u05E8\u05DA \u05DE\u05D9\u05E0\u05D9\u05DE\u05DC\u05D9 \u05D1\u05DC\u05E2\u05D3\u05D9 \u05E9\u05DC {0} +false = \u05D4\u05E1\u05DB\u05D9\u05DE\u05D4 \u05E2\u05D1\u05D5\u05E8 ''{0}'' \u05D4\u05D9\u05D0 \u05E9\u05E7\u05E8 +format = \u05D0\u05D9\u05E0\u05D5 \u05EA\u05D5\u05D0\u05DD \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA {0} +format.date = \u05D0\u05D9\u05E0\u05D5 \u05EA\u05D5\u05D0\u05DD \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA {0} \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05EA\u05D0\u05E8\u05D9\u05DA \u05DE\u05DC\u05D0 RFC 3339 \u05D7\u05D5\u05E7\u05D9 +format.date-time = \u05D0\u05D9\u05E0\u05D5 \u05EA\u05D5\u05D0\u05DD \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA {0} \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA RFC 3339 \u05EA\u05D0\u05E8\u05D9\u05DA-\u05E9\u05E2\u05D4 \u05D7\u05D5\u05E7\u05D9 +format.duration = \u05D0\u05D9\u05E0\u05D5 \u05EA\u05D5\u05D0\u05DD \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA {0} \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05DE\u05E9\u05DA ISO 8601 \u05D7\u05D5\u05E7\u05D9 +format.email = \u05D0\u05D9\u05E0\u05D5 \u05EA\u05D5\u05D0\u05DD \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA {0} \u05D7\u05D9\u05D9\u05D1\u05EA \u05DC\u05D4\u05D9\u05D5\u05EA \u05EA\u05D9\u05D1\u05EA \u05D3\u05D5\u05D0\u05E8 RFC 5321 \u05D7\u05D5\u05E7\u05D9\u05EA +format.ipv4 = \u05D0\u05D9\u05E0\u05D5 \u05EA\u05D5\u05D0\u05DD \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA {0} \u05D7\u05D9\u05D9\u05D1\u05EA \u05DC\u05D4\u05D9\u05D5\u05EA \u05DB\u05EA\u05D5\u05D1\u05EA IP \u05D7\u05D5\u05E7\u05D9\u05EA \u05E9\u05DC RFC 2673 +format.ipv6 = \u05D0\u05D9\u05E0\u05D5 \u05EA\u05D5\u05D0\u05DD \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA {0} \u05D7\u05D9\u05D9\u05D1\u05EA \u05DC\u05D4\u05D9\u05D5\u05EA \u05DB\u05EA\u05D5\u05D1\u05EA IP \u05D7\u05D5\u05E7\u05D9\u05EA \u05E9\u05DC RFC 4291 +format.idn-email = \u05D0\u05D9\u05E0\u05D5 \u05EA\u05D5\u05D0\u05DD \u05DC\u05D3\u05E4\u05D5\u05E1 {0} \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05EA\u05D9\u05D1\u05EA \u05D3\u05D5\u05D0\u05E8 RFC 6531 \u05D7\u05D5\u05E7\u05D9\u05EA +format.idn-hostname = \u05D0\u05D9\u05E0\u05D5 \u05EA\u05D5\u05D0\u05DD \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA {0} \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05E9\u05DD \u05DE\u05D0\u05E8\u05D7 \u05D7\u05D5\u05E7\u05D9 RFC 5890 \u05D1\u05D9\u05E0\u05DC\u05D0\u05D5\u05DE\u05D9 +format.iri = \u05D0\u05D9\u05E0\u05D5 \u05EA\u05D5\u05D0\u05DD \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA {0} \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA RFC 3987 IRI \u05D7\u05D5\u05E7\u05D9 +format.iri-reference = \u05D0\u05D9\u05E0\u05D5 \u05EA\u05D5\u05D0\u05DD \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA {0} \u05D7\u05D9\u05D9\u05D1\u05EA \u05DC\u05D4\u05D9\u05D5\u05EA \u05D4\u05E4\u05E0\u05D9\u05D4 \u05D7\u05D5\u05E7\u05D9\u05EA \u05E9\u05DC RFC 3987 IRI +format.uri = \u05D0\u05D9\u05E0\u05D5 \u05EA\u05D5\u05D0\u05DD \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA {0} \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA RFC 3986 URI \u05D7\u05D5\u05E7\u05D9 +format.uri-reference = \u05D0\u05D9\u05E0\u05D5 \u05EA\u05D5\u05D0\u05DD \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA {0} \u05D7\u05D9\u05D9\u05D1\u05EA \u05DC\u05D4\u05D9\u05D5\u05EA \u05D4\u05E4\u05E0\u05D9\u05D4 \u05D7\u05D5\u05E7\u05D9\u05EA \u05E9\u05DC RFC 3986 URI +format.uri-template = \u05D0\u05D9\u05E0\u05D5 \u05EA\u05D5\u05D0\u05DD \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA {0} \u05D7\u05D9\u05D9\u05D1\u05EA \u05DC\u05D4\u05D9\u05D5\u05EA \u05EA\u05D1\u05E0\u05D9\u05EA URI \u05D7\u05D5\u05E7\u05D9\u05EA \u05E9\u05DC RFC 6570 +format.uuid = \u05D0\u05D9\u05E0\u05D5 \u05EA\u05D5\u05D0\u05DD \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA {0} \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA RFC 4122 UUID \u05D7\u05D5\u05E7\u05D9 +format.regex = \u05D0\u05D9\u05E0\u05D5 \u05EA\u05D5\u05D0\u05DD \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA {0} \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05D1\u05D9\u05D8\u05D5\u05D9 \u05E8\u05D2\u05D5\u05DC\u05E8\u05D9 \u05D7\u05D5\u05E7\u05D9 ECMA-262 +format.time = \u05D0\u05D9\u05E0\u05D5 \u05EA\u05D5\u05D0\u05DD \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA {0} \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05D6\u05DE\u05DF RFC 3339 \u05D7\u05D5\u05E7\u05D9 +format.hostname = \u05D0\u05D9\u05E0\u05D5 \u05EA\u05D5\u05D0\u05DD \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA {0} \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05E9\u05DD \u05DE\u05D0\u05E8\u05D7 RFC 1123 \u05D7\u05D5\u05E7\u05D9 +format.json-pointer = \u05D0\u05D9\u05E0\u05D5 \u05EA\u05D5\u05D0\u05DD \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA {0} \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05DE\u05E6\u05D1\u05D9\u05E2 RFC 6901 JSON \u05D7\u05D5\u05E7\u05D9 +format.relative-json-pointer = \u05D0\u05D9\u05E0\u05D5 \u05EA\u05D5\u05D0\u05DD \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA {0} \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05DE\u05E6\u05D1\u05D9\u05E2 JSON \u05D9\u05D7\u05E1\u05D9 \u05E9\u05DC IETF \u05D7\u05D5\u05E7\u05D9 +format.unknown = \u05D9\u05E9 \u05E4\u05D5\u05E8\u05DE\u05D8 \u05DC\u05D0 \u05D9\u05D3\u05D5\u05E2 ''{0}'' +id = ''{0}'' \u05D0\u05D9\u05E0\u05D5 {1} \u05D7\u05D5\u05E7\u05D9 +items = \u05D0\u05D9\u05E0\u05D3\u05E7\u05E1 ''{0}'' \u05D0\u05D9\u05E0\u05D5 \u05DE\u05D5\u05D2\u05D3\u05E8 \u05D1\u05E1\u05DB\u05D9\u05DE\u05D4 \u05D5\u05D4\u05E1\u05DB\u05D9\u05DE\u05D4 \u05D0\u05D9\u05E0\u05D4 \u05DE\u05D0\u05E4\u05E9\u05E8\u05EA \u05E4\u05E8\u05D9\u05D8\u05D9\u05DD \u05E0\u05D5\u05E1\u05E4\u05D9\u05DD +maxContains = \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05DE\u05E1\u05E4\u05E8 \u05E9\u05DC\u05DD \u05DC\u05D0 \u05E9\u05DC\u05D9\u05DC\u05D9 \u05D1-{0} +maxItems = \u05D7\u05D9\u05D9\u05D1 \u05DC\u05DB\u05DC\u05D5\u05DC \u05DC\u05DB\u05DC \u05D4\u05D9\u05D5\u05EA\u05E8 {0} \u05E4\u05E8\u05D9\u05D8\u05D9\u05DD \u05D0\u05DA \u05E0\u05DE\u05E6\u05D0\u05D5 {1} +maxLength = \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05D1\u05D0\u05D5\u05E8\u05DA \u05E9\u05DC {0} \u05EA\u05D5\u05D5\u05D9\u05DD \u05DC\u05DB\u05DC \u05D4\u05D9\u05D5\u05EA\u05E8 +maxProperties = \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05DC\u05DB\u05DC \u05D4\u05D9\u05D5\u05EA\u05E8 {0} \u05DE\u05D0\u05E4\u05D9\u05D9\u05E0\u05D9\u05DD +maximum = \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05D1\u05E2\u05DC \u05E2\u05E8\u05DA \u05DE\u05E7\u05E1\u05D9\u05DE\u05DC\u05D9 \u05E9\u05DC {0} +minContains = \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05DE\u05E1\u05E4\u05E8 \u05E9\u05DC\u05DD \u05DC\u05D0 \u05E9\u05DC\u05D9\u05DC\u05D9 \u05D1-{0} +minContainsVsMaxContains = minContains \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05E7\u05D8\u05DF \u05D0\u05D5 \u05E9\u05D5\u05D5\u05D4 \u05DC-maxContains \u05D1-{0} +minItems = \u05D7\u05D9\u05D9\u05D1 \u05DC\u05DB\u05DC\u05D5\u05DC \u05DC\u05E4\u05D7\u05D5\u05EA {0} \u05E4\u05E8\u05D9\u05D8\u05D9\u05DD \u05D0\u05DA \u05E0\u05DE\u05E6\u05D0\u05D5 {1} +minLength = \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05D1\u05D0\u05D5\u05E8\u05DA \u05E9\u05DC \u05DC\u05E4\u05D7\u05D5\u05EA {0} \u05EA\u05D5\u05D5\u05D9\u05DD +minProperties = \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05DC\u05E4\u05D7\u05D5\u05EA {0} \u05DE\u05D0\u05E4\u05D9\u05D9\u05E0\u05D9\u05DD +minimum = \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05D1\u05E2\u05DC \u05E2\u05E8\u05DA \u05DE\u05D9\u05E0\u05D9\u05DE\u05DC\u05D9 \u05E9\u05DC {0} +multipleOf = \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05DB\u05E4\u05D5\u05DC\u05D4 \u05E9\u05DC {0} +not = \u05DC\u05D0 \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05D7\u05D5\u05E7\u05D9 \u05DC\u05E1\u05DB\u05D9\u05DE\u05D4 {0} +notAllowed = \u05D4\u05DE\u05D0\u05E4\u05D9\u05D9\u05DF ''{0}'' \u05D0\u05D9\u05E0\u05D5 \u05DE\u05D5\u05EA\u05E8 \u05D0\u05DA \u05D4\u05D5\u05D0 \u05E0\u05DE\u05E6\u05D0 \u05D1\u05E0\u05EA\u05D5\u05E0\u05D9\u05DD +oneOf = \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05D7\u05D5\u05E7\u05D9 \u05DC\u05E1\u05DB\u05D9\u05DE\u05D4 \u05D0\u05D7\u05EA \u05D5\u05D9\u05D7\u05D9\u05D3\u05D4, \u05D0\u05D1\u05DC {0} \u05D7\u05D5\u05E7\u05D9\u05D9\u05DD +oneOf.indexes = \u05D7\u05D9\u05D9\u05D1 \u05DC\u05D4\u05D9\u05D5\u05EA \u05D7\u05D5\u05E7\u05D9 \u05DC\u05E1\u05DB\u05D9\u05DE\u05D4 \u05D0\u05D7\u05EA \u05D5\u05D9\u05D7\u05D9\u05D3\u05D4, \u05D0\u05D1\u05DC {0} \u05EA\u05E7\u05E4\u05D9\u05DD \u05E2\u05DD \u05D4\u05D0\u05D9\u05E0\u05D3\u05E7\u05E1\u05D9\u05DD ''{1}'' +pattern = \u05D0\u05D9\u05E0\u05D5 \u05EA\u05D5\u05D0\u05DD \u05DC\u05EA\u05D1\u05E0\u05D9\u05EA \u05D4\u05D1\u05D9\u05D8\u05D5\u05D9 \u05D4\u05E8\u05D2\u05D5\u05DC\u05E8\u05D9 {0} +patternProperties = \u05D9\u05E9 \u05E9\u05D2\u05D9\u05D0\u05D4 \u05DB\u05DC\u05E9\u05D4\u05D9 \u05E2\u05DD ''\u05DE\u05D0\u05E4\u05D9\u05D9\u05E0\u05D9 \u05D3\u05E4\u05D5\u05E1'' +prefixItems = \u05DC\u05D0 \u05E0\u05DE\u05E6\u05D0 \u05DE\u05D0\u05DE\u05EA \u05D1\u05D0\u05D9\u05E0\u05D3\u05E7\u05E1 \u05D6\u05D4 +properties = \u05D9\u05E9 \u05E9\u05D2\u05D9\u05D0\u05D4 \u05E2\u05DD ''\u05DE\u05D0\u05E4\u05D9\u05D9\u05E0\u05D9\u05DD'' +propertyNames = \u05E9\u05DD \u05D4\u05E0\u05DB\u05E1 ''{0}'' \u05D0\u05D9\u05E0\u05D5 \u05D7\u05D5\u05E7\u05D9: {1} +readOnly = \u05D4\u05D5\u05D0 \u05E9\u05D3\u05D4 \u05DC\u05E7\u05E8\u05D9\u05D0\u05D4 \u05D1\u05DC\u05D1\u05D3, \u05DC\u05D0 \u05E0\u05D9\u05EA\u05DF \u05DC\u05E9\u05E0\u05D5\u05EA \u05D0\u05D5\u05EA\u05D5 +required = \u05D4\u05DE\u05D0\u05E4\u05D9\u05D9\u05DF \u05D4\u05E0\u05D3\u05E8\u05E9 ''{0}'' \u05DC\u05D0 \u05E0\u05DE\u05E6\u05D0 +type = {0} \u05E0\u05DE\u05E6\u05D0, {1} \u05E6\u05E4\u05D5\u05D9 +unevaluatedItems = \u05D4\u05D0\u05D9\u05E0\u05D3\u05E7\u05E1 ''{0}'' \u05D0\u05D9\u05E0\u05D5 \u05DE\u05D5\u05E2\u05E8\u05DA \u05D5\u05D4\u05E1\u05DB\u05D9\u05DE\u05D4 \u05D0\u05D9\u05E0\u05D4 \u05DE\u05D0\u05E4\u05E9\u05E8\u05EA \u05E4\u05E8\u05D9\u05D8\u05D9\u05DD \u05DC\u05DC\u05D0 \u05D4\u05E2\u05E8\u05DB\u05D4 +unevaluatedProperties = \u05D4\u05DE\u05D0\u05E4\u05D9\u05D9\u05DF ''{0}'' \u05D0\u05D9\u05E0\u05D5 \u05DE\u05D5\u05E2\u05E8\u05DA \u05D5\u05D4\u05E1\u05DB\u05D9\u05DE\u05D4 \u05D0\u05D9\u05E0\u05D4 \u05DE\u05D0\u05E4\u05E9\u05E8\u05EA \u05DE\u05D0\u05E4\u05D9\u05D9\u05E0\u05D9\u05DD \u05DC\u05DC\u05D0 \u05D4\u05E2\u05E8\u05DB\u05D4 +unionType = {0} \u05E0\u05DE\u05E6\u05D0, {1} \u05E6\u05E4\u05D5\u05D9 +uniqueItems = \u05D7\u05D9\u05D9\u05D1\u05D9\u05DD \u05DC\u05DB\u05DC\u05D5\u05DC \u05E8\u05E7 \u05E4\u05E8\u05D9\u05D8\u05D9\u05DD \u05D9\u05D9\u05D7\u05D5\u05D3\u05D9\u05D9\u05DD \u05D1\u05DE\u05E2\u05E8\u05DA +writeOnly = \u05D4\u05D5\u05D0 \u05E9\u05D3\u05D4 \u05DC\u05DB\u05EA\u05D9\u05D1\u05D4 \u05D1\u05DC\u05D1\u05D3, \u05D4\u05D5\u05D0 \u05DC\u05D0 \u05D9\u05DB\u05D5\u05DC \u05DC\u05D4\u05D5\u05E4\u05D9\u05E2 \u05D1\u05E0\u05EA\u05D5\u05E0\u05D9\u05DD +contentEncoding = \u05D0\u05D9\u05E0\u05D5 \u05EA\u05D5\u05D0\u05DD \u05D0\u05EA \u05E7\u05D9\u05D3\u05D5\u05D3 \u05D4\u05EA\u05D5\u05DB\u05DF {0} +contentMediaType = \u05D0\u05D9\u05E0\u05D5 \u05EA\u05D5\u05DB\u05DF \u05D0\u05E0\u05D9 diff --git a/src/main/resources/jsv-messages_hr.properties b/src/main/resources/jsv-messages_hr.properties index ec55eac96..6b2060ef3 100644 --- a/src/main/resources/jsv-messages_hr.properties +++ b/src/main/resources/jsv-messages_hr.properties @@ -1,70 +1,70 @@ -$ref = {0}: ima gre\u0161ku s ''refs'' -additionalItems = {0}: indeks ''{1}'' nije definiran u shemi i shema ne dopu\u0161ta dodatne stavke -additionalProperties = {0}: svojstvo ''{1}'' nije definirano u shemi i shema ne dopu\u0161ta dodatna svojstva -allOf = {0}: mora biti va\u017Ee\u0107e za sve sheme {1} -anyOf = {0}: mora biti va\u017Ee\u0107e za bilo koju od shema {1} -const = {0}: mora biti konstantna vrijednost ''{1}'' -contains = {0}: ne sadr\u017Ei element koji prolazi ove provjere: {2} -contains.max = {0}: mora sadr\u017Eavati najvi\u0161e {1} elemenata koji prolaze ove provjere: {2} -contains.min = {0}: mora sadr\u017Eavati najmanje {1} elementa koji prolaze ove provjere: {2} -dependencies = {0}: ima pogre\u0161ku s ovisnostima {1} -dependentRequired = {0}: nedostaje svojstvo ''{1}'' koje je ovisno potrebno jer je prisutan ''{2}'' -dependentSchemas = {0}: ima pogre\u0161ku s dependentSchemas {1} -enum = {0}: nema vrijednost u enumeraciji {1} -exclusiveMaximum = {0}: mora imati isklju\u010Divu maksimalnu vrijednost od {1} -exclusiveMinimum = {0}: mora imati isklju\u010Divu minimalnu vrijednost od {1} -false = {0}: shema za ''{1}'' je false -format = {0}: ne odgovara {1} uzorku {2} -format.date = {0}: ne odgovara uzorku {1} mora biti va\u017Ee\u0107i puni datum RFC 3339 -format.date-time = {0}: ne odgovara uzorku {1} mora biti va\u017Ee\u0107i RFC 3339 datum-vrijeme -format.duration = {0}: ne odgovara uzorku {1} mora biti va\u017Ee\u0107e ISO 8601 trajanje -format.email = {0}: ne odgovara uzorku {1} mora biti va\u017Ee\u0107i po\u0161tanski sandu\u010Di\u0107 RFC 5321 -format.ipv4 = {0}: ne odgovara uzorku {1} mora biti va\u017Ee\u0107a RFC 2673 IP adresa -format.ipv6 = {0}: ne odgovara uzorku {1} mora biti va\u017Ee\u0107a RFC 4291 IP adresa -format.idn-email = {0}: ne odgovara uzorku {1} mora biti va\u017Ee\u0107i po\u0161tanski sandu\u010Di\u0107 RFC 6531 -format.idn-hostname = {0}: ne odgovara uzorku {1} mora biti va\u017Ee\u0107i RFC 5890 internacionalizirani naziv glavnog ra\u010Dunala -format.iri = {0}: ne odgovara uzorku {1} mora biti va\u017Ee\u0107i RFC 3987 IRI -format.iri-reference = {0}: ne odgovara uzorku {1} mora biti va\u017Ee\u0107a RFC 3987 IRI referenca -format.uri = {0}: ne odgovara uzorku {1} mora biti va\u017Ee\u0107i RFC 3986 URI -format.uri-reference = {0}: ne odgovara uzorku {1} mora biti va\u017Ee\u0107a RFC 3986 URI referenca -format.uri-template = {0}: ne odgovara uzorku {1} mora biti va\u017Ee\u0107i RFC 6570 URI predlo\u017Eak -format.uuid = {0}: ne odgovara uzorku {1} mora biti va\u017Ee\u0107i RFC 4122 UUID -format.regex = {0}: ne odgovara uzorku {1} mora biti va\u017Ee\u0107i regularni izraz ECMA-262 -format.time = {0}: ne odgovara uzorku {1} mora biti va\u017Ee\u0107e RFC 3339 vrijeme -format.hostname = {0}: ne odgovara uzorku {1} mora biti va\u017Ee\u0107e RFC 1123 ime glavnog ra\u010Dunala -format.json-pointer = {0}: ne odgovara uzorku {1} mora biti va\u017Ee\u0107i RFC 6901 JSON pokaziva\u010D -format.relative-json-pointer = {0}: ne odgovara uzorku {1} mora biti va\u017Ee\u0107i IETF relativni JSON pokaziva\u010D -format.unknown = {0}: ima nepoznati format ''{1}'' -id = {0}: ''{1}'' nije valjan {2} -items = {0}: indeks ''{1}'' nije definiran u shemi i shema ne dopu\u0161ta dodatne stavke -maxContains = {0}: mora biti nenegativan cijeli broj u {1} -maxItems = {0}: mora imati najvi\u0161e {1} stavki, ali prona\u0111eno {2} -maxLength = {0}: mora imati najvi\u0161e {1} znakova -maxProperties = {0}: mora imati najvi\u0161e {1} svojstava -maximum = {0}: mora imati najve\u0107u vrijednost od {1} -minContains = {0}: mora biti nenegativan cijeli broj u {1} -minContainsVsMaxContains = {0}: minContains mora biti manji od ili jednak maxContains u {1} -minItems = {0}: mora imati najmanje {1} stavki, ali prona\u0111eno {2} -minLength = {0}: mora imati najmanje {1} znakova -minProperties = {0}: mora imati najmanje {1} svojstava -minimum = {0}: mora imati minimalnu vrijednost od {1} -multipleOf = {0}: mora biti vi\u0161estruko od {1} -not = {0}: ne smije biti va\u017Ee\u0107e za shemu {1} -notAllowed = {0}: svojstvo ''{1}'' nije dopu\u0161teno, ali je u podacima -oneOf = {0}: mora biti va\u017Ee\u0107e za jednu i samo jednu shemu, ali {1} su va\u017Ee\u0107e -oneOf.indexes = {0}: mora biti va\u017Ee\u0107e za jednu i samo jednu shemu, ali {1} su va\u017Ee\u0107e s indeksima ''{2}'' -pattern = {0}: ne odgovara uzorku regularnog izraza {1} -patternProperties = {0}: ima neke gre\u0161ke sa ''svojstvima uzorka'' -prefixItems = {0}: validator nije prona\u0111en u ovom indeksu -properties = {0}: ima gre\u0161ku sa ''svojstvima'' -propertyNames = {0}: ime svojstva ''{1}'' nije va\u017Ee\u0107e: {2} -readOnly = {0}: polje je samo za \u010Ditanje, ne mo\u017Ee se mijenjati -required = {0}: potrebno svojstvo ''{1}'' nije prona\u0111eno -type = {0}: {1} prona\u0111eno, {2} o\u010Dekivano -unevaluatedItems = {0}: indeks ''{1}'' se ne procjenjuje i shema ne dopu\u0161ta neprocijenjene stavke -unevaluatedProperties = {0}: svojstvo ''{1}'' se ne procjenjuje i shema ne dopu\u0161ta neprocijenjena svojstva -unionType = {0}: {1} prona\u0111eno, {2} o\u010Dekivano -uniqueItems = {0}: mora imati samo jedinstvene stavke u nizu -writeOnly = {0}: polje je samo za pisanje, ne mo\u017Ee se pojaviti u podacima -contentEncoding = {0}: ne odgovara kodiranju sadr\u017Eaja {1} -contentMediaType = {0}: nije ja sadr\u017Eaj +$ref = ima gre\u0161ku s ''refs'' +additionalItems = indeks ''{0}'' nije definiran u shemi i shema ne dopu\u0161ta dodatne stavke +additionalProperties = svojstvo ''{0}'' nije definirano u shemi i shema ne dopu\u0161ta dodatna svojstva +allOf = mora biti va\u017Ee\u0107e za sve sheme {0} +anyOf = mora biti va\u017Ee\u0107e za bilo koju od shema {0} +const = mora biti konstantna vrijednost ''{0}'' +contains = ne sadr\u017Ei element koji prolazi ove provjere: {1} +contains.max = mora sadr\u017Eavati najvi\u0161e {0} elemenata koji prolaze ove provjere: {1} +contains.min = mora sadr\u017Eavati najmanje {0} elementa koji prolaze ove provjere: {1} +dependencies = ima pogre\u0161ku s ovisnostima {0} +dependentRequired = nedostaje svojstvo ''{0}'' koje je ovisno potrebno jer je prisutan ''{1}'' +dependentSchemas = ima pogre\u0161ku s dependentSchemas {0} +enum = nema vrijednost u enumeraciji {0} +exclusiveMaximum = mora imati isklju\u010Divu maksimalnu vrijednost od {0} +exclusiveMinimum = mora imati isklju\u010Divu minimalnu vrijednost od {0} +false = shema za ''{0}'' je false +format = ne odgovara {0} uzorku +format.date = ne odgovara uzorku {0} mora biti va\u017Ee\u0107i puni datum RFC 3339 +format.date-time = ne odgovara uzorku {0} mora biti va\u017Ee\u0107i RFC 3339 datum-vrijeme +format.duration = ne odgovara uzorku {0} mora biti va\u017Ee\u0107e ISO 8601 trajanje +format.email = ne odgovara uzorku {0} mora biti va\u017Ee\u0107i po\u0161tanski sandu\u010Di\u0107 RFC 5321 +format.ipv4 = ne odgovara uzorku {0} mora biti va\u017Ee\u0107a RFC 2673 IP adresa +format.ipv6 = ne odgovara uzorku {0} mora biti va\u017Ee\u0107a RFC 4291 IP adresa +format.idn-email = ne odgovara uzorku {0} mora biti va\u017Ee\u0107i po\u0161tanski sandu\u010Di\u0107 RFC 6531 +format.idn-hostname = ne odgovara uzorku {0} mora biti va\u017Ee\u0107i RFC 5890 internacionalizirani naziv glavnog ra\u010Dunala +format.iri = ne odgovara uzorku {0} mora biti va\u017Ee\u0107i RFC 3987 IRI +format.iri-reference = ne odgovara uzorku {0} mora biti va\u017Ee\u0107a RFC 3987 IRI referenca +format.uri = ne odgovara uzorku {0} mora biti va\u017Ee\u0107i RFC 3986 URI +format.uri-reference = ne odgovara uzorku {0} mora biti va\u017Ee\u0107a RFC 3986 URI referenca +format.uri-template = ne odgovara uzorku {0} mora biti va\u017Ee\u0107i RFC 6570 URI predlo\u017Eak +format.uuid = ne odgovara uzorku {0} mora biti va\u017Ee\u0107i RFC 4122 UUID +format.regex = ne odgovara uzorku {0} mora biti va\u017Ee\u0107i regularni izraz ECMA-262 +format.time = ne odgovara uzorku {0} mora biti va\u017Ee\u0107e RFC 3339 vrijeme +format.hostname = ne odgovara uzorku {0} mora biti va\u017Ee\u0107e RFC 1123 ime glavnog ra\u010Dunala +format.json-pointer = ne odgovara uzorku {0} mora biti va\u017Ee\u0107i RFC 6901 JSON pokaziva\u010D +format.relative-json-pointer = ne odgovara uzorku {0} mora biti va\u017Ee\u0107i IETF relativni JSON pokaziva\u010D +format.unknown = ima nepoznati format ''{0}'' +id = ''{0}'' nije valjan {1} +items = indeks ''{0}'' nije definiran u shemi i shema ne dopu\u0161ta dodatne stavke +maxContains = mora biti nenegativan cijeli broj u {0} +maxItems = mora imati najvi\u0161e {0} stavki, ali prona\u0111eno {1} +maxLength = mora imati najvi\u0161e {0} znakova +maxProperties = mora imati najvi\u0161e {0} svojstava +maximum = mora imati najve\u0107u vrijednost od {0} +minContains = mora biti nenegativan cijeli broj u {0} +minContainsVsMaxContains = minContains mora biti manji od ili jednak maxContains u {0} +minItems = mora imati najmanje {0} stavki, ali prona\u0111eno {1} +minLength = mora imati najmanje {0} znakova +minProperties = mora imati najmanje {0} svojstava +minimum = mora imati minimalnu vrijednost od {0} +multipleOf = mora biti vi\u0161estruko od {0} +not = ne smije biti va\u017Ee\u0107e za shemu {0} +notAllowed = svojstvo ''{0}'' nije dopu\u0161teno, ali je u podacima +oneOf = mora biti va\u017Ee\u0107e za jednu i samo jednu shemu, ali {0} su va\u017Ee\u0107e +oneOf.indexes = mora biti va\u017Ee\u0107e za jednu i samo jednu shemu, ali {0} su va\u017Ee\u0107e s indeksima ''{1}'' +pattern = ne odgovara uzorku regularnog izraza {0} +patternProperties = ima neke gre\u0161ke sa ''svojstvima uzorka'' +prefixItems = validator nije prona\u0111en u ovom indeksu +properties = ima gre\u0161ku sa ''svojstvima'' +propertyNames = ime svojstva ''{0}'' nije va\u017Ee\u0107e: {1} +readOnly = polje je samo za \u010Ditanje, ne mo\u017Ee se mijenjati +required = potrebno svojstvo ''{0}'' nije prona\u0111eno +type = {0} prona\u0111eno, {1} o\u010Dekivano +unevaluatedItems = indeks ''{0}'' se ne procjenjuje i shema ne dopu\u0161ta neprocijenjene stavke +unevaluatedProperties = svojstvo ''{0}'' se ne procjenjuje i shema ne dopu\u0161ta neprocijenjena svojstva +unionType = {0} prona\u0111eno, {1} o\u010Dekivano +uniqueItems = mora imati samo jedinstvene stavke u nizu +writeOnly = polje je samo za pisanje, ne mo\u017Ee se pojaviti u podacima +contentEncoding = ne odgovara kodiranju sadr\u017Eaja {0} +contentMediaType = nije ja sadr\u017Eaj diff --git a/src/main/resources/jsv-messages_hu.properties b/src/main/resources/jsv-messages_hu.properties index 88485c631..2902a37d9 100644 --- a/src/main/resources/jsv-messages_hu.properties +++ b/src/main/resources/jsv-messages_hu.properties @@ -1,70 +1,70 @@ -$ref = {0}: hibás a ''refs'' -additionalItems = {0}: a ''{1}'' index nincs megadva a sémában, és a séma nem engedélyez további elemeket -additionalProperties = {0}: a ''{1}'' tulajdonság nincs megadva a sémában, és a séma nem engedélyez további tulajdonságokat -allOf = {0}: érvényesnek kell lennie az összes sémára {1} -anyOf = {0}: érvényesnek kell lennie a(z) {1} sémák bármelyikére -const = {0}: a ''{1}'' állandó értéknek kell lennie -contains = {0}: nem tartalmaz olyan elemet, amely átmegy a következ\u0151 ellen\u0151rzéseken: {2} -contains.max = {0}: legfeljebb {1} olyan elemet tartalmazhat, amely megfelel a következ\u0151 ellen\u0151rzéseknek: {2} -contains.min = {0}: tartalmaznia kell legalább {1} olyan elemet, amely átmegy a következ\u0151 ellen\u0151rzéseken: {2} -dependencies = {0}: hiba van a(z) {1} függ\u0151ségekkel -dependentRequired = {0}: hiányzik a(z) ''{1}'' tulajdonsága, amely szükséges, mert a ''{2}'' jelen van -dependentSchemas = {0}: hibás a dependentSchemas {1} -enum = {0}: nincs értéke a(z) {1} felsorolásban -exclusiveMaximum = {0}: kizárólagos maximális értéke {1} -exclusiveMinimum = {0}: kizárólagos minimális értéke {1} -false = {0}: ''{1}'' séma hamis -format = {0}: nem egyezik a {1} mintával {2} -format.date = {0}: nem egyezik a(z) {1} mintával, érvényes RFC 3339 teljes dátumúnak kell lennie -format.date-time = {0}: nem egyezik a {1} mintával, érvényes RFC 3339 dátum-id\u0151 -format.duration = {0}: nem egyezik a {1} mintával, érvényes ISO 8601 id\u0151tartamnak kell lennie -format.email = {0}: nem egyezik a {1} mintával, érvényes RFC 5321-es postafióknak kell lennie -format.ipv4 = {0}: nem egyezik a(z) {1} mintával, érvényes RFC 2673 IP-címnek kell lennie -format.ipv6 = {0}: nem egyezik a {1} mintával, érvényes RFC 4291 IP-címnek kell lennie -format.idn-email = {0}: nem egyezik a {1} mintával, érvényes RFC 6531-es postafióknak kell lennie -format.idn-hostname = {0}: nem egyezik a(z) {1} mintával, érvényes RFC 5890 nemzetköziesített gazdagépnévnek kell lennie -format.iri = {0}: nem egyezik a {1} mintával, érvényes RFC 3987 IRI-nek kell lennie -format.iri-reference = {0}: nem egyezik a {1} mintával, érvényes RFC 3987 IRI-hivatkozásnak kell lennie -format.uri = {0}: nem egyezik a {1} mintával, érvényes RFC 3986 URI-nek kell lennie -format.uri-reference = {0}: nem egyezik a {1} mintával, érvényes RFC 3986 URI-hivatkozásnak kell lennie -format.uri-template = {0}: nem egyezik a {1} mintával, érvényes RFC 6570 URI-sablonnak kell lennie -format.uuid = {0}: nem egyezik a {1} mintával, érvényes RFC 4122 UUID-nek kell lennie -format.regex = {0}: nem egyezik a {1} mintával, érvényes ECMA-262 reguláris kifejezésnek kell lennie -format.time = {0}: nem egyezik a {1} mintával, érvényes RFC 3339 id\u0151nek kell lennie -format.hostname = {0}: nem egyezik a(z) {1} mintával, érvényes RFC 1123 gazdagépnévnek kell lennie -format.json-pointer = {0}: nem egyezik a {1} mintával, érvényes RFC 6901 JSON-mutatónak kell lennie -format.relative-json-pointer = {0}: nem egyezik a {1} mintával, érvényes IETF relatív JSON-mutatónak kell lennie -format.unknown = {0}: ismeretlen formátuma: ''{1}'' -id = {0}: a ''{1}'' nem érvényes {2} -items = {0}: a ''{1}'' index nincs megadva a sémában, és a séma nem engedélyez további elemeket -maxContains = {0}: egy nem negatív egész számnak kell lennie a következ\u0151ben: {1} -maxItems = {0}: legfeljebb {1} elemet tartalmazhat, de {2} található -maxLength = {0}: legfeljebb {1} karakter hosszúságú lehet -maxProperties = {0}: legfeljebb {1} tulajdonsággal kell rendelkeznie -maximum = {0}: maximum {1} értékkel kell rendelkeznie -minContains = {0}: egy nem negatív egész számnak kell lennie a következ\u0151ben: {1} -minContainsVsMaxContains = {0}: A minContains értékének kisebbnek vagy egyenl\u0151nek kell lennie, mint a maxContains a következ\u0151ben: {1} -minItems = {0}: legalább {1} elemnek kell lennie, de {2} található -minLength = {0}: legalább {1} karakter hosszúságúnak kell lennie -minProperties = {0}: legalább {1} tulajdonsággal kell rendelkeznie -minimum = {0}: legalább {1} értékkel kell rendelkeznie -multipleOf = {0}: {1} többszörösének kell lennie -not = {0}: nem érvényes a(z) {1} sémára -notAllowed = {0}: a ''{1}'' tulajdonság nem engedélyezett, de benne van az adatokban -oneOf = {0}: érvényesnek kell lennie egy és csak egy sémára, de a {1} érvényes -oneOf.indexes = {0}: érvényesnek kell lennie egy és csak egy sémára, de a {1} érvényes a következ\u0151 indexekkel: ''{2}'' -pattern = {0}: nem egyezik a következ\u0151 regex mintával: {1} -patternProperties = {0}: hibás a "minta tulajdonságai" -prefixItems = {0}: ezen az indexen nem található érvényesít\u0151 -properties = {0}: hibás a "tulajdonságok" -propertyNames = {0}: a(z) ''{1}'' tulajdonság neve érvénytelen: {2} -readOnly = {0}: csak olvasható mez\u0151, nem módosítható -required = {0}: a(z) ''{1}'' kötelez\u0151 tulajdonság nem található -type = {0}: {1} található, {2} várható -unevaluatedItems = {0}: a ''{1}'' index nincs kiértékelve, és a séma nem engedélyezi az értékeletlen elemeket -unevaluatedProperties = {0}: a(z) ''{1}'' tulajdonság nincs kiértékelve, és a séma nem engedélyezi az értékeletlen tulajdonságokat -unionType = {0}: {1} található, {2} várható -uniqueItems = {0}: csak egyedi elemek lehetnek a tömbben -writeOnly = {0}: csak írható mez\u0151, nem jelenhet meg az adatokban -contentEncoding = {0}: nem egyezik a következ\u0151 tartalomkódolással: {1} -contentMediaType = {0}: nem egy tartalom én +$ref = hibás a ''refs'' +additionalItems = a ''{0}'' index nincs megadva a sémában, és a séma nem engedélyez további elemeket +additionalProperties = a ''{0}'' tulajdonság nincs megadva a sémában, és a séma nem engedélyez további tulajdonságokat +allOf = érvényesnek kell lennie az összes sémára {0} +anyOf = érvényesnek kell lennie a(z) {0} sémák bármelyikére +const = a ''{0}'' állandó értéknek kell lennie +contains = nem tartalmaz olyan elemet, amely átmegy a következ\u0151 ellen\u0151rzéseken: {1} +contains.max = legfeljebb {0} olyan elemet tartalmazhat, amely megfelel a következ\u0151 ellen\u0151rzéseknek: {1} +contains.min = tartalmaznia kell legalább {0} olyan elemet, amely átmegy a következ\u0151 ellen\u0151rzéseken: {1} +dependencies = hiba van a(z) {0} függ\u0151ségekkel +dependentRequired = hiányzik a(z) ''{0}'' tulajdonsága, amely szükséges, mert a ''{1}'' jelen van +dependentSchemas = hibás a dependentSchemas {0} +enum = nincs értéke a(z) {0} felsorolásban +exclusiveMaximum = kizárólagos maximális értéke {0} +exclusiveMinimum = kizárólagos minimális értéke {0} +false = ''{0}'' séma hamis +format = nem egyezik a {0} mintával +format.date = nem egyezik a(z) {0} mintával, érvényes RFC 3339 teljes dátumúnak kell lennie +format.date-time = nem egyezik a {0} mintával, érvényes RFC 3339 dátum-id\u0151 +format.duration = nem egyezik a {0} mintával, érvényes ISO 8601 id\u0151tartamnak kell lennie +format.email = nem egyezik a {0} mintával, érvényes RFC 5321-es postafióknak kell lennie +format.ipv4 = nem egyezik a(z) {0} mintával, érvényes RFC 2673 IP-címnek kell lennie +format.ipv6 = nem egyezik a {0} mintával, érvényes RFC 4291 IP-címnek kell lennie +format.idn-email = nem egyezik a {0} mintával, érvényes RFC 6531-es postafióknak kell lennie +format.idn-hostname = nem egyezik a(z) {0} mintával, érvényes RFC 5890 nemzetköziesített gazdagépnévnek kell lennie +format.iri = nem egyezik a {0} mintával, érvényes RFC 3987 IRI-nek kell lennie +format.iri-reference = nem egyezik a {0} mintával, érvényes RFC 3987 IRI-hivatkozásnak kell lennie +format.uri = nem egyezik a {0} mintával, érvényes RFC 3986 URI-nek kell lennie +format.uri-reference = nem egyezik a {0} mintával, érvényes RFC 3986 URI-hivatkozásnak kell lennie +format.uri-template = nem egyezik a {0} mintával, érvényes RFC 6570 URI-sablonnak kell lennie +format.uuid = nem egyezik a {0} mintával, érvényes RFC 4122 UUID-nek kell lennie +format.regex = nem egyezik a {0} mintával, érvényes ECMA-262 reguláris kifejezésnek kell lennie +format.time = nem egyezik a {0} mintával, érvényes RFC 3339 id\u0151nek kell lennie +format.hostname = nem egyezik a(z) {0} mintával, érvényes RFC 1123 gazdagépnévnek kell lennie +format.json-pointer = nem egyezik a {0} mintával, érvényes RFC 6901 JSON-mutatónak kell lennie +format.relative-json-pointer = nem egyezik a {0} mintával, érvényes IETF relatív JSON-mutatónak kell lennie +format.unknown = ismeretlen formátuma: ''{0}'' +id = a ''{0}'' nem érvényes {1} +items = a ''{0}'' index nincs megadva a sémában, és a séma nem engedélyez további elemeket +maxContains = egy nem negatív egész számnak kell lennie a következ\u0151ben: {0} +maxItems = legfeljebb {0} elemet tartalmazhat, de {1} található +maxLength = legfeljebb {0} karakter hosszúságú lehet +maxProperties = legfeljebb {0} tulajdonsággal kell rendelkeznie +maximum = maximum {0} értékkel kell rendelkeznie +minContains = egy nem negatív egész számnak kell lennie a következ\u0151ben: {0} +minContainsVsMaxContains = A minContains értékének kisebbnek vagy egyenl\u0151nek kell lennie, mint a maxContains a következ\u0151ben: {0} +minItems = legalább {0} elemnek kell lennie, de {1} található +minLength = legalább {0} karakter hosszúságúnak kell lennie +minProperties = legalább {0} tulajdonsággal kell rendelkeznie +minimum = legalább {0} értékkel kell rendelkeznie +multipleOf = {0} többszörösének kell lennie +not = nem érvényes a(z) {0} sémára +notAllowed = a ''{0}'' tulajdonság nem engedélyezett, de benne van az adatokban +oneOf = érvényesnek kell lennie egy és csak egy sémára, de a {0} érvényes +oneOf.indexes = érvényesnek kell lennie egy és csak egy sémára, de a {0} érvényes a következ\u0151 indexekkel: ''{1}'' +pattern = nem egyezik a következ\u0151 regex mintával: {0} +patternProperties = hibás a "minta tulajdonságai" +prefixItems = ezen az indexen nem található érvényesít\u0151 +properties = hibás a "tulajdonságok" +propertyNames = a(z) ''{0}'' tulajdonság neve érvénytelen: {1} +readOnly = csak olvasható mez\u0151, nem módosítható +required = a(z) ''{0}'' kötelez\u0151 tulajdonság nem található +type = {0} található, {1} várható +unevaluatedItems = a ''{0}'' index nincs kiértékelve, és a séma nem engedélyezi az értékeletlen elemeket +unevaluatedProperties = a(z) ''{0}'' tulajdonság nincs kiértékelve, és a séma nem engedélyezi az értékeletlen tulajdonságokat +unionType = {0} található, {1} várható +uniqueItems = csak egyedi elemek lehetnek a tömbben +writeOnly = csak írható mez\u0151, nem jelenhet meg az adatokban +contentEncoding = nem egyezik a következ\u0151 tartalomkódolással: {0} +contentMediaType = nem egy tartalom én diff --git a/src/main/resources/jsv-messages_it.properties b/src/main/resources/jsv-messages_it.properties index 87efce766..e5738ffbc 100644 --- a/src/main/resources/jsv-messages_it.properties +++ b/src/main/resources/jsv-messages_it.properties @@ -1,70 +1,70 @@ -$ref = {0}: ha un errore con ''refs'' -additionalItems = {0}: l''indice ''{1}'' non è definito nello schema e lo schema non consente elementi aggiuntivi -additionalProperties = {0}: la proprietà ''{1}'' non è definita nello schema e lo schema non consente proprietà aggiuntive -allOf = {0}: deve essere valido per tutti gli schemi {1} -anyOf = {0}: deve essere valido per uno qualsiasi degli schemi {1} -const = {0}: deve essere il valore costante ''{1}'' -contains = {0}: non contiene un elemento che supera queste convalide: {2} -contains.max = {0}: deve contenere al massimo {1} elemento/i che supera queste convalide: {2} -contains.min = {0}: deve contenere almeno {1} elemento/i che supera queste convalide: {2} -dependencies = {0}: presenta un errore con le dipendenze {1} -dependentRequired = {0}: ha una proprietà mancante ''{1}'' che è dipendente obbligatoria perché ''{2}'' è presente -dependentSchemas = {0}: ha un errore con dipendentiSchemas {1} -enum = {0}: non ha un valore nell''enumerazione {1} -exclusiveMaximum = {0}: deve avere un valore massimo esclusivo di {1} -exclusiveMinimum = {0}: deve avere un valore minimo esclusivo di {1} -false = {0}: lo schema per ''{1}'' è falso -format = {0}: non corrisponde al modello {1} {2} -format.date = {0}: non corrisponde al modello {1} deve essere una data completa RFC 3339 valida -format.date-time = {0}: non corrisponde al modello {1} deve essere una data-ora RFC 3339 valida -format.duration = {0}: non corrisponde al modello {1} deve essere una durata ISO 8601 valida -format.email = {0}: non corrisponde al modello {1} deve essere una casella di posta RFC 5321 valida -format.ipv4 = {0}: non corrisponde al modello {1} deve essere un indirizzo IP RFC 2673 valido -format.ipv6 = {0}: non corrisponde al modello {1} deve essere un indirizzo IP RFC 4291 valido -format.idn-email = {0}: non corrisponde al modello {1} deve essere una casella di posta RFC 6531 valida -format.idn-hostname = {0}: non corrisponde al modello {1} deve essere un nome host internazionalizzato RFC 5890 valido -format.iri = {0}: non corrisponde al modello {1} deve essere un IRI RFC 3987 valido -format.iri-reference = {0}: non corrisponde al modello {1} deve essere un riferimento IRI RFC 3987 valido -format.uri = {0}: non corrisponde al modello {1} deve essere un URI RFC 3986 valido -format.uri-reference = {0}: non corrisponde al modello {1} deve essere un riferimento URI RFC 3986 valido -format.uri-template = {0}: non corrisponde al modello {1} deve essere un modello URI RFC 6570 valido -format.uuid = {0}: non corrisponde al modello {1} deve essere un UUID RFC 4122 valido -format.regex = {0}: non corrisponde al modello {1} deve essere un''espressione regolare ECMA-262 valida -format.time = {0}: non corrisponde al modello {1} deve essere un''ora RFC 3339 valida -format.hostname = {0}: non corrisponde al modello {1} deve essere un nome host RFC 1123 valido -format.json-pointer = {0}: non corrisponde al modello {1} deve essere un puntatore JSON RFC 6901 valido -format.relative-json-pointer = {0}: non corrisponde al modello {1} deve essere un puntatore JSON relativo IETF valido -format.unknown = {0}: ha un formato sconosciuto ''{1}'' -id = {0}: ''{1}'' non è un {2} valido -items = {0}: l''indice ''{1}'' non è definito nello schema e lo schema non consente elementi aggiuntivi -maxContains = {0}: deve essere un numero intero non negativo in {1} -maxItems = {0}: deve avere al massimo {1} elementi ma trovati {2} -maxLength = {0}: deve contenere al massimo {1} caratteri -maxProperties = {0}: deve avere al massimo {1} proprietà -maximum = {0}: deve avere un valore massimo di {1} -minContains = {0}: deve essere un numero intero non negativo in {1} -minContainsVsMaxContains = {0}: minContains deve essere minore o uguale a maxContains in {1} -minItems = {0}: deve avere almeno {1} elementi ma trovati {2} -minLength = {0}: deve contenere almeno {1} caratteri -minProperties = {0}: deve avere almeno {1} proprietà -minimum = {0}: deve avere un valore minimo di {1} -multipleOf = {0}: deve essere multiplo di {1} -not = {0}: non deve essere valido per lo schema {1} -notAllowed = {0}: la proprietà ''{1}'' non è consentita ma è nei dati -oneOf = {0}: deve essere valido per uno e un solo schema, ma {1} sono validi -oneOf.indexes = {0}: deve essere valido per uno e un solo schema, ma {1} sono validi con gli indici ''{2}'' -pattern = {0}: non corrisponde al pattern regex {1} -patternProperties = {0}: presenta qualche errore con le ''proprietà del modello'' -prefixItems = {0}: nessun validatore trovato in questo indice -properties = {0}: presenta un errore con ''proprietà'' -propertyNames = {0}: il nome della proprietà ''{1}'' non è valido: {2} -readOnly = {0}: è un campo di sola lettura, non può essere modificato -required = {0}: proprietà richiesta ''{1}'' non trovata -type = {0}: {1} trovato, {2} previsto -unevaluatedItems = {0}: l''indice ''{1}'' non viene valutato e lo schema non consente elementi non valutati -unevaluatedProperties = {0}: la proprietà ''{1}'' non viene valutata e lo schema non consente proprietà non valutate -unionType = {0}: {1} trovato, {2} previsto -uniqueItems = {0}: deve contenere solo elementi univoci nell''array -writeOnly = {0}: è un campo di sola scrittura, non può apparire nei dati -contentEncoding = {0}: non corrisponde alla codifica del contenuto {1} -contentMediaType = {0}: non è un contenuto me +$ref = ha un errore con ''refs'' +additionalItems = l''indice ''{0}'' non è definito nello schema e lo schema non consente elementi aggiuntivi +additionalProperties = la proprietà ''{0}'' non è definita nello schema e lo schema non consente proprietà aggiuntive +allOf = deve essere valido per tutti gli schemi {0} +anyOf = deve essere valido per uno qualsiasi degli schemi {0} +const = deve essere il valore costante ''{0}'' +contains = non contiene un elemento che supera queste convalide: {1} +contains.max = deve contenere al massimo {0} elemento/i che supera queste convalide: {1} +contains.min = deve contenere almeno {0} elemento/i che supera queste convalide: {1} +dependencies = presenta un errore con le dipendenze {0} +dependentRequired = ha una proprietà mancante ''{0}'' che è dipendente obbligatoria perché ''{1}'' è presente +dependentSchemas = ha un errore con dipendentiSchemas {0} +enum = non ha un valore nell''enumerazione {0} +exclusiveMaximum = deve avere un valore massimo esclusivo di {0} +exclusiveMinimum = deve avere un valore minimo esclusivo di {0} +false = lo schema per ''{0}'' è falso +format = non corrisponde al modello {0} +format.date = non corrisponde al modello {0} deve essere una data completa RFC 3339 valida +format.date-time = non corrisponde al modello {0} deve essere una data-ora RFC 3339 valida +format.duration = non corrisponde al modello {0} deve essere una durata ISO 8601 valida +format.email = non corrisponde al modello {0} deve essere una casella di posta RFC 5321 valida +format.ipv4 = non corrisponde al modello {0} deve essere un indirizzo IP RFC 2673 valido +format.ipv6 = non corrisponde al modello {0} deve essere un indirizzo IP RFC 4291 valido +format.idn-email = non corrisponde al modello {0} deve essere una casella di posta RFC 6531 valida +format.idn-hostname = non corrisponde al modello {0} deve essere un nome host internazionalizzato RFC 5890 valido +format.iri = non corrisponde al modello {0} deve essere un IRI RFC 3987 valido +format.iri-reference = non corrisponde al modello {0} deve essere un riferimento IRI RFC 3987 valido +format.uri = non corrisponde al modello {0} deve essere un URI RFC 3986 valido +format.uri-reference = non corrisponde al modello {0} deve essere un riferimento URI RFC 3986 valido +format.uri-template = non corrisponde al modello {0} deve essere un modello URI RFC 6570 valido +format.uuid = non corrisponde al modello {0} deve essere un UUID RFC 4122 valido +format.regex = non corrisponde al modello {0} deve essere un''espressione regolare ECMA-262 valida +format.time = non corrisponde al modello {0} deve essere un''ora RFC 3339 valida +format.hostname = non corrisponde al modello {0} deve essere un nome host RFC 1123 valido +format.json-pointer = non corrisponde al modello {0} deve essere un puntatore JSON RFC 6901 valido +format.relative-json-pointer = non corrisponde al modello {0} deve essere un puntatore JSON relativo IETF valido +format.unknown = ha un formato sconosciuto ''{0}'' +id = ''{0}'' non è un {1} valido +items = l''indice ''{0}'' non è definito nello schema e lo schema non consente elementi aggiuntivi +maxContains = deve essere un numero intero non negativo in {0} +maxItems = deve avere al massimo {0} elementi ma trovati {1} +maxLength = deve contenere al massimo {0} caratteri +maxProperties = deve avere al massimo {0} proprietà +maximum = deve avere un valore massimo di {0} +minContains = deve essere un numero intero non negativo in {0} +minContainsVsMaxContains = minContains deve essere minore o uguale a maxContains in {0} +minItems = deve avere almeno {0} elementi ma trovati {1} +minLength = deve contenere almeno {0} caratteri +minProperties = deve avere almeno {0} proprietà +minimum = deve avere un valore minimo di {0} +multipleOf = deve essere multiplo di {0} +not = non deve essere valido per lo schema {0} +notAllowed = la proprietà ''{0}'' non è consentita ma è nei dati +oneOf = deve essere valido per uno e un solo schema, ma {0} sono validi +oneOf.indexes = deve essere valido per uno e un solo schema, ma {0} sono validi con gli indici ''{1}'' +pattern = non corrisponde al pattern regex {0} +patternProperties = presenta qualche errore con le ''proprietà del modello'' +prefixItems = nessun validatore trovato in questo indice +properties = presenta un errore con ''proprietà'' +propertyNames = il nome della proprietà ''{0}'' non è valido: {1} +readOnly = è un campo di sola lettura, non può essere modificato +required = proprietà richiesta ''{0}'' non trovata +type = {0} trovato, {1} previsto +unevaluatedItems = l''indice ''{0}'' non viene valutato e lo schema non consente elementi non valutati +unevaluatedProperties = la proprietà ''{0}'' non viene valutata e lo schema non consente proprietà non valutate +unionType = {0} trovato, {1} previsto +uniqueItems = deve contenere solo elementi univoci nell''array +writeOnly = è un campo di sola scrittura, non può apparire nei dati +contentEncoding = non corrisponde alla codifica del contenuto {0} +contentMediaType = non è un contenuto me diff --git a/src/main/resources/jsv-messages_ja.properties b/src/main/resources/jsv-messages_ja.properties index 15a6b6a52..cb2a3259b 100644 --- a/src/main/resources/jsv-messages_ja.properties +++ b/src/main/resources/jsv-messages_ja.properties @@ -1,70 +1,70 @@ -$ref = {0}: ''refs'' \u306B\u30A8\u30E9\u30FC\u304C\u3042\u308A\u307E\u3059 -additionalItems = {0}: \u30A4\u30F3\u30C7\u30C3\u30AF\u30B9 ''{1}'' \u304C\u30B9\u30AD\u30FC\u30DE\u3067\u5B9A\u7FA9\u3055\u308C\u3066\u304A\u3089\u305A\u3001\u30B9\u30AD\u30FC\u30DE\u3067\u306F\u8FFD\u52A0\u306E\u9805\u76EE\u304C\u8A31\u53EF\u3055\u308C\u3066\u3044\u307E\u305B\u3093 -additionalProperties = {0}: \u30D7\u30ED\u30D1\u30C6\u30A3 ''{1}'' \u304C\u30B9\u30AD\u30FC\u30DE\u3067\u5B9A\u7FA9\u3055\u308C\u3066\u304A\u3089\u305A\u3001\u30B9\u30AD\u30FC\u30DE\u3067\u306F\u8FFD\u52A0\u306E\u30D7\u30ED\u30D1\u30C6\u30A3\u304C\u8A31\u53EF\u3055\u308C\u3066\u3044\u307E\u305B\u3093 -allOf = {0}: \u3059\u3079\u3066\u306E\u30B9\u30AD\u30FC\u30DE {1} \u306B\u5BFE\u3057\u3066\u6709\u52B9\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 -anyOf = {0}: \u3044\u305A\u308C\u304B\u306E\u30B9\u30AD\u30FC\u30DE {1} \u306B\u5BFE\u3057\u3066\u6709\u52B9\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 -const = {0}: \u5B9A\u6570\u5024 ''{1}'' \u3067\u306A\u3051\u308C\u3070\u306A\u308A\u307E\u305B\u3093 -contains = {0}: \u6B21\u306E\u691C\u8A3C\u306B\u5408\u683C\u3059\u308B\u8981\u7D20\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u305B\u3093: {2} -contains.max = {0}: \u3053\u308C\u3089\u306E\u691C\u8A3C\u306B\u5408\u683C\u3059\u308B\u8981\u7D20\u306F\u6700\u5927\u3067\u3082 {1} \u500B\u542B\u307E\u308C\u3066\u3044\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059: {2} -contains.min = {0}: \u3053\u308C\u3089\u306E\u691C\u8A3C\u306B\u5408\u683C\u3059\u308B\u5C11\u306A\u304F\u3068\u3082 {1} \u500B\u306E\u8981\u7D20\u304C\u542B\u307E\u308C\u3066\u3044\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059: {2} -dependencies = {0}: \u4F9D\u5B58\u95A2\u4FC2 {1} \u306B\u30A8\u30E9\u30FC\u304C\u3042\u308A\u307E\u3059 -dependentRequired = {0}: \u30D7\u30ED\u30D1\u30C6\u30A3 ''{1}'' \u304C\u3042\u308A\u307E\u305B\u3093\u3002''{2}'' \u304C\u5B58\u5728\u3059\u308B\u305F\u3081\u3001\u4F9D\u5B58\u95A2\u4FC2\u304C\u5FC5\u8981\u3067\u3059\u3002 -dependentSchemas = {0}:dependentSchemas {1} \u306B\u30A8\u30E9\u30FC\u304C\u3042\u308A\u307E\u3059 -enum = {0}: \u5217\u6319\u578B {1} \u306B\u5024\u304C\u3042\u308A\u307E\u305B\u3093 -exclusiveMaximum = {0}: \u6392\u4ED6\u7684\u306A\u6700\u5927\u5024\u306F {1} \u3067\u306A\u3051\u308C\u3070\u306A\u308A\u307E\u305B\u3093 -exclusiveMinimum = {0}: \u6392\u4ED6\u7684\u306A\u6700\u5C0F\u5024\u306F {1} \u3067\u306A\u3051\u308C\u3070\u306A\u308A\u307E\u305B\u3093 -false = {0}: ''{1}'' \u306E\u30B9\u30AD\u30FC\u30DE\u306F false \u3067\u3059 -format = {0}: {1} \u30D1\u30BF\u30FC\u30F3 {2} \u306B\u4E00\u81F4\u3057\u307E\u305B\u3093 -format.date = {0}: {1} \u30D1\u30BF\u30FC\u30F3\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6709\u52B9\u306A RFC 3339 \u306E\u5B8C\u5168\u306A\u65E5\u4ED8\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 -format.date-time = {0}: {1} \u30D1\u30BF\u30FC\u30F3\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6709\u52B9\u306A RFC 3339 \u65E5\u4ED8/\u6642\u523B\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 -format.duration = {0}: {1} \u30D1\u30BF\u30FC\u30F3\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6709\u52B9\u306A ISO 8601 \u671F\u9593\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 -format.email = {0}: {1} \u30D1\u30BF\u30FC\u30F3\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6709\u52B9\u306A RFC 5321 \u30E1\u30FC\u30EB\u30DC\u30C3\u30AF\u30B9\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 -format.ipv4 = {0}: {1} \u30D1\u30BF\u30FC\u30F3\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6709\u52B9\u306A RFC 2673 IP \u30A2\u30C9\u30EC\u30B9\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 -format.ipv6 = {0}: {1} \u30D1\u30BF\u30FC\u30F3\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6709\u52B9\u306A RFC 4291 IP \u30A2\u30C9\u30EC\u30B9\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 -format.idn-email = {0}: {1} \u30D1\u30BF\u30FC\u30F3\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6709\u52B9\u306A RFC 6531 \u30E1\u30FC\u30EB\u30DC\u30C3\u30AF\u30B9\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 -format.idn-hostname = {0}: {1} \u30D1\u30BF\u30FC\u30F3\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6709\u52B9\u306A RFC 5890 \u56FD\u969B\u5316\u30DB\u30B9\u30C8\u540D\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 -format.iri = {0}: {1} \u30D1\u30BF\u30FC\u30F3\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6709\u52B9\u306A RFC 3987 IRI \u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 -format.iri-reference = {0}: {1} \u30D1\u30BF\u30FC\u30F3\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6709\u52B9\u306A RFC 3987 IRI \u53C2\u7167\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 -format.uri = {0}: {1} \u30D1\u30BF\u30FC\u30F3\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6709\u52B9\u306A RFC 3986 URI \u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 -format.uri-reference = {0}: {1} \u30D1\u30BF\u30FC\u30F3\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6709\u52B9\u306A RFC 3986 URI \u53C2\u7167\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 -format.uri-template = {0}: {1} \u30D1\u30BF\u30FC\u30F3\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6709\u52B9\u306A RFC 6570 URI \u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 -format.uuid = {0}: {1} \u30D1\u30BF\u30FC\u30F3\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6709\u52B9\u306A RFC 4122 UUID \u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 -format.regex = {0}: {1} \u30D1\u30BF\u30FC\u30F3\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6709\u52B9\u306A ECMA-262 \u6B63\u898F\u8868\u73FE\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 -format.time = {0}: {1} \u30D1\u30BF\u30FC\u30F3\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6709\u52B9\u306A RFC 3339 \u6642\u523B\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 -format.hostname = {0}: {1} \u30D1\u30BF\u30FC\u30F3\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6709\u52B9\u306A RFC 1123 \u30DB\u30B9\u30C8\u540D\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 -format.json-pointer = {0}: {1} \u30D1\u30BF\u30FC\u30F3\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6709\u52B9\u306A RFC 6901 JSON \u30DD\u30A4\u30F3\u30BF\u30FC\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 -format.relative-json-pointer = {0}: {1} \u30D1\u30BF\u30FC\u30F3\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6709\u52B9\u306A IETF \u76F8\u5BFE JSON \u30DD\u30A4\u30F3\u30BF\u30FC\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 -format.unknown = {0}: \u4E0D\u660E\u306A\u5F62\u5F0F ''{1}'' \u304C\u3042\u308A\u307E\u3059 -id = {0}: ''{1}'' \u306F\u6709\u52B9\u306A {2} \u3067\u306F\u3042\u308A\u307E\u305B\u3093 -items = {0}: \u30A4\u30F3\u30C7\u30C3\u30AF\u30B9 ''{1}'' \u304C\u30B9\u30AD\u30FC\u30DE\u3067\u5B9A\u7FA9\u3055\u308C\u3066\u304A\u3089\u305A\u3001\u30B9\u30AD\u30FC\u30DE\u3067\u306F\u8FFD\u52A0\u306E\u9805\u76EE\u304C\u8A31\u53EF\u3055\u308C\u3066\u3044\u307E\u305B\u3093 -maxContains = {0}: {1} \u306B\u306F\u8CA0\u3067\u306A\u3044\u6574\u6570\u3092\u6307\u5B9A\u3059\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 -maxItems = {0}: \u30A2\u30A4\u30C6\u30E0\u306F\u6700\u5927\u3067\u3082 {1} \u500B\u5FC5\u8981\u3067\u3059\u304C\u3001{2} \u304C\u898B\u3064\u304B\u308A\u307E\u3057\u305F -maxLength = {0}: \u9577\u3055\u306F\u6700\u5927 {1} \u6587\u5B57\u3067\u306A\u3051\u308C\u3070\u306A\u308A\u307E\u305B\u3093 -maxProperties = {0}: \u6700\u5927\u3067 {1} \u500B\u306E\u30D7\u30ED\u30D1\u30C6\u30A3\u304C\u5FC5\u8981\u3067\u3059 -maximum = {0}: \u6700\u5927\u5024\u306F {1} \u3067\u306A\u3051\u308C\u3070\u306A\u308A\u307E\u305B\u3093 -minContains = {0}: {1} \u306B\u306F\u8CA0\u3067\u306A\u3044\u6574\u6570\u3092\u6307\u5B9A\u3059\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 -minContainsVsMaxContains = {0}: minContains \u306F {1} \u306E maxContains \u4EE5\u4E0B\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 -minItems = {0}: \u5C11\u306A\u304F\u3068\u3082 {1} \u500B\u306E\u9805\u76EE\u304C\u5FC5\u8981\u3067\u3059\u304C\u3001{2} \u304C\u898B\u3064\u304B\u308A\u307E\u3057\u305F -minLength = {0}: \u5C11\u306A\u304F\u3068\u3082 {1} \u6587\u5B57\u306E\u9577\u3055\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 -minProperties = {0}: \u5C11\u306A\u304F\u3068\u3082 {1} \u500B\u306E\u30D7\u30ED\u30D1\u30C6\u30A3\u304C\u5FC5\u8981\u3067\u3059 -minimum = {0}: \u6700\u5C0F\u5024\u306F {1} \u3067\u306A\u3051\u308C\u3070\u306A\u308A\u307E\u305B\u3093 -multipleOf = {0}: {1} \u306E\u500D\u6570\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 -not = {0}: \u30B9\u30AD\u30FC\u30DE {1} \u306B\u5BFE\u3057\u3066\u6709\u52B9\u3067\u3042\u3063\u3066\u306F\u306A\u308A\u307E\u305B\u3093 -notAllowed = {0}: \u30D7\u30ED\u30D1\u30C6\u30A3 ''{1}'' \u306F\u8A31\u53EF\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u304C\u3001\u30C7\u30FC\u30BF\u5185\u306B\u3042\u308A\u307E\u3059 -oneOf = {0}: 1 \u3064\u306E\u30B9\u30AD\u30FC\u30DE\u306B\u5BFE\u3057\u3066\u306E\u307F\u6709\u52B9\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u304C\u3001{1} \u306F\u6709\u52B9\u3067\u3059 -oneOf.indexes = {0}: 1 \u3064\u306E\u30B9\u30AD\u30FC\u30DE\u306B\u5BFE\u3057\u3066\u306E\u307F\u6709\u52B9\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u304C\u3001{1} \u306F\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9 ''{2}'' \u306B\u5BFE\u3057\u3066\u6709\u52B9\u3067\u3059 -pattern = {0}: \u6B63\u898F\u8868\u73FE\u30D1\u30BF\u30FC\u30F3 {1} \u306B\u4E00\u81F4\u3057\u307E\u305B\u3093 -patternProperties = {0}: ''\u30D1\u30BF\u30FC\u30F3 \u30D7\u30ED\u30D1\u30C6\u30A3'' \u306B\u30A8\u30E9\u30FC\u304C\u3042\u308A\u307E\u3059 -prefixItems = {0}: \u3053\u306E\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u3067\u30D0\u30EA\u30C7\u30FC\u30BF\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093 -properties = {0}: ''\u30D7\u30ED\u30D1\u30C6\u30A3'' \u306B\u30A8\u30E9\u30FC\u304C\u3042\u308A\u307E\u3059 -propertyNames = {0}: \u30D7\u30ED\u30D1\u30C6\u30A3 ''{1}'' \u306E\u540D\u524D\u304C\u7121\u52B9\u3067\u3059: {2} -readOnly = {0}: \u306F\u8AAD\u307F\u53D6\u308A\u5C02\u7528\u30D5\u30A3\u30FC\u30EB\u30C9\u3067\u3059\u3002\u5909\u66F4\u3067\u304D\u307E\u305B\u3093 -required = {0}: \u5FC5\u9808\u30D7\u30ED\u30D1\u30C6\u30A3 ''{1}'' \u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093 -type = {0}: {1} \u304C\u898B\u3064\u304B\u308A\u307E\u3057\u305F\u3001{2} \u304C\u4E88\u671F\u3055\u308C\u307E\u3057\u305F -unevaluatedItems = {0}: \u30A4\u30F3\u30C7\u30C3\u30AF\u30B9 ''{1}'' \u306F\u8A55\u4FA1\u3055\u308C\u3066\u304A\u3089\u305A\u3001\u30B9\u30AD\u30FC\u30DE\u306F\u672A\u8A55\u4FA1\u306E\u9805\u76EE\u3092\u8A31\u53EF\u3057\u3066\u3044\u307E\u305B\u3093 -unevaluatedProperties = {0}: \u30D7\u30ED\u30D1\u30C6\u30A3 ''{1}'' \u306F\u8A55\u4FA1\u3055\u308C\u3066\u304A\u3089\u305A\u3001\u30B9\u30AD\u30FC\u30DE\u306F\u672A\u8A55\u4FA1\u306E\u30D7\u30ED\u30D1\u30C6\u30A3\u3092\u8A31\u53EF\u3057\u3066\u3044\u307E\u305B\u3093 -unionType = {0}: {1} \u304C\u898B\u3064\u304B\u308A\u307E\u3057\u305F\u3001{2} \u304C\u4E88\u671F\u3055\u308C\u307E\u3057\u305F -uniqueItems = {0}: \u914D\u5217\u306B\u306F\u4E00\u610F\u306E\u9805\u76EE\u306E\u307F\u3092\u542B\u3081\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 -writeOnly = {0}: \u306F\u66F8\u304D\u8FBC\u307F\u5C02\u7528\u30D5\u30A3\u30FC\u30EB\u30C9\u3067\u3059\u3002\u30C7\u30FC\u30BF\u306B\u306F\u8868\u793A\u3067\u304D\u307E\u305B\u3093\u3002 -contentEncoding = {0}: \u30B3\u30F3\u30C6\u30F3\u30C4 \u30A8\u30F3\u30B3\u30FC\u30C7\u30A3\u30F3\u30B0 {1} \u3068\u4E00\u81F4\u3057\u307E\u305B\u3093 -contentMediaType = {0}: \u30B3\u30F3\u30C6\u30F3\u30C4\u3067\u306F\u3042\u308A\u307E\u305B\u3093 +$ref = ''refs'' \u306B\u30A8\u30E9\u30FC\u304C\u3042\u308A\u307E\u3059 +additionalItems = \u30A4\u30F3\u30C7\u30C3\u30AF\u30B9 ''{0}'' \u304C\u30B9\u30AD\u30FC\u30DE\u3067\u5B9A\u7FA9\u3055\u308C\u3066\u304A\u3089\u305A\u3001\u30B9\u30AD\u30FC\u30DE\u3067\u306F\u8FFD\u52A0\u306E\u9805\u76EE\u304C\u8A31\u53EF\u3055\u308C\u3066\u3044\u307E\u305B\u3093 +additionalProperties = \u30D7\u30ED\u30D1\u30C6\u30A3 ''{0}'' \u304C\u30B9\u30AD\u30FC\u30DE\u3067\u5B9A\u7FA9\u3055\u308C\u3066\u304A\u3089\u305A\u3001\u30B9\u30AD\u30FC\u30DE\u3067\u306F\u8FFD\u52A0\u306E\u30D7\u30ED\u30D1\u30C6\u30A3\u304C\u8A31\u53EF\u3055\u308C\u3066\u3044\u307E\u305B\u3093 +allOf = \u3059\u3079\u3066\u306E\u30B9\u30AD\u30FC\u30DE {0} \u306B\u5BFE\u3057\u3066\u6709\u52B9\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 +anyOf = \u3044\u305A\u308C\u304B\u306E\u30B9\u30AD\u30FC\u30DE {0} \u306B\u5BFE\u3057\u3066\u6709\u52B9\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 +const = \u5B9A\u6570\u5024 ''{0}'' \u3067\u306A\u3051\u308C\u3070\u306A\u308A\u307E\u305B\u3093 +contains = \u6B21\u306E\u691C\u8A3C\u306B\u5408\u683C\u3059\u308B\u8981\u7D20\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u305B\u3093: {1} +contains.max = \u3053\u308C\u3089\u306E\u691C\u8A3C\u306B\u5408\u683C\u3059\u308B\u8981\u7D20\u306F\u6700\u5927\u3067\u3082 {0} \u500B\u542B\u307E\u308C\u3066\u3044\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059: {1} +contains.min = \u3053\u308C\u3089\u306E\u691C\u8A3C\u306B\u5408\u683C\u3059\u308B\u5C11\u306A\u304F\u3068\u3082 {0} \u500B\u306E\u8981\u7D20\u304C\u542B\u307E\u308C\u3066\u3044\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059: {1} +dependencies = \u4F9D\u5B58\u95A2\u4FC2 {0} \u306B\u30A8\u30E9\u30FC\u304C\u3042\u308A\u307E\u3059 +dependentRequired = \u30D7\u30ED\u30D1\u30C6\u30A3 ''{0}'' \u304C\u3042\u308A\u307E\u305B\u3093\u3002''{1}'' \u304C\u5B58\u5728\u3059\u308B\u305F\u3081\u3001\u4F9D\u5B58\u95A2\u4FC2\u304C\u5FC5\u8981\u3067\u3059\u3002 +dependentSchemas = {0}:dependentSchemas {0} \u306B\u30A8\u30E9\u30FC\u304C\u3042\u308A\u307E\u3059 +enum = \u5217\u6319\u578B {0} \u306B\u5024\u304C\u3042\u308A\u307E\u305B\u3093 +exclusiveMaximum = \u6392\u4ED6\u7684\u306A\u6700\u5927\u5024\u306F {0} \u3067\u306A\u3051\u308C\u3070\u306A\u308A\u307E\u305B\u3093 +exclusiveMinimum = \u6392\u4ED6\u7684\u306A\u6700\u5C0F\u5024\u306F {0} \u3067\u306A\u3051\u308C\u3070\u306A\u308A\u307E\u305B\u3093 +false = ''{0}'' \u306E\u30B9\u30AD\u30FC\u30DE\u306F false \u3067\u3059 +format = {0} \u30D1\u30BF\u30FC\u30F3 \u306B\u4E00\u81F4\u3057\u307E\u305B\u3093 +format.date = {0} \u30D1\u30BF\u30FC\u30F3\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6709\u52B9\u306A RFC 3339 \u306E\u5B8C\u5168\u306A\u65E5\u4ED8\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 +format.date-time = {0} \u30D1\u30BF\u30FC\u30F3\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6709\u52B9\u306A RFC 3339 \u65E5\u4ED8/\u6642\u523B\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 +format.duration = {0} \u30D1\u30BF\u30FC\u30F3\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6709\u52B9\u306A ISO 8601 \u671F\u9593\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 +format.email = {0} \u30D1\u30BF\u30FC\u30F3\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6709\u52B9\u306A RFC 5321 \u30E1\u30FC\u30EB\u30DC\u30C3\u30AF\u30B9\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 +format.ipv4 = {0} \u30D1\u30BF\u30FC\u30F3\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6709\u52B9\u306A RFC 2673 IP \u30A2\u30C9\u30EC\u30B9\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 +format.ipv6 = {0} \u30D1\u30BF\u30FC\u30F3\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6709\u52B9\u306A RFC 4291 IP \u30A2\u30C9\u30EC\u30B9\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 +format.idn-email = {0} \u30D1\u30BF\u30FC\u30F3\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6709\u52B9\u306A RFC 6531 \u30E1\u30FC\u30EB\u30DC\u30C3\u30AF\u30B9\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 +format.idn-hostname = {0} \u30D1\u30BF\u30FC\u30F3\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6709\u52B9\u306A RFC 5890 \u56FD\u969B\u5316\u30DB\u30B9\u30C8\u540D\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 +format.iri = {0} \u30D1\u30BF\u30FC\u30F3\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6709\u52B9\u306A RFC 3987 IRI \u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 +format.iri-reference = {0} \u30D1\u30BF\u30FC\u30F3\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6709\u52B9\u306A RFC 3987 IRI \u53C2\u7167\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 +format.uri = {0} \u30D1\u30BF\u30FC\u30F3\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6709\u52B9\u306A RFC 3986 URI \u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 +format.uri-reference = {0} \u30D1\u30BF\u30FC\u30F3\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6709\u52B9\u306A RFC 3986 URI \u53C2\u7167\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 +format.uri-template = {0} \u30D1\u30BF\u30FC\u30F3\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6709\u52B9\u306A RFC 6570 URI \u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 +format.uuid = {0} \u30D1\u30BF\u30FC\u30F3\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6709\u52B9\u306A RFC 4122 UUID \u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 +format.regex = {0} \u30D1\u30BF\u30FC\u30F3\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6709\u52B9\u306A ECMA-262 \u6B63\u898F\u8868\u73FE\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 +format.time = {0} \u30D1\u30BF\u30FC\u30F3\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6709\u52B9\u306A RFC 3339 \u6642\u523B\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 +format.hostname = {0} \u30D1\u30BF\u30FC\u30F3\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6709\u52B9\u306A RFC 1123 \u30DB\u30B9\u30C8\u540D\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 +format.json-pointer = {0} \u30D1\u30BF\u30FC\u30F3\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6709\u52B9\u306A RFC 6901 JSON \u30DD\u30A4\u30F3\u30BF\u30FC\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 +format.relative-json-pointer = {0} \u30D1\u30BF\u30FC\u30F3\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u6709\u52B9\u306A IETF \u76F8\u5BFE JSON \u30DD\u30A4\u30F3\u30BF\u30FC\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 +format.unknown = \u4E0D\u660E\u306A\u5F62\u5F0F ''{0}'' \u304C\u3042\u308A\u307E\u3059 +id = ''{0}'' \u306F\u6709\u52B9\u306A {1} \u3067\u306F\u3042\u308A\u307E\u305B\u3093 +items = \u30A4\u30F3\u30C7\u30C3\u30AF\u30B9 ''{0}'' \u304C\u30B9\u30AD\u30FC\u30DE\u3067\u5B9A\u7FA9\u3055\u308C\u3066\u304A\u3089\u305A\u3001\u30B9\u30AD\u30FC\u30DE\u3067\u306F\u8FFD\u52A0\u306E\u9805\u76EE\u304C\u8A31\u53EF\u3055\u308C\u3066\u3044\u307E\u305B\u3093 +maxContains = {0} \u306B\u306F\u8CA0\u3067\u306A\u3044\u6574\u6570\u3092\u6307\u5B9A\u3059\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 +maxItems = \u30A2\u30A4\u30C6\u30E0\u306F\u6700\u5927\u3067\u3082 {0} \u500B\u5FC5\u8981\u3067\u3059\u304C\u3001{1} \u304C\u898B\u3064\u304B\u308A\u307E\u3057\u305F +maxLength = \u9577\u3055\u306F\u6700\u5927 {0} \u6587\u5B57\u3067\u306A\u3051\u308C\u3070\u306A\u308A\u307E\u305B\u3093 +maxProperties = \u6700\u5927\u3067 {0} \u500B\u306E\u30D7\u30ED\u30D1\u30C6\u30A3\u304C\u5FC5\u8981\u3067\u3059 +maximum = \u6700\u5927\u5024\u306F {0} \u3067\u306A\u3051\u308C\u3070\u306A\u308A\u307E\u305B\u3093 +minContains = {0} \u306B\u306F\u8CA0\u3067\u306A\u3044\u6574\u6570\u3092\u6307\u5B9A\u3059\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 +minContainsVsMaxContains = minContains \u306F {0} \u306E maxContains \u4EE5\u4E0B\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 +minItems = \u5C11\u306A\u304F\u3068\u3082 {0} \u500B\u306E\u9805\u76EE\u304C\u5FC5\u8981\u3067\u3059\u304C\u3001{1} \u304C\u898B\u3064\u304B\u308A\u307E\u3057\u305F +minLength = \u5C11\u306A\u304F\u3068\u3082 {0} \u6587\u5B57\u306E\u9577\u3055\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 +minProperties = \u5C11\u306A\u304F\u3068\u3082 {0} \u500B\u306E\u30D7\u30ED\u30D1\u30C6\u30A3\u304C\u5FC5\u8981\u3067\u3059 +minimum = \u6700\u5C0F\u5024\u306F {0} \u3067\u306A\u3051\u308C\u3070\u306A\u308A\u307E\u305B\u3093 +multipleOf = {0} \u306E\u500D\u6570\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 +not = \u30B9\u30AD\u30FC\u30DE {0} \u306B\u5BFE\u3057\u3066\u6709\u52B9\u3067\u3042\u3063\u3066\u306F\u306A\u308A\u307E\u305B\u3093 +notAllowed = \u30D7\u30ED\u30D1\u30C6\u30A3 ''{0}'' \u306F\u8A31\u53EF\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u304C\u3001\u30C7\u30FC\u30BF\u5185\u306B\u3042\u308A\u307E\u3059 +oneOf = 1 \u3064\u306E\u30B9\u30AD\u30FC\u30DE\u306B\u5BFE\u3057\u3066\u306E\u307F\u6709\u52B9\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u304C\u3001{0} \u306F\u6709\u52B9\u3067\u3059 +oneOf.indexes = 1 \u3064\u306E\u30B9\u30AD\u30FC\u30DE\u306B\u5BFE\u3057\u3066\u306E\u307F\u6709\u52B9\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u304C\u3001{0} \u306F\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9 ''{1}'' \u306B\u5BFE\u3057\u3066\u6709\u52B9\u3067\u3059 +pattern = \u6B63\u898F\u8868\u73FE\u30D1\u30BF\u30FC\u30F3 {0} \u306B\u4E00\u81F4\u3057\u307E\u305B\u3093 +patternProperties = ''\u30D1\u30BF\u30FC\u30F3 \u30D7\u30ED\u30D1\u30C6\u30A3'' \u306B\u30A8\u30E9\u30FC\u304C\u3042\u308A\u307E\u3059 +prefixItems = \u3053\u306E\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u3067\u30D0\u30EA\u30C7\u30FC\u30BF\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093 +properties = ''\u30D7\u30ED\u30D1\u30C6\u30A3'' \u306B\u30A8\u30E9\u30FC\u304C\u3042\u308A\u307E\u3059 +propertyNames = \u30D7\u30ED\u30D1\u30C6\u30A3 ''{0}'' \u306E\u540D\u524D\u304C\u7121\u52B9\u3067\u3059: {1} +readOnly = \u306F\u8AAD\u307F\u53D6\u308A\u5C02\u7528\u30D5\u30A3\u30FC\u30EB\u30C9\u3067\u3059\u3002\u5909\u66F4\u3067\u304D\u307E\u305B\u3093 +required = \u5FC5\u9808\u30D7\u30ED\u30D1\u30C6\u30A3 ''{0}'' \u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093 +type = {0} \u304C\u898B\u3064\u304B\u308A\u307E\u3057\u305F\u3001{1} \u304C\u4E88\u671F\u3055\u308C\u307E\u3057\u305F +unevaluatedItems = \u30A4\u30F3\u30C7\u30C3\u30AF\u30B9 ''{0}'' \u306F\u8A55\u4FA1\u3055\u308C\u3066\u304A\u3089\u305A\u3001\u30B9\u30AD\u30FC\u30DE\u306F\u672A\u8A55\u4FA1\u306E\u9805\u76EE\u3092\u8A31\u53EF\u3057\u3066\u3044\u307E\u305B\u3093 +unevaluatedProperties = \u30D7\u30ED\u30D1\u30C6\u30A3 ''{0}'' \u306F\u8A55\u4FA1\u3055\u308C\u3066\u304A\u3089\u305A\u3001\u30B9\u30AD\u30FC\u30DE\u306F\u672A\u8A55\u4FA1\u306E\u30D7\u30ED\u30D1\u30C6\u30A3\u3092\u8A31\u53EF\u3057\u3066\u3044\u307E\u305B\u3093 +unionType = {0} \u304C\u898B\u3064\u304B\u308A\u307E\u3057\u305F\u3001{1} \u304C\u4E88\u671F\u3055\u308C\u307E\u3057\u305F +uniqueItems = \u914D\u5217\u306B\u306F\u4E00\u610F\u306E\u9805\u76EE\u306E\u307F\u3092\u542B\u3081\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059 +writeOnly = \u306F\u66F8\u304D\u8FBC\u307F\u5C02\u7528\u30D5\u30A3\u30FC\u30EB\u30C9\u3067\u3059\u3002\u30C7\u30FC\u30BF\u306B\u306F\u8868\u793A\u3067\u304D\u307E\u305B\u3093\u3002 +contentEncoding = \u30B3\u30F3\u30C6\u30F3\u30C4 \u30A8\u30F3\u30B3\u30FC\u30C7\u30A3\u30F3\u30B0 {0} \u3068\u4E00\u81F4\u3057\u307E\u305B\u3093 +contentMediaType = \u30B3\u30F3\u30C6\u30F3\u30C4\u3067\u306F\u3042\u308A\u307E\u305B\u3093 diff --git a/src/main/resources/jsv-messages_ko.properties b/src/main/resources/jsv-messages_ko.properties index 7c03d5d00..9a61c08aa 100644 --- a/src/main/resources/jsv-messages_ko.properties +++ b/src/main/resources/jsv-messages_ko.properties @@ -1,70 +1,70 @@ -$ref = {0}: ''refs''\uC5D0 \uC624\uB958\uAC00 \uC788\uC2B5\uB2C8\uB2E4. -additionalItems = {0}: \uC0C9\uC778 ''{1}''\uC774(\uAC00) \uC2A4\uD0A4\uB9C8\uC5D0 \uC815\uC758\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC73C\uBA70 \uC2A4\uD0A4\uB9C8\uAC00 \uCD94\uAC00 \uD56D\uBAA9\uC744 \uD5C8\uC6A9\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. -additionalProperties = {0}: ''{1}'' \uC18D\uC131\uC774 \uC2A4\uD0A4\uB9C8\uC5D0 \uC815\uC758\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC73C\uBA70 \uC2A4\uD0A4\uB9C8\uAC00 \uCD94\uAC00 \uC18D\uC131\uC744 \uD5C8\uC6A9\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. -allOf = {0}: \uBAA8\uB4E0 \uC2A4\uD0A4\uB9C8\uC5D0 \uC720\uD6A8\uD574\uC57C \uD569\uB2C8\uB2E4. {1} -anyOf = {0}: \uBAA8\uB4E0 \uC2A4\uD0A4\uB9C8 {1}\uC5D0 \uC720\uD6A8\uD574\uC57C \uD569\uB2C8\uB2E4. -const = {0}: \uC0C1\uC218 \uAC12 ''{1}''\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4. -contains = {0}: \uB2E4\uC74C \uC720\uD6A8\uC131 \uAC80\uC0AC\uB97C \uD1B5\uACFC\uD55C \uC694\uC18C\uB97C \uD3EC\uD568\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4: {2} -contains.max = {0}: \uB2E4\uC74C \uC720\uD6A8\uC131 \uAC80\uC0AC\uB97C \uD1B5\uACFC\uD558\uB294 \uCD5C\uB300 {1}\uAC1C\uC758 \uC694\uC18C\uB97C \uD3EC\uD568\uD574\uC57C \uD569\uB2C8\uB2E4: {2} -contains.min = {0}: \uB2E4\uC74C \uC720\uD6A8\uC131 \uAC80\uC0AC\uB97C \uD1B5\uACFC\uD558\uB294 \uC694\uC18C\uAC00 \uCD5C\uC18C\uD55C {1}\uAC1C \uD3EC\uD568\uB418\uC5B4\uC57C \uD569\uB2C8\uB2E4: {2} -dependencies = {0}: \uC885\uC18D\uC131 {1}\uC5D0 \uC624\uB958\uAC00 \uC788\uC2B5\uB2C8\uB2E4. -dependentRequired = {0}: ''{2}''\uC774(\uAC00) \uC874\uC7AC\uD558\uAE30 \uB54C\uBB38\uC5D0 \uC885\uC18D \uD544\uC218\uC778 ''{1}'' \uC18D\uC131\uC774 \uB204\uB77D\uB418\uC5C8\uC2B5\uB2C8\uB2E4. -dependentSchemas = {0}:dependentSchemas {1}\uC5D0 \uC624\uB958\uAC00 \uC788\uC2B5\uB2C8\uB2E4. -enum = {0}: \uC5F4\uAC70\uD615 {1}\uC5D0 \uAC12\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. -exclusiveMaximum = {0}: {1}\uC758 \uBC30\uD0C0\uC801 \uCD5C\uB300\uAC12\uC744 \uAC00\uC838\uC57C \uD569\uB2C8\uB2E4. -exclusiveMinimum = {0}: {1}\uC758 \uBC30\uD0C0\uC801 \uCD5C\uC18C\uAC12\uC744 \uAC00\uC838\uC57C \uD569\uB2C8\uB2E4. -false = {0}: ''{1}''\uC5D0 \uB300\uD55C \uC2A4\uD0A4\uB9C8\uAC00 false\uC785\uB2C8\uB2E4. -format = {0}: {1} \uD328\uD134 {2}\uACFC(\uC640) \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. -format.date = {0}: {1} \uD328\uD134\uACFC \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC720\uD6A8\uD55C RFC 3339 \uC804\uCCB4 \uB0A0\uC9DC\uC5EC\uC57C \uD569\uB2C8\uB2E4. -format.date-time = {0}: {1} \uD328\uD134\uACFC \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC720\uD6A8\uD55C RFC 3339 \uB0A0\uC9DC-\uC2DC\uAC04\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4. -format.duration = {0}: {1} \uD328\uD134\uACFC \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC720\uD6A8\uD55C ISO 8601 \uAE30\uAC04\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4. -format.email = {0}: {1} \uD328\uD134\uACFC \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC720\uD6A8\uD55C RFC 5321 \uBA54\uC77C\uBC15\uC2A4\uC5EC\uC57C \uD569\uB2C8\uB2E4. -format.ipv4 = {0}: {1} \uD328\uD134\uACFC \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC720\uD6A8\uD55C RFC 2673 IP \uC8FC\uC18C\uC5EC\uC57C \uD569\uB2C8\uB2E4. -format.ipv6 = {0}: {1} \uD328\uD134\uACFC \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC720\uD6A8\uD55C RFC 4291 IP \uC8FC\uC18C\uC5EC\uC57C \uD569\uB2C8\uB2E4. -format.idn-email = {0}: {1} \uD328\uD134\uACFC \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC720\uD6A8\uD55C RFC 6531 \uC0AC\uC11C\uD568\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4. -format.idn-hostname = {0}: {1} \uD328\uD134\uACFC \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC720\uD6A8\uD55C RFC 5890 \uAD6D\uC81C\uD654 \uD638\uC2A4\uD2B8 \uC774\uB984\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4. -format.iri = {0}: {1} \uD328\uD134\uACFC \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC720\uD6A8\uD55C RFC 3987 IRI\uC5EC\uC57C \uD569\uB2C8\uB2E4. -format.iri-reference = {0}: {1} \uD328\uD134\uACFC \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC720\uD6A8\uD55C RFC 3987 IRI \uCC38\uC870\uC5EC\uC57C \uD569\uB2C8\uB2E4. -format.uri = {0}: {1} \uD328\uD134\uACFC \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC720\uD6A8\uD55C RFC 3986 URI\uC5EC\uC57C \uD569\uB2C8\uB2E4. -format.uri-reference = {0}: {1} \uD328\uD134\uACFC \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC720\uD6A8\uD55C RFC 3986 URI \uCC38\uC870\uC5EC\uC57C \uD569\uB2C8\uB2E4. -format.uri-template = {0}: {1} \uD328\uD134\uACFC \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC720\uD6A8\uD55C RFC 6570 URI \uD15C\uD50C\uB9BF\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4. -format.uuid = {0}: {1} \uD328\uD134\uACFC \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC720\uD6A8\uD55C RFC 4122 UUID\uC5EC\uC57C \uD569\uB2C8\uB2E4. -format.regex = {0}: {1} \uD328\uD134\uACFC \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC720\uD6A8\uD55C ECMA-262 \uC815\uADDC \uD45C\uD604\uC2DD\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4. -format.time = {0}: {1} \uD328\uD134\uACFC \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC720\uD6A8\uD55C RFC 3339 \uC2DC\uAC04\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4. -format.hostname = {0}: {1} \uD328\uD134\uACFC \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC720\uD6A8\uD55C RFC 1123 \uD638\uC2A4\uD2B8 \uC774\uB984\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4. -format.json-pointer = {0}: {1} \uD328\uD134\uACFC \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC720\uD6A8\uD55C RFC 6901 JSON \uD3EC\uC778\uD130\uC5EC\uC57C \uD569\uB2C8\uB2E4. -format.relative-json-pointer = {0}: {1} \uD328\uD134\uACFC \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC720\uD6A8\uD55C IETF \uC0C1\uB300 JSON \uD3EC\uC778\uD130\uC5EC\uC57C \uD569\uB2C8\uB2E4. -format.unknown = {0}: \uC54C \uC218 \uC5C6\uB294 \uD615\uC2DD ''{1}''\uC774(\uAC00) \uC788\uC2B5\uB2C8\uB2E4. -id = {0}: ''{1}''\uC740(\uB294) \uC720\uD6A8\uD55C {2}\uC774 \uC544\uB2D9\uB2C8\uB2E4. -items = {0}: \uC0C9\uC778 ''{1}''\uC774(\uAC00) \uC2A4\uD0A4\uB9C8\uC5D0 \uC815\uC758\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC73C\uBA70 \uC2A4\uD0A4\uB9C8\uAC00 \uCD94\uAC00 \uD56D\uBAA9\uC744 \uD5C8\uC6A9\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. -maxContains = {0}: {1}\uC5D0\uC11C \uC74C\uC218\uAC00 \uC544\uB2CC \uC815\uC218\uC5EC\uC57C \uD569\uB2C8\uB2E4. -maxItems = {0}: \uCD5C\uB300 {1}\uAC1C\uC758 \uD56D\uBAA9\uC774 \uC788\uC5B4\uC57C \uD558\uC9C0\uB9CC {2}\uAC1C\uB97C \uCC3E\uC558\uC2B5\uB2C8\uB2E4. -maxLength = {0}: \uAE38\uC774\uB294 \uCD5C\uB300 {1}\uC790\uC5EC\uC57C \uD569\uB2C8\uB2E4. -maxProperties = {0}: \uCD5C\uB300 {1}\uAC1C\uC758 \uC18D\uC131\uC744 \uAC00\uC838\uC57C \uD569\uB2C8\uB2E4. -maximum = {0}: \uCD5C\uB300\uAC12\uC740 {1}\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4. -minContains = {0}: {1}\uC5D0\uC11C \uC74C\uC218\uAC00 \uC544\uB2CC \uC815\uC218\uC5EC\uC57C \uD569\uB2C8\uB2E4. -minContainsVsMaxContains = {0}: minContains\uB294 {1}\uC758 maxContains\uBCF4\uB2E4 \uC791\uAC70\uB098 \uAC19\uC544\uC57C \uD569\uB2C8\uB2E4. -minItems = {0}: \uCD5C\uC18C {1}\uAC1C\uC758 \uD56D\uBAA9\uC774 \uC788\uC5B4\uC57C \uD558\uC9C0\uB9CC {2}\uAC1C\uB97C \uCC3E\uC558\uC2B5\uB2C8\uB2E4. -minLength = {0}: \uAE38\uC774\uB294 {1}\uC790 \uC774\uC0C1\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4. -minProperties = {0}: \uCD5C\uC18C\uD55C {1}\uAC1C\uC758 \uC18D\uC131\uC774 \uC788\uC5B4\uC57C \uD569\uB2C8\uB2E4. -minimum = {0}: \uCD5C\uC18C\uAC12\uC740 {1}\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4. -multipleOf = {0}: {1}\uC758 \uBC30\uC218\uC5EC\uC57C \uD569\uB2C8\uB2E4. -not = {0}: \uC2A4\uD0A4\uB9C8 {1}\uC5D0 \uC720\uD6A8\uD558\uC9C0 \uC54A\uC544\uC57C \uD569\uB2C8\uB2E4. -notAllowed = {0}: ''{1}'' \uC18D\uC131\uC740 \uD5C8\uC6A9\uB418\uC9C0 \uC54A\uC9C0\uB9CC \uB370\uC774\uD130\uC5D0 \uC788\uC2B5\uB2C8\uB2E4. -oneOf = {0}: \uD558\uB098\uC758 \uC2A4\uD0A4\uB9C8\uC5D0\uB9CC \uC720\uD6A8\uD574\uC57C \uD558\uC9C0\uB9CC {1}\uC740(\uB294) \uC720\uD6A8\uD569\uB2C8\uB2E4. -oneOf.indexes = {0}: \uD558\uB098\uC758 \uC2A4\uD0A4\uB9C8\uC5D0\uB9CC \uC720\uD6A8\uD574\uC57C \uD558\uC9C0\uB9CC {1}\uC740(\uB294) \uC0C9\uC778 ''{2}''\uC5D0 \uC720\uD6A8\uD569\uB2C8\uB2E4. -pattern = {0}: \uC815\uADDC\uC2DD \uD328\uD134 {1}\uACFC(\uC640) \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. -patternProperties = {0}: ''\uD328\uD134 \uC18D\uC131''\uC5D0 \uC77C\uBD80 \uC624\uB958\uAC00 \uC788\uC2B5\uB2C8\uB2E4. -prefixItems = {0}: \uC774 \uC0C9\uC778\uC5D0\uC11C \uC720\uD6A8\uC131 \uAC80\uC0AC\uAE30\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. -properties = {0}: ''\uC18D\uC131''\uC5D0 \uC624\uB958\uAC00 \uC788\uC2B5\uB2C8\uB2E4. -propertyNames = {0}: ''{1}'' \uC18D\uC131 \uC774\uB984\uC774 \uC720\uD6A8\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4: {2} -readOnly = {0}: \uC77D\uAE30 \uC804\uC6A9 \uD544\uB4DC\uC774\uBBC0\uB85C \uBCC0\uACBD\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. -required = {0}: \uD544\uC218 \uC18D\uC131 ''{1}''\uC744(\uB97C) \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. -type = {0}: {1} \uBC1C\uACAC, {2} \uC608\uC0C1 -unevaluatedItems = {0}: ''{1}'' \uC0C9\uC778\uC740 \uD3C9\uAC00\uB418\uC9C0 \uC54A\uC73C\uBA70 \uC2A4\uD0A4\uB9C8\uB294 \uD3C9\uAC00\uB418\uC9C0 \uC54A\uC740 \uD56D\uBAA9\uC744 \uD5C8\uC6A9\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. -unevaluatedProperties = {0}: ''{1}'' \uC18D\uC131\uC740 \uD3C9\uAC00\uB418\uC9C0 \uC54A\uC73C\uBA70 \uC2A4\uD0A4\uB9C8\uB294 \uD3C9\uAC00\uB418\uC9C0 \uC54A\uC740 \uC18D\uC131\uC744 \uD5C8\uC6A9\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. -unionType = {0}: {1} \uBC1C\uACAC, {2} \uC608\uC0C1 -uniqueItems = {0}: \uBC30\uC5F4\uC5D0 \uACE0\uC720\uD55C \uD56D\uBAA9\uB9CC \uC788\uC5B4\uC57C \uD569\uB2C8\uB2E4. -writeOnly = {0}: \uC4F0\uAE30 \uC804\uC6A9 \uD544\uB4DC\uC774\uBBC0\uB85C \uB370\uC774\uD130\uC5D0 \uB098\uD0C0\uB0A0 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. -contentEncoding = {0}: \uCF58\uD150\uCE20 \uC778\uCF54\uB529 {1}\uACFC(\uC640) \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. -contentMediaType = {0}: \uCF58\uD150\uCE20\uAC00 \uC544\uB2D9\uB2C8\uB2E4. +$ref = ''refs''\uC5D0 \uC624\uB958\uAC00 \uC788\uC2B5\uB2C8\uB2E4. +additionalItems = \uC0C9\uC778 ''{0}''\uC774(\uAC00) \uC2A4\uD0A4\uB9C8\uC5D0 \uC815\uC758\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC73C\uBA70 \uC2A4\uD0A4\uB9C8\uAC00 \uCD94\uAC00 \uD56D\uBAA9\uC744 \uD5C8\uC6A9\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. +additionalProperties = ''{0}'' \uC18D\uC131\uC774 \uC2A4\uD0A4\uB9C8\uC5D0 \uC815\uC758\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC73C\uBA70 \uC2A4\uD0A4\uB9C8\uAC00 \uCD94\uAC00 \uC18D\uC131\uC744 \uD5C8\uC6A9\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. +allOf = \uBAA8\uB4E0 \uC2A4\uD0A4\uB9C8\uC5D0 \uC720\uD6A8\uD574\uC57C \uD569\uB2C8\uB2E4. {0} +anyOf = \uBAA8\uB4E0 \uC2A4\uD0A4\uB9C8 {0}\uC5D0 \uC720\uD6A8\uD574\uC57C \uD569\uB2C8\uB2E4. +const = \uC0C1\uC218 \uAC12 ''{0}''\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4. +contains = \uB2E4\uC74C \uC720\uD6A8\uC131 \uAC80\uC0AC\uB97C \uD1B5\uACFC\uD55C \uC694\uC18C\uB97C \uD3EC\uD568\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4: {1} +contains.max = \uB2E4\uC74C \uC720\uD6A8\uC131 \uAC80\uC0AC\uB97C \uD1B5\uACFC\uD558\uB294 \uCD5C\uB300 {0}\uAC1C\uC758 \uC694\uC18C\uB97C \uD3EC\uD568\uD574\uC57C \uD569\uB2C8\uB2E4: {1} +contains.min = \uB2E4\uC74C \uC720\uD6A8\uC131 \uAC80\uC0AC\uB97C \uD1B5\uACFC\uD558\uB294 \uC694\uC18C\uAC00 \uCD5C\uC18C\uD55C {0}\uAC1C \uD3EC\uD568\uB418\uC5B4\uC57C \uD569\uB2C8\uB2E4: {1} +dependencies = \uC885\uC18D\uC131 {0}\uC5D0 \uC624\uB958\uAC00 \uC788\uC2B5\uB2C8\uB2E4. +dependentRequired = ''{1}''\uC774(\uAC00) \uC874\uC7AC\uD558\uAE30 \uB54C\uBB38\uC5D0 \uC885\uC18D \uD544\uC218\uC778 ''{0}'' \uC18D\uC131\uC774 \uB204\uB77D\uB418\uC5C8\uC2B5\uB2C8\uB2E4. +dependentSchemas = {0}:dependentSchemas {0}\uC5D0 \uC624\uB958\uAC00 \uC788\uC2B5\uB2C8\uB2E4. +enum = \uC5F4\uAC70\uD615 {0}\uC5D0 \uAC12\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. +exclusiveMaximum = {0}\uC758 \uBC30\uD0C0\uC801 \uCD5C\uB300\uAC12\uC744 \uAC00\uC838\uC57C \uD569\uB2C8\uB2E4. +exclusiveMinimum = {0}\uC758 \uBC30\uD0C0\uC801 \uCD5C\uC18C\uAC12\uC744 \uAC00\uC838\uC57C \uD569\uB2C8\uB2E4. +false = ''{0}''\uC5D0 \uB300\uD55C \uC2A4\uD0A4\uB9C8\uAC00 false\uC785\uB2C8\uB2E4. +format = {0} \uD328\uD134 \uACFC(\uC640) \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. +format.date = {0} \uD328\uD134\uACFC \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC720\uD6A8\uD55C RFC 3339 \uC804\uCCB4 \uB0A0\uC9DC\uC5EC\uC57C \uD569\uB2C8\uB2E4. +format.date-time = {0} \uD328\uD134\uACFC \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC720\uD6A8\uD55C RFC 3339 \uB0A0\uC9DC-\uC2DC\uAC04\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4. +format.duration = {0} \uD328\uD134\uACFC \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC720\uD6A8\uD55C ISO 8601 \uAE30\uAC04\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4. +format.email = {0} \uD328\uD134\uACFC \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC720\uD6A8\uD55C RFC 5321 \uBA54\uC77C\uBC15\uC2A4\uC5EC\uC57C \uD569\uB2C8\uB2E4. +format.ipv4 = {0} \uD328\uD134\uACFC \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC720\uD6A8\uD55C RFC 2673 IP \uC8FC\uC18C\uC5EC\uC57C \uD569\uB2C8\uB2E4. +format.ipv6 = {0} \uD328\uD134\uACFC \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC720\uD6A8\uD55C RFC 4291 IP \uC8FC\uC18C\uC5EC\uC57C \uD569\uB2C8\uB2E4. +format.idn-email = {0} \uD328\uD134\uACFC \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC720\uD6A8\uD55C RFC 6531 \uC0AC\uC11C\uD568\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4. +format.idn-hostname = {0} \uD328\uD134\uACFC \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC720\uD6A8\uD55C RFC 5890 \uAD6D\uC81C\uD654 \uD638\uC2A4\uD2B8 \uC774\uB984\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4. +format.iri = {0} \uD328\uD134\uACFC \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC720\uD6A8\uD55C RFC 3987 IRI\uC5EC\uC57C \uD569\uB2C8\uB2E4. +format.iri-reference = {0} \uD328\uD134\uACFC \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC720\uD6A8\uD55C RFC 3987 IRI \uCC38\uC870\uC5EC\uC57C \uD569\uB2C8\uB2E4. +format.uri = {0} \uD328\uD134\uACFC \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC720\uD6A8\uD55C RFC 3986 URI\uC5EC\uC57C \uD569\uB2C8\uB2E4. +format.uri-reference = {0} \uD328\uD134\uACFC \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC720\uD6A8\uD55C RFC 3986 URI \uCC38\uC870\uC5EC\uC57C \uD569\uB2C8\uB2E4. +format.uri-template = {0} \uD328\uD134\uACFC \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC720\uD6A8\uD55C RFC 6570 URI \uD15C\uD50C\uB9BF\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4. +format.uuid = {0} \uD328\uD134\uACFC \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC720\uD6A8\uD55C RFC 4122 UUID\uC5EC\uC57C \uD569\uB2C8\uB2E4. +format.regex = {0} \uD328\uD134\uACFC \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC720\uD6A8\uD55C ECMA-262 \uC815\uADDC \uD45C\uD604\uC2DD\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4. +format.time = {0} \uD328\uD134\uACFC \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC720\uD6A8\uD55C RFC 3339 \uC2DC\uAC04\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4. +format.hostname = {0} \uD328\uD134\uACFC \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC720\uD6A8\uD55C RFC 1123 \uD638\uC2A4\uD2B8 \uC774\uB984\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4. +format.json-pointer = {0} \uD328\uD134\uACFC \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC720\uD6A8\uD55C RFC 6901 JSON \uD3EC\uC778\uD130\uC5EC\uC57C \uD569\uB2C8\uB2E4. +format.relative-json-pointer = {0} \uD328\uD134\uACFC \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC720\uD6A8\uD55C IETF \uC0C1\uB300 JSON \uD3EC\uC778\uD130\uC5EC\uC57C \uD569\uB2C8\uB2E4. +format.unknown = \uC54C \uC218 \uC5C6\uB294 \uD615\uC2DD ''{0}''\uC774(\uAC00) \uC788\uC2B5\uB2C8\uB2E4. +id = ''{0}''\uC740(\uB294) \uC720\uD6A8\uD55C {1}\uC774 \uC544\uB2D9\uB2C8\uB2E4. +items = \uC0C9\uC778 ''{0}''\uC774(\uAC00) \uC2A4\uD0A4\uB9C8\uC5D0 \uC815\uC758\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC73C\uBA70 \uC2A4\uD0A4\uB9C8\uAC00 \uCD94\uAC00 \uD56D\uBAA9\uC744 \uD5C8\uC6A9\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. +maxContains = {0}\uC5D0\uC11C \uC74C\uC218\uAC00 \uC544\uB2CC \uC815\uC218\uC5EC\uC57C \uD569\uB2C8\uB2E4. +maxItems = \uCD5C\uB300 {0}\uAC1C\uC758 \uD56D\uBAA9\uC774 \uC788\uC5B4\uC57C \uD558\uC9C0\uB9CC {1}\uAC1C\uB97C \uCC3E\uC558\uC2B5\uB2C8\uB2E4. +maxLength = \uAE38\uC774\uB294 \uCD5C\uB300 {0}\uC790\uC5EC\uC57C \uD569\uB2C8\uB2E4. +maxProperties = \uCD5C\uB300 {0}\uAC1C\uC758 \uC18D\uC131\uC744 \uAC00\uC838\uC57C \uD569\uB2C8\uB2E4. +maximum = \uCD5C\uB300\uAC12\uC740 {0}\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4. +minContains = {0}\uC5D0\uC11C \uC74C\uC218\uAC00 \uC544\uB2CC \uC815\uC218\uC5EC\uC57C \uD569\uB2C8\uB2E4. +minContainsVsMaxContains = minContains\uB294 {0}\uC758 maxContains\uBCF4\uB2E4 \uC791\uAC70\uB098 \uAC19\uC544\uC57C \uD569\uB2C8\uB2E4. +minItems = \uCD5C\uC18C {0}\uAC1C\uC758 \uD56D\uBAA9\uC774 \uC788\uC5B4\uC57C \uD558\uC9C0\uB9CC {1}\uAC1C\uB97C \uCC3E\uC558\uC2B5\uB2C8\uB2E4. +minLength = \uAE38\uC774\uB294 {0}\uC790 \uC774\uC0C1\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4. +minProperties = \uCD5C\uC18C\uD55C {0}\uAC1C\uC758 \uC18D\uC131\uC774 \uC788\uC5B4\uC57C \uD569\uB2C8\uB2E4. +minimum = \uCD5C\uC18C\uAC12\uC740 {0}\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4. +multipleOf = {0}\uC758 \uBC30\uC218\uC5EC\uC57C \uD569\uB2C8\uB2E4. +not = \uC2A4\uD0A4\uB9C8 {0}\uC5D0 \uC720\uD6A8\uD558\uC9C0 \uC54A\uC544\uC57C \uD569\uB2C8\uB2E4. +notAllowed = ''{0}'' \uC18D\uC131\uC740 \uD5C8\uC6A9\uB418\uC9C0 \uC54A\uC9C0\uB9CC \uB370\uC774\uD130\uC5D0 \uC788\uC2B5\uB2C8\uB2E4. +oneOf = \uD558\uB098\uC758 \uC2A4\uD0A4\uB9C8\uC5D0\uB9CC \uC720\uD6A8\uD574\uC57C \uD558\uC9C0\uB9CC {0}\uC740(\uB294) \uC720\uD6A8\uD569\uB2C8\uB2E4. +oneOf.indexes = \uD558\uB098\uC758 \uC2A4\uD0A4\uB9C8\uC5D0\uB9CC \uC720\uD6A8\uD574\uC57C \uD558\uC9C0\uB9CC {0}\uC740(\uB294) \uC0C9\uC778 ''{1}''\uC5D0 \uC720\uD6A8\uD569\uB2C8\uB2E4. +pattern = \uC815\uADDC\uC2DD \uD328\uD134 {0}\uACFC(\uC640) \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. +patternProperties = ''\uD328\uD134 \uC18D\uC131''\uC5D0 \uC77C\uBD80 \uC624\uB958\uAC00 \uC788\uC2B5\uB2C8\uB2E4. +prefixItems = \uC774 \uC0C9\uC778\uC5D0\uC11C \uC720\uD6A8\uC131 \uAC80\uC0AC\uAE30\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. +properties = ''\uC18D\uC131''\uC5D0 \uC624\uB958\uAC00 \uC788\uC2B5\uB2C8\uB2E4. +propertyNames = ''{0}'' \uC18D\uC131 \uC774\uB984\uC774 \uC720\uD6A8\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4: {1} +readOnly = \uC77D\uAE30 \uC804\uC6A9 \uD544\uB4DC\uC774\uBBC0\uB85C \uBCC0\uACBD\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. +required = \uD544\uC218 \uC18D\uC131 ''{0}''\uC744(\uB97C) \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. +type = {0} \uBC1C\uACAC, {1} \uC608\uC0C1 +unevaluatedItems = ''{0}'' \uC0C9\uC778\uC740 \uD3C9\uAC00\uB418\uC9C0 \uC54A\uC73C\uBA70 \uC2A4\uD0A4\uB9C8\uB294 \uD3C9\uAC00\uB418\uC9C0 \uC54A\uC740 \uD56D\uBAA9\uC744 \uD5C8\uC6A9\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. +unevaluatedProperties = ''{0}'' \uC18D\uC131\uC740 \uD3C9\uAC00\uB418\uC9C0 \uC54A\uC73C\uBA70 \uC2A4\uD0A4\uB9C8\uB294 \uD3C9\uAC00\uB418\uC9C0 \uC54A\uC740 \uC18D\uC131\uC744 \uD5C8\uC6A9\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. +unionType = {0} \uBC1C\uACAC, {1} \uC608\uC0C1 +uniqueItems = \uBC30\uC5F4\uC5D0 \uACE0\uC720\uD55C \uD56D\uBAA9\uB9CC \uC788\uC5B4\uC57C \uD569\uB2C8\uB2E4. +writeOnly = \uC4F0\uAE30 \uC804\uC6A9 \uD544\uB4DC\uC774\uBBC0\uB85C \uB370\uC774\uD130\uC5D0 \uB098\uD0C0\uB0A0 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. +contentEncoding = \uCF58\uD150\uCE20 \uC778\uCF54\uB529 {0}\uACFC(\uC640) \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. +contentMediaType = \uCF58\uD150\uCE20\uAC00 \uC544\uB2D9\uB2C8\uB2E4. diff --git a/src/main/resources/jsv-messages_nb.properties b/src/main/resources/jsv-messages_nb.properties index 2a9437008..b536ed4f1 100644 --- a/src/main/resources/jsv-messages_nb.properties +++ b/src/main/resources/jsv-messages_nb.properties @@ -1,70 +1,70 @@ -$ref = {0}: har en feil med ''refs'' -additionalItems = {0}: indeks ''{1}'' er ikke definert i skjemaet og skjemaet tillater ikke flere elementer -additionalProperties = {0}: egenskapen ''{1}'' er ikke definert i skjemaet og skjemaet tillater ikke ytterligere egenskaper -allOf = {0}: må være gyldig for alle skjemaene {1} -anyOf = {0}: må være gyldig for alle skjemaene {1} -const = {0}: må være konstantverdien ''{1}'' -contains = {0}: inneholder ikke et element som består disse valideringene: {2} -contains.max = {0}: må inneholde maksimalt {1} element(er) som består disse valideringene: {2} -contains.min = {0}: må inneholde minst {1} element(er) som består disse valideringene: {2} -dependencies = {0}: har en feil med avhengigheter {1} -dependentRequired = {0}: har en manglende egenskap ''{1}'' som er avhengig nødvendig fordi ''{2}'' er tilstede -dependentSchemas = {0}: har en feil med dependentSchemas {1} -enum = {0}: har ikke en verdi i oppregningen {1} -exclusiveMaximum = {0}: må ha en eksklusiv maksimumsverdi på {1} -exclusiveMinimum = {0}: må ha en eksklusiv minimumsverdi på {1} -false = {0}: skjemaet for ''{1}'' er usant -format = {0}: samsvarer ikke med {1}-mønsteret {2} -format.date = {0}: samsvarer ikke med {1}-mønsteret må være en gyldig RFC 3339 full-dato -format.date-time = {0}: samsvarer ikke med {1}-mønsteret må være en gyldig RFC 3339 dato-klokkeslett -format.duration = {0}: samsvarer ikke med {1}-mønsteret må være en gyldig ISO 8601-varighet -format.email = {0}: samsvarer ikke med {1}-mønsteret må være en gyldig RFC 5321-postboks -format.ipv4 = {0}: samsvarer ikke med {1}-mønsteret må være en gyldig RFC 2673 IP-adresse -format.ipv6 = {0}: samsvarer ikke med {1}-mønsteret må være en gyldig RFC 4291 IP-adresse -format.idn-email = {0}: samsvarer ikke med {1}-mønsteret må være en gyldig RFC 6531-postboks -format.idn-hostname = {0}: samsvarer ikke med {1}-mønsteret må være et gyldig RFC 5890 internasjonalisert vertsnavn -format.iri = {0}: samsvarer ikke med {1}-mønsteret må være en gyldig RFC 3987 IRI -format.iri-reference = {0}: samsvarer ikke med {1}-mønsteret må være en gyldig RFC 3987 IRI-referanse -format.uri = {0}: samsvarer ikke med {1}-mønsteret må være en gyldig RFC 3986 URI -format.uri-reference = {0}: samsvarer ikke med {1}-mønsteret må være en gyldig RFC 3986 URI-referanse -format.uri-template = {0}: samsvarer ikke med {1}-mønsteret må være en gyldig RFC 6570 URI-mal -format.uuid = {0}: samsvarer ikke med {1}-mønsteret må være en gyldig RFC 4122 UUID -format.regex = {0}: samsvarer ikke med {1}-mønsteret må være et gyldig ECMA-262 regulært uttrykk -format.time = {0}: samsvarer ikke med {1}-mønsteret må være en gyldig RFC 3339-tid -format.hostname = {0}: samsvarer ikke med {1}-mønsteret må være et gyldig RFC 1123-vertsnavn -format.json-pointer = {0}: samsvarer ikke med {1}-mønsteret må være en gyldig RFC 6901 JSON-peker -format.relative-json-pointer = {0}: samsvarer ikke med {1}-mønsteret må være en gyldig IETF relativ JSON-peker -format.unknown = {0}: har et ukjent format ''{1}'' -id = {0}: ''{1}'' er ikke en gyldig {2} -items = {0}: indeks ''{1}'' er ikke definert i skjemaet, og skjemaet tillater ikke flere elementer -maxContains = {0}: må være et ikke-negativt heltall i {1} -maxItems = {0}: må ha maksimalt {1} varer, men fant {2} -maxLength = {0}: må bestå av maksimalt {1} tegn -maxProperties = {0}: må ha maksimalt {1} egenskaper -maximum = {0}: må ha en maksimal verdi på {1} -minContains = {0}: må være et ikke-negativt heltall i {1} -minContainsVsMaxContains = {0}: minContains må være mindre enn eller lik maxContains i {1} -minItems = {0}: må ha minst {1} elementer, men fant {2} -minLength = {0}: må bestå av minst {1} tegn -minProperties = {0}: må ha minst {1} egenskaper -minimum = {0}: må ha en minimumsverdi på {1} -multipleOf = {0}: må være multiplum av {1} -not = {0}: må ikke være gyldig for skjemaet {1} -notAllowed = {0}: egenskapen ''{1}'' er ikke tillatt, men den er i dataene -oneOf = {0}: må være gyldig for ett og bare ett skjema, men {1} er gyldige -oneOf.indexes = {0}: må være gyldig for ett og bare ett skjema, men {1} er gyldige med indeksene ''{2}'' -pattern = {0}: samsvarer ikke med regex-mønsteret {1} -patternProperties = {0}: har en feil med ''mønsteregenskaper'' -prefixItems = {0}: ingen validator funnet i denne indeksen -properties = {0}: har en feil med ''egenskaper'' -propertyNames = {0}: egenskapen ''{1}'' navn er ikke gyldig: {2} -readOnly = {0}: er et skrivebeskyttet felt, det kan ikke endres -required = {0}: påkrevd egenskap ''{1}'' ikke funnet -type = {0}: {1} funnet, {2} forventet -unevaluatedItems = {0}: indeks ''{1}'' er ikke evaluert og skjemaet tillater ikke uevaluerte elementer -unevaluatedProperties = {0}: egenskapen ''{1}'' er ikke evaluert og skjemaet tillater ikke uevaluerte egenskaper -unionType = {0}: {1} funnet, {2} forventet -uniqueItems = {0}: må bare ha unike elementer i matrisen -writeOnly = {0}: er et skrivebeskyttet felt, det kan ikke vises i dataene -contentEncoding = {0}: samsvarer ikke med innholdskoding {1} -contentMediaType = {0}: er ikke et innhold for meg +$ref = har en feil med ''refs'' +additionalItems = indeks ''{0}'' er ikke definert i skjemaet og skjemaet tillater ikke flere elementer +additionalProperties = egenskapen ''{0}'' er ikke definert i skjemaet og skjemaet tillater ikke ytterligere egenskaper +allOf = må være gyldig for alle skjemaene {0} +anyOf = må være gyldig for alle skjemaene {0} +const = må være konstantverdien ''{0}'' +contains = inneholder ikke et element som består disse valideringene: {1} +contains.max = må inneholde maksimalt {0} element(er) som består disse valideringene: {1} +contains.min = må inneholde minst {0} element(er) som består disse valideringene: {1} +dependencies = har en feil med avhengigheter {0} +dependentRequired = har en manglende egenskap ''{0}'' som er avhengig nødvendig fordi ''{1}'' er tilstede +dependentSchemas = har en feil med dependentSchemas {0} +enum = har ikke en verdi i oppregningen {0} +exclusiveMaximum = må ha en eksklusiv maksimumsverdi på {0} +exclusiveMinimum = må ha en eksklusiv minimumsverdi på {0} +false = skjemaet for ''{0}'' er usant +format = samsvarer ikke med {0}-mønsteret +format.date = samsvarer ikke med {0}-mønsteret må være en gyldig RFC 3339 full-dato +format.date-time = samsvarer ikke med {0}-mønsteret må være en gyldig RFC 3339 dato-klokkeslett +format.duration = samsvarer ikke med {0}-mønsteret må være en gyldig ISO 8601-varighet +format.email = samsvarer ikke med {0}-mønsteret må være en gyldig RFC 5321-postboks +format.ipv4 = samsvarer ikke med {0}-mønsteret må være en gyldig RFC 2673 IP-adresse +format.ipv6 = samsvarer ikke med {0}-mønsteret må være en gyldig RFC 4291 IP-adresse +format.idn-email = samsvarer ikke med {0}-mønsteret må være en gyldig RFC 6531-postboks +format.idn-hostname = samsvarer ikke med {0}-mønsteret må være et gyldig RFC 5890 internasjonalisert vertsnavn +format.iri = samsvarer ikke med {0}-mønsteret må være en gyldig RFC 3987 IRI +format.iri-reference = samsvarer ikke med {0}-mønsteret må være en gyldig RFC 3987 IRI-referanse +format.uri = samsvarer ikke med {0}-mønsteret må være en gyldig RFC 3986 URI +format.uri-reference = samsvarer ikke med {0}-mønsteret må være en gyldig RFC 3986 URI-referanse +format.uri-template = samsvarer ikke med {0}-mønsteret må være en gyldig RFC 6570 URI-mal +format.uuid = samsvarer ikke med {0}-mønsteret må være en gyldig RFC 4122 UUID +format.regex = samsvarer ikke med {0}-mønsteret må være et gyldig ECMA-262 regulært uttrykk +format.time = samsvarer ikke med {0}-mønsteret må være en gyldig RFC 3339-tid +format.hostname = samsvarer ikke med {0}-mønsteret må være et gyldig RFC 1123-vertsnavn +format.json-pointer = samsvarer ikke med {0}-mønsteret må være en gyldig RFC 6901 JSON-peker +format.relative-json-pointer = samsvarer ikke med {0}-mønsteret må være en gyldig IETF relativ JSON-peker +format.unknown = har et ukjent format ''{0}'' +id = ''{0}'' er ikke en gyldig {1} +items = indeks ''{0}'' er ikke definert i skjemaet, og skjemaet tillater ikke flere elementer +maxContains = må være et ikke-negativt heltall i {0} +maxItems = må ha maksimalt {0} varer, men fant {1} +maxLength = må bestå av maksimalt {0} tegn +maxProperties = må ha maksimalt {0} egenskaper +maximum = må ha en maksimal verdi på {0} +minContains = må være et ikke-negativt heltall i {0} +minContainsVsMaxContains = minContains må være mindre enn eller lik maxContains i {0} +minItems = må ha minst {0} elementer, men fant {1} +minLength = må bestå av minst {0} tegn +minProperties = må ha minst {0} egenskaper +minimum = må ha en minimumsverdi på {0} +multipleOf = må være multiplum av {0} +not = må ikke være gyldig for skjemaet {0} +notAllowed = egenskapen ''{0}'' er ikke tillatt, men den er i dataene +oneOf = må være gyldig for ett og bare ett skjema, men {0} er gyldige +oneOf.indexes = må være gyldig for ett og bare ett skjema, men {0} er gyldige med indeksene ''{1}'' +pattern = samsvarer ikke med regex-mønsteret {0} +patternProperties = har en feil med ''mønsteregenskaper'' +prefixItems = ingen validator funnet i denne indeksen +properties = har en feil med ''egenskaper'' +propertyNames = egenskapen ''{0}'' navn er ikke gyldig: {1} +readOnly = er et skrivebeskyttet felt, det kan ikke endres +required = påkrevd egenskap ''{0}'' ikke funnet +type = {0} funnet, {1} forventet +unevaluatedItems = indeks ''{0}'' er ikke evaluert og skjemaet tillater ikke uevaluerte elementer +unevaluatedProperties = egenskapen ''{0}'' er ikke evaluert og skjemaet tillater ikke uevaluerte egenskaper +unionType = {0} funnet, {1} forventet +uniqueItems = må bare ha unike elementer i matrisen +writeOnly = er et skrivebeskyttet felt, det kan ikke vises i dataene +contentEncoding = samsvarer ikke med innholdskoding {0} +contentMediaType = er ikke et innhold for meg diff --git a/src/main/resources/jsv-messages_nl.properties b/src/main/resources/jsv-messages_nl.properties index bf77c37a6..437d94429 100644 --- a/src/main/resources/jsv-messages_nl.properties +++ b/src/main/resources/jsv-messages_nl.properties @@ -1,70 +1,70 @@ -$ref = {0}: bevat een fout met ''refs'' -additionalItems = {0}: index ''{1}'' is niet gedefinieerd in het schema en het schema staat geen extra items toe -additionalProperties = {0}: eigenschap ''{1}'' is niet gedefinieerd in het schema en het schema staat geen aanvullende eigenschappen toe -allOf = {0}: moet geldig zijn voor alle schema''s {1} -anyOf = {0}: moet geldig zijn voor elk van de schema''s {1} -const = {0}: moet de constante waarde ''{1}'' zijn -contains = {0}: bevat geen element dat deze validaties doorstaat: {2} -contains.max = {0}: moet maximaal {1} element(en) bevatten die aan deze validaties voldoen: {2} -contains.min = {0}: moet minimaal {1} element(en) bevatten die aan deze validaties voldoen: {2} -dependencies = {0}: bevat een fout met afhankelijkheden {1} -dependentRequired = {0}: heeft een ontbrekende eigenschap ''{1}'' die afhankelijk is vereist omdat ''{2}'' aanwezig is -dependentSchemas = {0}: bevat een fout met dependSchemas {1} -enum = {0}: heeft geen waarde in de opsomming {1} -exclusiveMaximum = {0}: moet een exclusieve maximumwaarde hebben van {1} -exclusiveMinimum = {0}: moet een exclusieve minimumwaarde hebben van {1} -false = {0}: schema voor ''{1}'' is false -format = {0}: komt niet overeen met het {1} patroon {2} -format.date = {0}: komt niet overeen met het {1}-patroon moet een geldige RFC 3339-volledige datum zijn -format.date-time = {0}: komt niet overeen met het {1}-patroon moet een geldige RFC 3339-datum-tijd zijn -format.duration = {0}: komt niet overeen met het patroon {1} moet een geldige ISO 8601-duur hebben -format.email = {0}: komt niet overeen met het patroon {1} moet een geldige RFC 5321-mailbox zijn -format.ipv4 = {0}: komt niet overeen met het patroon {1} moet een geldig RFC 2673 IP-adres zijn -format.ipv6 = {0}: komt niet overeen met het patroon {1} moet een geldig RFC 4291 IP-adres zijn -format.idn-email = {0}: komt niet overeen met het patroon {1} moet een geldige RFC 6531-mailbox zijn -format.idn-hostname = {0}: komt niet overeen met het patroon {1} moet een geldige geïnternationaliseerde RFC 5890-hostnaam zijn -format.iri = {0}: komt niet overeen met het {1}-patroon moet een geldige RFC 3987 IRI zijn -format.iri-reference = {0}: komt niet overeen met het {1}-patroon moet een geldige RFC 3987 IRI-referentie zijn -format.uri = {0}: komt niet overeen met het {1}-patroon moet een geldige RFC 3986-URI zijn -format.uri-reference = {0}: komt niet overeen met het {1}-patroon moet een geldige RFC 3986 URI-referentie zijn -format.uri-template = {0}: komt niet overeen met het {1}-patroon moet een geldige RFC 6570 URI-sjabloon zijn -format.uuid = {0}: komt niet overeen met het {1}-patroon moet een geldige RFC 4122 UUID zijn -format.regex = {0}: komt niet overeen met het patroon {1} moet een geldige reguliere ECMA-262-expressie zijn -format.time = {0}: komt niet overeen met het {1}-patroon moet een geldige RFC 3339-tijd zijn -format.hostname = {0}: komt niet overeen met het patroon {1} moet een geldige RFC 1123-hostnaam zijn -format.json-pointer = {0}: komt niet overeen met het {1}-patroon moet een geldige RFC 6901 JSON-aanwijzer zijn -format.relative-json-pointer = {0}: komt niet overeen met het {1}-patroon moet een geldige IETF relatieve JSON-aanwijzer zijn -format.unknown = {0}: heeft een onbekend formaat ''{1}'' -id = {0}: ''{1}'' is geen geldige {2} -items = {0}: index ''{1}'' is niet gedefinieerd in het schema en het schema staat geen extra items toe -maxContains = {0}: moet een niet-negatief geheel getal zijn in {1} -maxItems = {0}: moet maximaal {1} items bevatten, maar heeft {2} gevonden -maxLength = {0}: mag maximaal {1} tekens lang zijn -maxProperties = {0}: moet maximaal {1} eigenschappen hebben -maximum = {0}: moet een maximale waarde van {1} hebben -minContains = {0}: moet een niet-negatief geheel getal zijn in {1} -minContainsVsMaxContains = {0}: minContains moet kleiner zijn dan of gelijk zijn aan maxContains in {1} -minItems = {0}: moet minstens {1} items hebben, maar {2} gevonden -minLength = {0}: moet minimaal {1} tekens lang zijn -minProperties = {0}: moet minimaal {1} eigenschappen hebben -minimum = {0}: moet een minimumwaarde van {1} hebben -multipleOf = {0}: moet een veelvoud zijn van {1} -not = {0}: mag niet geldig zijn voor het schema {1} -notAllowed = {0}: eigenschap ''{1}'' is niet toegestaan, maar staat wel in de gegevens -oneOf = {0}: moet geldig zijn voor slechts één schema, maar {1} zijn geldig -oneOf.indexes = {0}: moet geldig zijn voor één en slechts één schema, maar {1} zijn geldig met indexen ''{2}'' -pattern = {0}: komt niet overeen met het regex-patroon {1} -patternProperties = {0}: bevat een fout met ''patrooneigenschappen'' -prefixItems = {0}: geen validator gevonden bij deze index -properties = {0}: bevat een fout met ''properties'' -propertyNames = {0}: eigenschap ''{1}'' naam is niet geldig: {2} -readOnly = {0}: is een alleen-lezen veld, dit kan niet worden gewijzigd -required = {0}: vereiste eigenschap ''{1}'' niet gevonden -type = {0}: {1} gevonden, {2} verwacht -unevaluatedItems = {0}: index ''{1}'' wordt niet geëvalueerd en het schema staat geen niet-geëvalueerde items toe -unevaluatedProperties = {0}: eigenschap ''{1}'' wordt niet geëvalueerd en het schema staat geen niet-geëvalueerde eigenschappen toe -unionType = {0}: {1} gevonden, {2} verwacht -uniqueItems = {0}: mag alleen unieke items in de array bevatten -writeOnly = {0}: is een alleen-schrijven-veld, het kan niet voorkomen in de gegevens -contentEncoding = {0}: komt niet overeen met inhoudscodering {1} -contentMediaType = {0}: is geen inhoudsmij +$ref = bevat een fout met ''refs'' +additionalItems = index ''{0}'' is niet gedefinieerd in het schema en het schema staat geen extra items toe +additionalProperties = eigenschap ''{0}'' is niet gedefinieerd in het schema en het schema staat geen aanvullende eigenschappen toe +allOf = moet geldig zijn voor alle schema''s {0} +anyOf = moet geldig zijn voor elk van de schema''s {0} +const = moet de constante waarde ''{0}'' zijn +contains = bevat geen element dat deze validaties doorstaat: {1} +contains.max = moet maximaal {0} element(en) bevatten die aan deze validaties voldoen: {1} +contains.min = moet minimaal {0} element(en) bevatten die aan deze validaties voldoen: {1} +dependencies = bevat een fout met afhankelijkheden {0} +dependentRequired = heeft een ontbrekende eigenschap ''{0}'' die afhankelijk is vereist omdat ''{1}'' aanwezig is +dependentSchemas = bevat een fout met dependSchemas {0} +enum = heeft geen waarde in de opsomming {0} +exclusiveMaximum = moet een exclusieve maximumwaarde hebben van {0} +exclusiveMinimum = moet een exclusieve minimumwaarde hebben van {0} +false = schema voor ''{0}'' is false +format = komt niet overeen met het {0} patroon +format.date = komt niet overeen met het {0}-patroon moet een geldige RFC 3339-volledige datum zijn +format.date-time = komt niet overeen met het {0}-patroon moet een geldige RFC 3339-datum-tijd zijn +format.duration = komt niet overeen met het patroon {0} moet een geldige ISO 8601-duur hebben +format.email = komt niet overeen met het patroon {0} moet een geldige RFC 5321-mailbox zijn +format.ipv4 = komt niet overeen met het patroon {0} moet een geldig RFC 2673 IP-adres zijn +format.ipv6 = komt niet overeen met het patroon {0} moet een geldig RFC 4291 IP-adres zijn +format.idn-email = komt niet overeen met het patroon {0} moet een geldige RFC 6531-mailbox zijn +format.idn-hostname = komt niet overeen met het patroon {0} moet een geldige geïnternationaliseerde RFC 5890-hostnaam zijn +format.iri = komt niet overeen met het {0}-patroon moet een geldige RFC 3987 IRI zijn +format.iri-reference = komt niet overeen met het {0}-patroon moet een geldige RFC 3987 IRI-referentie zijn +format.uri = komt niet overeen met het {0}-patroon moet een geldige RFC 3986-URI zijn +format.uri-reference = komt niet overeen met het {0}-patroon moet een geldige RFC 3986 URI-referentie zijn +format.uri-template = komt niet overeen met het {0}-patroon moet een geldige RFC 6570 URI-sjabloon zijn +format.uuid = komt niet overeen met het {0}-patroon moet een geldige RFC 4122 UUID zijn +format.regex = komt niet overeen met het patroon {0} moet een geldige reguliere ECMA-262-expressie zijn +format.time = komt niet overeen met het {0}-patroon moet een geldige RFC 3339-tijd zijn +format.hostname = komt niet overeen met het patroon {0} moet een geldige RFC 1123-hostnaam zijn +format.json-pointer = komt niet overeen met het {0}-patroon moet een geldige RFC 6901 JSON-aanwijzer zijn +format.relative-json-pointer = komt niet overeen met het {0}-patroon moet een geldige IETF relatieve JSON-aanwijzer zijn +format.unknown = heeft een onbekend formaat ''{0}'' +id = ''{0}'' is geen geldige {1} +items = index ''{0}'' is niet gedefinieerd in het schema en het schema staat geen extra items toe +maxContains = moet een niet-negatief geheel getal zijn in {0} +maxItems = moet maximaal {0} items bevatten, maar heeft {1} gevonden +maxLength = mag maximaal {0} tekens lang zijn +maxProperties = moet maximaal {0} eigenschappen hebben +maximum = moet een maximale waarde van {0} hebben +minContains = moet een niet-negatief geheel getal zijn in {0} +minContainsVsMaxContains = minContains moet kleiner zijn dan of gelijk zijn aan maxContains in {0} +minItems = moet minstens {0} items hebben, maar {1} gevonden +minLength = moet minimaal {0} tekens lang zijn +minProperties = moet minimaal {0} eigenschappen hebben +minimum = moet een minimumwaarde van {0} hebben +multipleOf = moet een veelvoud zijn van {0} +not = mag niet geldig zijn voor het schema {0} +notAllowed = eigenschap ''{0}'' is niet toegestaan, maar staat wel in de gegevens +oneOf = moet geldig zijn voor slechts één schema, maar {0} zijn geldig +oneOf.indexes = moet geldig zijn voor één en slechts één schema, maar {0} zijn geldig met indexen ''{1}'' +pattern = komt niet overeen met het regex-patroon {0} +patternProperties = bevat een fout met ''patrooneigenschappen'' +prefixItems = geen validator gevonden bij deze index +properties = bevat een fout met ''properties'' +propertyNames = eigenschap ''{0}'' naam is niet geldig: {1} +readOnly = is een alleen-lezen veld, dit kan niet worden gewijzigd +required = vereiste eigenschap ''{0}'' niet gevonden +type = {0} gevonden, {1} verwacht +unevaluatedItems = index ''{0}'' wordt niet geëvalueerd en het schema staat geen niet-geëvalueerde items toe +unevaluatedProperties = eigenschap ''{0}'' wordt niet geëvalueerd en het schema staat geen niet-geëvalueerde eigenschappen toe +unionType = {0} gevonden, {1} verwacht +uniqueItems = mag alleen unieke items in de array bevatten +writeOnly = is een alleen-schrijven-veld, het kan niet voorkomen in de gegevens +contentEncoding = komt niet overeen met inhoudscodering {0} +contentMediaType = is geen inhoudsmij diff --git a/src/main/resources/jsv-messages_pl.properties b/src/main/resources/jsv-messages_pl.properties index 254477b1c..4717b151b 100644 --- a/src/main/resources/jsv-messages_pl.properties +++ b/src/main/resources/jsv-messages_pl.properties @@ -1,70 +1,70 @@ -$ref = {0}: zawiera b\u0142\u0105d z \u201Erefami\u201D -additionalItems = {0}: indeks \u201E{1}\u201D nie jest zdefiniowany w schemacie i schemat nie pozwala na dodatkowe elementy -additionalProperties = {0}: w\u0142a\u015Bciwo\u015B\u0107 \u201E{1}\u201D nie jest zdefiniowana w schemacie i schemat nie pozwala na dodatkowe w\u0142a\u015Bciwo\u015Bci -allOf = {0}: musi by\u0107 poprawny dla wszystkich schematów {1} -anyOf = {0}: musi by\u0107 poprawny dla dowolnego schematu {1} -const = {0}: musi by\u0107 sta\u0142\u0105 warto\u015Bci\u0105 \u201E{1}\u201D -contains = {0}: nie zawiera elementu, który przechodzi te weryfikacje: {2} -contains.max = {0}: musi zawiera\u0107 maksymalnie {1} elementów, które przechodz\u0105 t\u0119 weryfikacj\u0119: {2} -contains.min = {0}: musi zawiera\u0107 co najmniej {1} elementów, które przechodz\u0105 t\u0119 weryfikacj\u0119: {2} -dependencies = {0}: zawiera b\u0142\u0105d z zale\u017Cno\u015Bciami {1} -dependentRequired = {0}: ma brakuj\u0105c\u0105 w\u0142a\u015Bciwo\u015B\u0107 \u201E{1}\u201D, która jest zale\u017Cna i wymagana, poniewa\u017C wyst\u0119puje \u201E{2}\u201D -dependentSchemas = {0}: zawiera b\u0142\u0105d w schematach zale\u017Cnych {1} -enum = {0}: nie ma warto\u015Bci w wyliczeniu {1} -exclusiveMaximum = {0}: musi mie\u0107 wy\u0142\u0105czn\u0105 warto\u015B\u0107 maksymaln\u0105 wynosz\u0105c\u0105 {1} -exclusiveMinimum = {0}: musi mie\u0107 wy\u0142\u0105czn\u0105 minimaln\u0105 warto\u015B\u0107 {1} -false = {0}: schemat dla \u201E{1}\u201D jest fa\u0142szywy -format = {0}: nie pasuje do wzorca {1} {2} -format.date = {0}: nie pasuje do wzorca {1} musi by\u0107 prawid\u0142ow\u0105 pe\u0142n\u0105 dat\u0105 RFC 3339 -format.date-time = {0}: nie pasuje do wzorca {1} musi by\u0107 prawid\u0142ow\u0105 dat\u0105 i godzin\u0105 RFC 3339 -format.duration = {0}: nie pasuje do wzorca {1}, musi mie\u0107 prawid\u0142owy czas trwania ISO 8601 -format.email = {0}: nie pasuje do wzorca {1} musi by\u0107 prawid\u0142ow\u0105 skrzynk\u0105 pocztow\u0105 RFC 5321 -format.ipv4 = {0}: nie pasuje do wzorca {1} musi by\u0107 prawid\u0142owym adresem IP RFC 2673 -format.ipv6 = {0}: nie pasuje do wzorca {1} musi by\u0107 prawid\u0142owym adresem IP RFC 4291 -format.idn-email = {0}: nie pasuje do wzorca {1} musi by\u0107 prawid\u0142ow\u0105 skrzynk\u0105 pocztow\u0105 RFC 6531 -format.idn-hostname = {0}: nie pasuje do wzorca {1} musi by\u0107 prawid\u0142ow\u0105 mi\u0119dzynarodow\u0105 nazw\u0105 hosta zgodn\u0105 z RFC 5890 -format.iri = {0}: nie pasuje do wzorca {1} musi by\u0107 prawid\u0142owym IRI RFC 3987 -format.iri-reference = {0}: nie pasuje do wzorca {1} musi by\u0107 prawid\u0142owym odwo\u0142aniem IRI RFC 3987 -format.uri = {0}: nie pasuje do wzorca {1} musi by\u0107 prawid\u0142owym identyfikatorem URI RFC 3986 -format.uri-reference = {0}: nie pasuje do wzorca {1} musi by\u0107 prawid\u0142owym odwo\u0142aniem URI RFC 3986 -format.uri-template = {0}: nie pasuje do wzorca {1} musi by\u0107 prawid\u0142owym szablonem URI RFC 6570 -format.uuid = {0}: nie pasuje do wzorca {1} musi by\u0107 prawid\u0142owym identyfikatorem UUID RFC 4122 -format.regex = {0}: nie pasuje do wzorca {1} musi by\u0107 prawid\u0142owym wyra\u017Ceniem regularnym ECMA-262 -format.time = {0}: nie pasuje do wzorca {1} musi by\u0107 prawid\u0142owym czasem RFC 3339 -format.hostname = {0}: nie pasuje do wzorca {1} musi by\u0107 prawid\u0142ow\u0105 nazw\u0105 hosta zgodn\u0105 z RFC 1123 -format.json-pointer = {0}: nie pasuje do wzorca {1} musi by\u0107 prawid\u0142owym wska\u017Anikiem JSON RFC 6901 -format.relative-json-pointer = {0}: nie pasuje do wzorca {1} musi by\u0107 prawid\u0142owym wzgl\u0119dnym wska\u017Anikiem JSON IETF -format.unknown = {0}: ma nieznany format \u201E{1}\u201D -id = {0}: \u201E{1}\u201D nie jest prawid\u0142owym {2} -items = {0}: indeks ''{1}'' nie jest zdefiniowany w schemacie i schemat nie pozwala na dodatkowe elementy -maxContains = {0}: musi by\u0107 nieujemn\u0105 liczb\u0105 ca\u0142kowit\u0105 w {1} -maxItems = {0}: musi mie\u0107 co najwy\u017Cej {1} elementów, ale znaleziono {2} -maxLength = {0}: musi mie\u0107 maksymalnie {1} znaków -maxProperties = {0}: musi mie\u0107 co najwy\u017Cej {1} w\u0142a\u015Bciwo\u015Bci -maximum = {0}: musi mie\u0107 maksymaln\u0105 warto\u015B\u0107 {1} -minContains = {0}: musi by\u0107 nieujemn\u0105 liczb\u0105 ca\u0142kowit\u0105 w {1} -minContainsVsMaxContains = {0}: minContains musi by\u0107 mniejsze lub równe maxContains w {1} -minItems = {0}: musi mie\u0107 co najmniej {1} elementów, ale znaleziono {2} -minLength = {0}: musi mie\u0107 co najmniej {1} znaków -minProperties = {0}: musi mie\u0107 co najmniej {1} w\u0142a\u015Bciwo\u015Bci -minimum = {0}: musi mie\u0107 minimaln\u0105 warto\u015B\u0107 {1} -multipleOf = {0}: musi by\u0107 wielokrotno\u015Bci\u0105 {1} -not = {0}: nie mo\u017Ce by\u0107 poprawny dla schematu {1} -notAllowed = {0}: w\u0142a\u015Bciwo\u015B\u0107 \u201E{1}\u201D jest niedozwolona, ale znajduje si\u0119 w danych -oneOf = {0}: musi by\u0107 poprawny dla jednego i tylko jednego schematu, ale {1} s\u0105 prawid\u0142owe -oneOf.indexes = {0}: musi by\u0107 poprawny dla jednego i tylko jednego schematu, ale {1} jest prawid\u0142owe z indeksami \u201E{2}\u201D -pattern = {0}: nie pasuje do wzorca wyra\u017Cenia regularnego {1} -patternProperties = {0}: zawiera b\u0142\u0105d dotycz\u0105cy \u201Ew\u0142a\u015Bciwo\u015Bci wzorca\u201D -prefixItems = {0}: w tym indeksie nie znaleziono walidatora -properties = {0}: zawiera b\u0142\u0105d dotycz\u0105cy \u201Ew\u0142a\u015Bciwo\u015Bci\u201D -propertyNames = {0}: nazwa w\u0142a\u015Bciwo\u015Bci \u201E{1}\u201D jest nieprawid\u0142owa: {2} -readOnly = {0}: jest polem tylko do odczytu, nie mo\u017Cna go zmieni\u0107 -required = {0}: nie znaleziono wymaganej w\u0142a\u015Bciwo\u015Bci \u201E{1}\u201D. -type = {0}: Znaleziono {1}, oczekiwano {2} -unevaluatedItems = {0}: indeks \u201E{1}\u201D nie jest oceniany i schemat nie pozwala na nieocenione elementy -unevaluatedProperties = {0}: w\u0142a\u015Bciwo\u015B\u0107 \u201E{1}\u201D nie jest oceniana i schemat nie pozwala na nieocenione w\u0142a\u015Bciwo\u015Bci -unionType = {0}: Znaleziono {1}, oczekiwano {2} -uniqueItems = {0}: tablica musi zawiera\u0107 tylko unikalne elementy -writeOnly = {0}: jest polem tylko do zapisu, nie mo\u017Ce pojawia\u0107 si\u0119 w danych -contentEncoding = {0}: nie pasuje do kodowania tre\u015Bci {1} -contentMediaType = {0}: nie jest tre\u015Bci\u0105 +$ref = zawiera b\u0142\u0105d z \u201Erefami\u201D +additionalItems = indeks \u201E{0}\u201D nie jest zdefiniowany w schemacie i schemat nie pozwala na dodatkowe elementy +additionalProperties = w\u0142a\u015Bciwo\u015B\u0107 \u201E{0}\u201D nie jest zdefiniowana w schemacie i schemat nie pozwala na dodatkowe w\u0142a\u015Bciwo\u015Bci +allOf = musi by\u0107 poprawny dla wszystkich schematów {0} +anyOf = musi by\u0107 poprawny dla dowolnego schematu {0} +const = musi by\u0107 sta\u0142\u0105 warto\u015Bci\u0105 \u201E{0}\u201D +contains = nie zawiera elementu, który przechodzi te weryfikacje: {1} +contains.max = musi zawiera\u0107 maksymalnie {0} elementów, które przechodz\u0105 t\u0119 weryfikacj\u0119: {1} +contains.min = musi zawiera\u0107 co najmniej {0} elementów, które przechodz\u0105 t\u0119 weryfikacj\u0119: {1} +dependencies = zawiera b\u0142\u0105d z zale\u017Cno\u015Bciami {0} +dependentRequired = ma brakuj\u0105c\u0105 w\u0142a\u015Bciwo\u015B\u0107 \u201E{0}\u201D, która jest zale\u017Cna i wymagana, poniewa\u017C wyst\u0119puje \u201E{1}\u201D +dependentSchemas = zawiera b\u0142\u0105d w schematach zale\u017Cnych {0} +enum = nie ma warto\u015Bci w wyliczeniu {0} +exclusiveMaximum = musi mie\u0107 wy\u0142\u0105czn\u0105 warto\u015B\u0107 maksymaln\u0105 wynosz\u0105c\u0105 {0} +exclusiveMinimum = musi mie\u0107 wy\u0142\u0105czn\u0105 minimaln\u0105 warto\u015B\u0107 {0} +false = schemat dla \u201E{0}\u201D jest fa\u0142szywy +format = nie pasuje do wzorca {0} +format.date = nie pasuje do wzorca {0} musi by\u0107 prawid\u0142ow\u0105 pe\u0142n\u0105 dat\u0105 RFC 3339 +format.date-time = nie pasuje do wzorca {0} musi by\u0107 prawid\u0142ow\u0105 dat\u0105 i godzin\u0105 RFC 3339 +format.duration = nie pasuje do wzorca {0}, musi mie\u0107 prawid\u0142owy czas trwania ISO 8601 +format.email = nie pasuje do wzorca {0} musi by\u0107 prawid\u0142ow\u0105 skrzynk\u0105 pocztow\u0105 RFC 5321 +format.ipv4 = nie pasuje do wzorca {0} musi by\u0107 prawid\u0142owym adresem IP RFC 2673 +format.ipv6 = nie pasuje do wzorca {0} musi by\u0107 prawid\u0142owym adresem IP RFC 4291 +format.idn-email = nie pasuje do wzorca {0} musi by\u0107 prawid\u0142ow\u0105 skrzynk\u0105 pocztow\u0105 RFC 6531 +format.idn-hostname = nie pasuje do wzorca {0} musi by\u0107 prawid\u0142ow\u0105 mi\u0119dzynarodow\u0105 nazw\u0105 hosta zgodn\u0105 z RFC 5890 +format.iri = nie pasuje do wzorca {0} musi by\u0107 prawid\u0142owym IRI RFC 3987 +format.iri-reference = nie pasuje do wzorca {0} musi by\u0107 prawid\u0142owym odwo\u0142aniem IRI RFC 3987 +format.uri = nie pasuje do wzorca {0} musi by\u0107 prawid\u0142owym identyfikatorem URI RFC 3986 +format.uri-reference = nie pasuje do wzorca {0} musi by\u0107 prawid\u0142owym odwo\u0142aniem URI RFC 3986 +format.uri-template = nie pasuje do wzorca {0} musi by\u0107 prawid\u0142owym szablonem URI RFC 6570 +format.uuid = nie pasuje do wzorca {0} musi by\u0107 prawid\u0142owym identyfikatorem UUID RFC 4122 +format.regex = nie pasuje do wzorca {0} musi by\u0107 prawid\u0142owym wyra\u017Ceniem regularnym ECMA-262 +format.time = nie pasuje do wzorca {0} musi by\u0107 prawid\u0142owym czasem RFC 3339 +format.hostname = nie pasuje do wzorca {0} musi by\u0107 prawid\u0142ow\u0105 nazw\u0105 hosta zgodn\u0105 z RFC 1123 +format.json-pointer = nie pasuje do wzorca {0} musi by\u0107 prawid\u0142owym wska\u017Anikiem JSON RFC 6901 +format.relative-json-pointer = nie pasuje do wzorca {0} musi by\u0107 prawid\u0142owym wzgl\u0119dnym wska\u017Anikiem JSON IETF +format.unknown = ma nieznany format \u201E{0}\u201D +id = \u201E{0}\u201D nie jest prawid\u0142owym {1} +items = indeks ''{0}'' nie jest zdefiniowany w schemacie i schemat nie pozwala na dodatkowe elementy +maxContains = musi by\u0107 nieujemn\u0105 liczb\u0105 ca\u0142kowit\u0105 w {0} +maxItems = musi mie\u0107 co najwy\u017Cej {0} elementów, ale znaleziono {1} +maxLength = musi mie\u0107 maksymalnie {0} znaków +maxProperties = musi mie\u0107 co najwy\u017Cej {0} w\u0142a\u015Bciwo\u015Bci +maximum = musi mie\u0107 maksymaln\u0105 warto\u015B\u0107 {0} +minContains = musi by\u0107 nieujemn\u0105 liczb\u0105 ca\u0142kowit\u0105 w {0} +minContainsVsMaxContains = minContains musi by\u0107 mniejsze lub równe maxContains w {0} +minItems = musi mie\u0107 co najmniej {0} elementów, ale znaleziono {1} +minLength = musi mie\u0107 co najmniej {0} znaków +minProperties = musi mie\u0107 co najmniej {0} w\u0142a\u015Bciwo\u015Bci +minimum = musi mie\u0107 minimaln\u0105 warto\u015B\u0107 {0} +multipleOf = musi by\u0107 wielokrotno\u015Bci\u0105 {0} +not = nie mo\u017Ce by\u0107 poprawny dla schematu {0} +notAllowed = w\u0142a\u015Bciwo\u015B\u0107 \u201E{0}\u201D jest niedozwolona, ale znajduje si\u0119 w danych +oneOf = musi by\u0107 poprawny dla jednego i tylko jednego schematu, ale {0} s\u0105 prawid\u0142owe +oneOf.indexes = musi by\u0107 poprawny dla jednego i tylko jednego schematu, ale {0} jest prawid\u0142owe z indeksami \u201E{1}\u201D +pattern = nie pasuje do wzorca wyra\u017Cenia regularnego {0} +patternProperties = zawiera b\u0142\u0105d dotycz\u0105cy \u201Ew\u0142a\u015Bciwo\u015Bci wzorca\u201D +prefixItems = w tym indeksie nie znaleziono walidatora +properties = zawiera b\u0142\u0105d dotycz\u0105cy \u201Ew\u0142a\u015Bciwo\u015Bci\u201D +propertyNames = nazwa w\u0142a\u015Bciwo\u015Bci \u201E{0}\u201D jest nieprawid\u0142owa: {1} +readOnly = jest polem tylko do odczytu, nie mo\u017Cna go zmieni\u0107 +required = nie znaleziono wymaganej w\u0142a\u015Bciwo\u015Bci \u201E{0}\u201D. +type = Znaleziono {0}, oczekiwano {1} +unevaluatedItems = indeks \u201E{0}\u201D nie jest oceniany i schemat nie pozwala na nieocenione elementy +unevaluatedProperties = w\u0142a\u015Bciwo\u015B\u0107 \u201E{0}\u201D nie jest oceniana i schemat nie pozwala na nieocenione w\u0142a\u015Bciwo\u015Bci +unionType = Znaleziono {0}, oczekiwano {1} +uniqueItems = tablica musi zawiera\u0107 tylko unikalne elementy +writeOnly = jest polem tylko do zapisu, nie mo\u017Ce pojawia\u0107 si\u0119 w danych +contentEncoding = nie pasuje do kodowania tre\u015Bci {0} +contentMediaType = nie jest tre\u015Bci\u0105 diff --git a/src/main/resources/jsv-messages_pt.properties b/src/main/resources/jsv-messages_pt.properties index ae3ebc145..39b130852 100644 --- a/src/main/resources/jsv-messages_pt.properties +++ b/src/main/resources/jsv-messages_pt.properties @@ -1,70 +1,70 @@ -$ref = {0}: tem um erro com ''refs'' -additionalItems = {0}: o índice ''{1}'' não está definido no esquema e o esquema não permite itens adicionais -additionalProperties = {0}: a propriedade ''{1}'' não está definida no esquema e o esquema não permite propriedades adicionais -allOf = {0}: deve ser válido para todos os esquemas {1} -anyOf = {0}: deve ser válido para qualquer um dos esquemas {1} -const = {0}: deve ser o valor constante ''{1}'' -contains = {0}: não contém um elemento que passe nestas validações: {2} -contains.max = {0}: deve conter no máximo {1} elemento(s) que passe(m) nestas validações: {2} -contains.min = {0}: deve conter pelo menos {1} elemento(s) que passe(m) nestas validações: {2} -dependencies = {0}: há um erro com dependências {1} -dependentRequired = {0}: tem uma propriedade ausente ''{1}'' que é dependente necessária porque ''{2}'' está presente -dependentSchemas = {0}: há um erro com dependenteSchemas {1} -enum = {0}: não possui valor na enumeração {1} -exclusiveMaximum = {0}: deve ter um valor máximo exclusivo de {1} -exclusiveMinimum = {0}: deve ter um valor mínimo exclusivo de {1} -false = {0}: o esquema para ''{1}'' é falso -format = {0}: não corresponde ao padrão {1} {2} -format.date = {0}: não corresponde ao padrão {1} deve ser uma data completa RFC 3339 válida -format.date-time = {0}: não corresponde ao padrão {1} deve ser uma data e hora RFC 3339 válida -format.duration = {0}: não corresponde ao padrão {1} deve ter uma duração ISO 8601 válida -format.email = {0}: não corresponde ao padrão {1} deve ser uma caixa de correio RFC 5321 válida -format.ipv4 = {0}: não corresponde ao padrão {1} deve ser um endereço IP RFC 2673 válido -format.ipv6 = {0}: não corresponde ao padrão {1} deve ser um endereço IP RFC 4291 válido -format.idn-email = {0}: não corresponde ao padrão {1} deve ser uma caixa de correio RFC 6531 válida -format.idn-hostname = {0}: não corresponde ao padrão {1} deve ser um nome de host internacionalizado RFC 5890 válido -format.iri = {0}: não corresponde ao padrão {1} deve ser um RFC 3987 IRI válido -format.iri-reference = {0}: não corresponde ao padrão {1} deve ser uma referência IRI RFC 3987 válida -format.uri = {0}: não corresponde ao padrão {1} deve ser um URI RFC 3986 válido -format.uri-reference = {0}: não corresponde ao padrão {1} deve ser uma referência de URI RFC 3986 válida -format.uri-template = {0}: não corresponde ao padrão {1} deve ser um modelo de URI RFC 6570 válido -format.uuid = {0}: não corresponde ao padrão {1} deve ser um UUID RFC 4122 válido -format.regex = {0}: não corresponde ao padrão {1} deve ser uma expressão regular ECMA-262 válida -format.time = {0}: não corresponde ao padrão {1} deve ser um horário RFC 3339 válido -format.hostname = {0}: não corresponde ao padrão {1} deve ser um nome de host RFC 1123 válido -format.json-pointer = {0}: não corresponde ao padrão {1} deve ser um ponteiro JSON RFC 6901 válido -format.relative-json-pointer = {0}: não corresponde ao padrão {1} deve ser um ponteiro JSON relativo IETF válido -format.unknown = {0}: tem um formato desconhecido ''{1}'' -id = {0}: ''{1}'' não é um {2} válido -items = {0}: o índice ''{1}'' não está definido no esquema e o esquema não permite itens adicionais -maxContains = {0}: deve ser um número inteiro não negativo em {1} -maxItems = {0}: deve ter no máximo {1} itens, mas foram encontrados {2} -maxLength = {0}: deve ter no máximo {1} caracteres -maxProperties = {0}: deve ter no máximo {1} propriedades -maximum = {0}: deve ter um valor máximo de {1} -minContains = {0}: deve ser um número inteiro não negativo em {1} -minContainsVsMaxContains = {0}: minContains deve ser menor ou igual a maxContains em {1} -minItems = {0}: deve ter pelo menos {1} itens, mas foi encontrado {2} -minLength = {0}: deve ter pelo menos {1} caracteres -minProperties = {0}: deve ter pelo menos {1} propriedades -minimum = {0}: deve ter um valor mínimo de {1} -multipleOf = {0}: deve ser múltiplo de {1} -not = {0}: não deve ser válido para o esquema {1} -notAllowed = {0}: propriedade ''{1}'' não é permitida, mas está nos dados -oneOf = {0}: deve ser válido para um e apenas um esquema, mas {1} são válidos -oneOf.indexes = {0}: deve ser válido para um e somente um esquema, mas {1} são válidos com índices ''{2}'' -pattern = {0}: não corresponde ao padrão regex {1} -patternProperties = {0}: há algum erro com ''propriedades do padrão'' -prefixItems = {0}: nenhum validador encontrado neste índice -properties = {0}: há um erro com ''propriedades'' -propertyNames = {0}: o nome da propriedade ''{1}'' não é válido: {2} -readOnly = {0}: é um campo somente leitura, não pode ser alterado -required = {0}: propriedade obrigatória ''{1}'' não encontrada -type = {0}: {1} encontrado, {2} esperado -unevaluatedItems = {0}: o índice ''{1}'' não é avaliado e o esquema não permite itens não avaliados -unevaluatedProperties = {0}: a propriedade ''{1}'' não foi avaliada e o esquema não permite propriedades não avaliadas -unionType = {0}: {1} encontrado, {2} esperado -uniqueItems = {0}: deve ter apenas itens únicos no array -writeOnly = {0}: é um campo somente gravação, não pode aparecer nos dados -contentEncoding = {0}: não corresponde à codificação de conteúdo {1} -contentMediaType = {0}: não é um conteúdo para mim +$ref = tem um erro com ''refs'' +additionalItems = o índice ''{0}'' não está definido no esquema e o esquema não permite itens adicionais +additionalProperties = a propriedade ''{0}'' não está definida no esquema e o esquema não permite propriedades adicionais +allOf = deve ser válido para todos os esquemas {0} +anyOf = deve ser válido para qualquer um dos esquemas {0} +const = deve ser o valor constante ''{0}'' +contains = não contém um elemento que passe nestas validações: {1} +contains.max = deve conter no máximo {0} elemento(s) que passe(m) nestas validações: {1} +contains.min = deve conter pelo menos {0} elemento(s) que passe(m) nestas validações: {1} +dependencies = há um erro com dependências {0} +dependentRequired = tem uma propriedade ausente ''{0}'' que é dependente necessária porque ''{1}'' está presente +dependentSchemas = há um erro com dependenteSchemas {0} +enum = não possui valor na enumeração {0} +exclusiveMaximum = deve ter um valor máximo exclusivo de {0} +exclusiveMinimum = deve ter um valor mínimo exclusivo de {0} +false = o esquema para ''{0}'' é falso +format = não corresponde ao padrão {0} +format.date = não corresponde ao padrão {0} deve ser uma data completa RFC 3339 válida +format.date-time = não corresponde ao padrão {0} deve ser uma data e hora RFC 3339 válida +format.duration = não corresponde ao padrão {0} deve ter uma duração ISO 8601 válida +format.email = não corresponde ao padrão {0} deve ser uma caixa de correio RFC 5321 válida +format.ipv4 = não corresponde ao padrão {0} deve ser um endereço IP RFC 2673 válido +format.ipv6 = não corresponde ao padrão {0} deve ser um endereço IP RFC 4291 válido +format.idn-email = não corresponde ao padrão {0} deve ser uma caixa de correio RFC 6531 válida +format.idn-hostname = não corresponde ao padrão {0} deve ser um nome de host internacionalizado RFC 5890 válido +format.iri = não corresponde ao padrão {0} deve ser um RFC 3987 IRI válido +format.iri-reference = não corresponde ao padrão {0} deve ser uma referência IRI RFC 3987 válida +format.uri = não corresponde ao padrão {0} deve ser um URI RFC 3986 válido +format.uri-reference = não corresponde ao padrão {0} deve ser uma referência de URI RFC 3986 válida +format.uri-template = não corresponde ao padrão {0} deve ser um modelo de URI RFC 6570 válido +format.uuid = não corresponde ao padrão {0} deve ser um UUID RFC 4122 válido +format.regex = não corresponde ao padrão {0} deve ser uma expressão regular ECMA-262 válida +format.time = não corresponde ao padrão {0} deve ser um horário RFC 3339 válido +format.hostname = não corresponde ao padrão {0} deve ser um nome de host RFC 1123 válido +format.json-pointer = não corresponde ao padrão {0} deve ser um ponteiro JSON RFC 6901 válido +format.relative-json-pointer = não corresponde ao padrão {0} deve ser um ponteiro JSON relativo IETF válido +format.unknown = tem um formato desconhecido ''{0}'' +id = ''{0}'' não é um {1} válido +items = o índice ''{0}'' não está definido no esquema e o esquema não permite itens adicionais +maxContains = deve ser um número inteiro não negativo em {0} +maxItems = deve ter no máximo {0} itens, mas foram encontrados {1} +maxLength = deve ter no máximo {0} caracteres +maxProperties = deve ter no máximo {0} propriedades +maximum = deve ter um valor máximo de {0} +minContains = deve ser um número inteiro não negativo em {0} +minContainsVsMaxContains = minContains deve ser menor ou igual a maxContains em {0} +minItems = deve ter pelo menos {0} itens, mas foi encontrado {1} +minLength = deve ter pelo menos {0} caracteres +minProperties = deve ter pelo menos {0} propriedades +minimum = deve ter um valor mínimo de {0} +multipleOf = deve ser múltiplo de {0} +not = não deve ser válido para o esquema {0} +notAllowed = propriedade ''{0}'' não é permitida, mas está nos dados +oneOf = deve ser válido para um e apenas um esquema, mas {0} são válidos +oneOf.indexes = deve ser válido para um e somente um esquema, mas {0} são válidos com índices ''{1}'' +pattern = não corresponde ao padrão regex {0} +patternProperties = há algum erro com ''propriedades do padrão'' +prefixItems = nenhum validador encontrado neste índice +properties = há um erro com ''propriedades'' +propertyNames = o nome da propriedade ''{0}'' não é válido: {1} +readOnly = é um campo somente leitura, não pode ser alterado +required = propriedade obrigatória ''{0}'' não encontrada +type = {0} encontrado, {1} esperado +unevaluatedItems = o índice ''{0}'' não é avaliado e o esquema não permite itens não avaliados +unevaluatedProperties = a propriedade ''{0}'' não foi avaliada e o esquema não permite propriedades não avaliadas +unionType = {0} encontrado, {1} esperado +uniqueItems = deve ter apenas itens únicos no array +writeOnly = é um campo somente gravação, não pode aparecer nos dados +contentEncoding = não corresponde à codificação de conteúdo {0} +contentMediaType = não é um conteúdo para mim diff --git a/src/main/resources/jsv-messages_ro.properties b/src/main/resources/jsv-messages_ro.properties index 3ade90c74..2c5fcbe72 100644 --- a/src/main/resources/jsv-messages_ro.properties +++ b/src/main/resources/jsv-messages_ro.properties @@ -1,70 +1,70 @@ -$ref = {0}: are o eroare cu \u201Erefs\u201D -additionalItems = {0}: indexul \u201E{1}\u201D nu este definit în schem\u0103, iar schema nu permite elemente suplimentare -additionalProperties = {0}: proprietatea \u201E{1}\u201D nu este definit\u0103 în schem\u0103, iar schema nu permite propriet\u0103\u021Bi suplimentare -allOf = {0}: trebuie s\u0103 fie valid pentru toate schemele {1} -anyOf = {0}: trebuie s\u0103 fie valid pentru oricare dintre schemele {1} -const = {0}: trebuie s\u0103 fie valoarea constant\u0103 \u201E{1}\u201D -contains = {0}: nu con\u0163ine un element care trece aceste valid\u0103ri: {2} -contains.max = {0}: trebuie s\u0103 con\u021Bin\u0103 cel mult {1} element(e) care trece aceste valid\u0103ri: {2} -contains.min = {0}: trebuie s\u0103 con\u021Bin\u0103 cel pu\u021Bin {1} element(e) care trece aceste valid\u0103ri: {2} -dependencies = {0}: are o eroare cu dependen\u021Bele {1} -dependentRequired = {0}: are o proprietate lips\u0103 ''{1}'' care este dependent\u0103 necesar\u0103 deoarece ''{2}'' este prezent -dependentSchemas = {0}: are o eroare cu dependentSchemas {1} -enum = {0}: nu are o valoare în enumerarea {1} -exclusiveMaximum = {0}: trebuie s\u0103 aib\u0103 o valoare maxim\u0103 exclusiv\u0103 de {1} -exclusiveMinimum = {0}: trebuie s\u0103 aib\u0103 o valoare minim\u0103 exclusiv\u0103 de {1} -false = {0}: schema pentru \u201E{1}\u201D este fals\u0103 -format = {0}: nu se potrive\u0219te cu modelul {1} {2} -format.date = {0}: nu se potrive\u0219te cu modelul {1} trebuie s\u0103 fie o dat\u0103 complet\u0103 RFC 3339 valid\u0103 -format.date-time = {0}: nu se potrive\u0219te cu modelul {1} trebuie s\u0103 fie un RFC 3339 data-ora valid -format.duration = {0}: nu se potrive\u0219te cu modelul {1} trebuie s\u0103 fie o durat\u0103 ISO 8601 valid\u0103 -format.email = {0}: nu se potrive\u0219te cu modelul {1} trebuie s\u0103 fie o cutie po\u0219tal\u0103 RFC 5321 valid\u0103 -format.ipv4 = {0}: nu se potrive\u0219te cu modelul {1} trebuie s\u0103 fie o adres\u0103 IP RFC 2673 valid\u0103 -format.ipv6 = {0}: nu se potrive\u0219te cu modelul {1} trebuie s\u0103 fie o adres\u0103 IP RFC 4291 valid\u0103 -format.idn-email = {0}: nu se potrive\u0219te cu modelul {1} trebuie s\u0103 fie o cutie po\u0219tal\u0103 RFC 6531 valid\u0103 -format.idn-hostname = {0}: nu se potrive\u0219te cu modelul {1} trebuie s\u0103 fie un nume de gazd\u0103 interna\u021Bionalizat RFC 5890 valid -format.iri = {0}: nu se potrive\u0219te cu modelul {1} trebuie s\u0103 fie un RFC 3987 IRI valid -format.iri-reference = {0}: nu se potrive\u0219te cu modelul {1} trebuie s\u0103 fie o referin\u021B\u0103 IRI RFC 3987 valid\u0103 -format.uri = {0}: nu se potrive\u0219te cu modelul {1} trebuie s\u0103 fie un URI RFC 3986 valid -format.uri-reference = {0}: nu se potrive\u0219te cu modelul {1} trebuie s\u0103 fie o referin\u021B\u0103 URI RFC 3986 valid\u0103 -format.uri-template = {0}: nu se potrive\u0219te cu modelul {1} trebuie s\u0103 fie un \u0219ablon URI RFC 6570 valid -format.uuid = {0}: nu se potrive\u0219te cu modelul {1} trebuie s\u0103 fie un UUID RFC 4122 valid -format.regex = {0}: nu se potrive\u0219te cu modelul {1} trebuie s\u0103 fie o expresie regulat\u0103 ECMA-262 valid\u0103 -format.time = {0}: nu se potrive\u0219te cu modelul {1} trebuie s\u0103 fie un timp RFC 3339 valid -format.hostname = {0}: nu se potrive\u0219te cu modelul {1} trebuie s\u0103 fie un nume de gazd\u0103 RFC 1123 valid -format.json-pointer = {0}: nu se potrive\u0219te cu modelul {1} trebuie s\u0103 fie un pointer JSON RFC 6901 valid -format.relative-json-pointer = {0}: nu se potrive\u0219te cu modelul {1} trebuie s\u0103 fie un pointer JSON relativ IETF valid -format.unknown = {0}: are un format necunoscut ''{1}'' -id = {0}: \u201E{1}\u201D nu este un {2} valid -items = {0}: indexul \u201E{1}\u201D nu este definit în schem\u0103, iar schema nu permite articole suplimentare -maxContains = {0}: trebuie s\u0103 fie un num\u0103r întreg nenegativ în {1} -maxItems = {0}: trebuie s\u0103 aib\u0103 cel mult {1} articole, dar g\u0103site {2} -maxLength = {0}: trebuie s\u0103 aib\u0103 cel mult {1} caractere -maxProperties = {0}: trebuie s\u0103 aib\u0103 cel mult {1} propriet\u0103\u021Bi -maximum = {0}: trebuie s\u0103 aib\u0103 o valoare maxim\u0103 de {1} -minContains = {0}: trebuie s\u0103 fie un num\u0103r întreg nenegativ în {1} -minContainsVsMaxContains = {0}: minContains trebuie s\u0103 fie mai mic sau egal cu maxContains în {1} -minItems = {0}: trebuie s\u0103 aib\u0103 cel pu\u021Bin {1} articole, dar g\u0103site {2} -minLength = {0}: trebuie s\u0103 aib\u0103 cel pu\u021Bin {1} caractere -minProperties = {0}: trebuie s\u0103 aib\u0103 cel pu\u021Bin {1} propriet\u0103\u021Bi -minimum = {0}: trebuie s\u0103 aib\u0103 o valoare minim\u0103 de {1} -multipleOf = {0}: trebuie s\u0103 fie multiplu de {1} -not = {0}: nu trebuie s\u0103 fie valid pentru schema {1} -notAllowed = {0}: proprietatea \u201E{1}\u201D nu este permis\u0103, dar este în date -oneOf = {0}: trebuie s\u0103 fie valid pentru una \u0219i doar o schem\u0103, dar {1} sunt valide -oneOf.indexes = {0}: trebuie s\u0103 fie valid pentru una \u0219i doar o schem\u0103, dar {1} sunt valide cu indec\u0219ii \u201E{2}\u201D -pattern = {0}: nu se potrive\u0219te cu modelul regex {1} -patternProperties = {0}: are o eroare cu \u201Epropriet\u0103\u021Bile modelului\u201D -prefixItems = {0}: nu a fost g\u0103sit niciun validator la acest index -properties = {0}: are o eroare cu \u201Epropriet\u0103\u021Bi\u201D -propertyNames = {0}: numele propriet\u0103\u021Bii \u201E{1}\u201D nu este valid: {2} -readOnly = {0}: este un câmp numai în citire, nu poate fi modificat -required = {0}: proprietatea obligatorie \u201E{1}\u201D nu a fost g\u0103sit\u0103 -type = {0}: {1} g\u0103sit, {2} a\u0219teptat -unevaluatedItems = {0}: indexul \u201E{1}\u201D nu este evaluat \u0219i schema nu permite elemente neevaluate -unevaluatedProperties = {0}: proprietatea \u201E{1}\u201D nu este evaluat\u0103 \u0219i schema nu permite propriet\u0103\u021Bi neevaluate -unionType = {0}: {1} g\u0103sit, {2} a\u0219teptat -uniqueItems = {0}: trebuie s\u0103 aib\u0103 numai elemente unice în matrice -writeOnly = {0}: este un câmp numai pentru scriere, nu poate ap\u0103rea în date -contentEncoding = {0}: nu se potrive\u0219te cu codificarea con\u021Binutului {1} -contentMediaType = {0}: nu este un con\u021Binut eu +$ref = are o eroare cu \u201Erefs\u201D +additionalItems = indexul \u201E{0}\u201D nu este definit în schem\u0103, iar schema nu permite elemente suplimentare +additionalProperties = proprietatea \u201E{0}\u201D nu este definit\u0103 în schem\u0103, iar schema nu permite propriet\u0103\u021Bi suplimentare +allOf = trebuie s\u0103 fie valid pentru toate schemele {0} +anyOf = trebuie s\u0103 fie valid pentru oricare dintre schemele {0} +const = trebuie s\u0103 fie valoarea constant\u0103 \u201E{0}\u201D +contains = nu con\u0163ine un element care trece aceste valid\u0103ri: {1} +contains.max = trebuie s\u0103 con\u021Bin\u0103 cel mult {0} element(e) care trece aceste valid\u0103ri: {1} +contains.min = trebuie s\u0103 con\u021Bin\u0103 cel pu\u021Bin {0} element(e) care trece aceste valid\u0103ri: {1} +dependencies = are o eroare cu dependen\u021Bele {0} +dependentRequired = are o proprietate lips\u0103 ''{0}'' care este dependent\u0103 necesar\u0103 deoarece ''{1}'' este prezent +dependentSchemas = are o eroare cu dependentSchemas {0} +enum = nu are o valoare în enumerarea {0} +exclusiveMaximum = trebuie s\u0103 aib\u0103 o valoare maxim\u0103 exclusiv\u0103 de {0} +exclusiveMinimum = trebuie s\u0103 aib\u0103 o valoare minim\u0103 exclusiv\u0103 de {0} +false = schema pentru \u201E{0}\u201D este fals\u0103 +format = nu se potrive\u0219te cu modelul {0} +format.date = nu se potrive\u0219te cu modelul {0} trebuie s\u0103 fie o dat\u0103 complet\u0103 RFC 3339 valid\u0103 +format.date-time = nu se potrive\u0219te cu modelul {0} trebuie s\u0103 fie un RFC 3339 data-ora valid +format.duration = nu se potrive\u0219te cu modelul {0} trebuie s\u0103 fie o durat\u0103 ISO 8601 valid\u0103 +format.email = nu se potrive\u0219te cu modelul {0} trebuie s\u0103 fie o cutie po\u0219tal\u0103 RFC 5321 valid\u0103 +format.ipv4 = nu se potrive\u0219te cu modelul {0} trebuie s\u0103 fie o adres\u0103 IP RFC 2673 valid\u0103 +format.ipv6 = nu se potrive\u0219te cu modelul {0} trebuie s\u0103 fie o adres\u0103 IP RFC 4291 valid\u0103 +format.idn-email = nu se potrive\u0219te cu modelul {0} trebuie s\u0103 fie o cutie po\u0219tal\u0103 RFC 6531 valid\u0103 +format.idn-hostname = nu se potrive\u0219te cu modelul {0} trebuie s\u0103 fie un nume de gazd\u0103 interna\u021Bionalizat RFC 5890 valid +format.iri = nu se potrive\u0219te cu modelul {0} trebuie s\u0103 fie un RFC 3987 IRI valid +format.iri-reference = nu se potrive\u0219te cu modelul {0} trebuie s\u0103 fie o referin\u021B\u0103 IRI RFC 3987 valid\u0103 +format.uri = nu se potrive\u0219te cu modelul {0} trebuie s\u0103 fie un URI RFC 3986 valid +format.uri-reference = nu se potrive\u0219te cu modelul {0} trebuie s\u0103 fie o referin\u021B\u0103 URI RFC 3986 valid\u0103 +format.uri-template = nu se potrive\u0219te cu modelul {0} trebuie s\u0103 fie un \u0219ablon URI RFC 6570 valid +format.uuid = nu se potrive\u0219te cu modelul {0} trebuie s\u0103 fie un UUID RFC 4122 valid +format.regex = nu se potrive\u0219te cu modelul {0} trebuie s\u0103 fie o expresie regulat\u0103 ECMA-262 valid\u0103 +format.time = nu se potrive\u0219te cu modelul {0} trebuie s\u0103 fie un timp RFC 3339 valid +format.hostname = nu se potrive\u0219te cu modelul {0} trebuie s\u0103 fie un nume de gazd\u0103 RFC 1123 valid +format.json-pointer = nu se potrive\u0219te cu modelul {0} trebuie s\u0103 fie un pointer JSON RFC 6901 valid +format.relative-json-pointer = nu se potrive\u0219te cu modelul {0} trebuie s\u0103 fie un pointer JSON relativ IETF valid +format.unknown = are un format necunoscut ''{0}'' +id = \u201E{0}\u201D nu este un {1} valid +items = indexul \u201E{0}\u201D nu este definit în schem\u0103, iar schema nu permite articole suplimentare +maxContains = trebuie s\u0103 fie un num\u0103r întreg nenegativ în {0} +maxItems = trebuie s\u0103 aib\u0103 cel mult {0} articole, dar g\u0103site {1} +maxLength = trebuie s\u0103 aib\u0103 cel mult {0} caractere +maxProperties = trebuie s\u0103 aib\u0103 cel mult {0} propriet\u0103\u021Bi +maximum = trebuie s\u0103 aib\u0103 o valoare maxim\u0103 de {0} +minContains = trebuie s\u0103 fie un num\u0103r întreg nenegativ în {0} +minContainsVsMaxContains = minContains trebuie s\u0103 fie mai mic sau egal cu maxContains în {0} +minItems = trebuie s\u0103 aib\u0103 cel pu\u021Bin {0} articole, dar g\u0103site {1} +minLength = trebuie s\u0103 aib\u0103 cel pu\u021Bin {0} caractere +minProperties = trebuie s\u0103 aib\u0103 cel pu\u021Bin {0} propriet\u0103\u021Bi +minimum = trebuie s\u0103 aib\u0103 o valoare minim\u0103 de {0} +multipleOf = trebuie s\u0103 fie multiplu de {0} +not = nu trebuie s\u0103 fie valid pentru schema {0} +notAllowed = proprietatea \u201E{0}\u201D nu este permis\u0103, dar este în date +oneOf = trebuie s\u0103 fie valid pentru una \u0219i doar o schem\u0103, dar {0} sunt valide +oneOf.indexes = trebuie s\u0103 fie valid pentru una \u0219i doar o schem\u0103, dar {0} sunt valide cu indec\u0219ii \u201E{1}\u201D +pattern = nu se potrive\u0219te cu modelul regex {0} +patternProperties = are o eroare cu \u201Epropriet\u0103\u021Bile modelului\u201D +prefixItems = nu a fost g\u0103sit niciun validator la acest index +properties = are o eroare cu \u201Epropriet\u0103\u021Bi\u201D +propertyNames = numele propriet\u0103\u021Bii \u201E{0}\u201D nu este valid: {1} +readOnly = este un câmp numai în citire, nu poate fi modificat +required = proprietatea obligatorie \u201E{0}\u201D nu a fost g\u0103sit\u0103 +type = {0} g\u0103sit, {1} a\u0219teptat +unevaluatedItems = indexul \u201E{0}\u201D nu este evaluat \u0219i schema nu permite elemente neevaluate +unevaluatedProperties = proprietatea \u201E{0}\u201D nu este evaluat\u0103 \u0219i schema nu permite propriet\u0103\u021Bi neevaluate +unionType = {0} g\u0103sit, {1} a\u0219teptat +uniqueItems = trebuie s\u0103 aib\u0103 numai elemente unice în matrice +writeOnly = este un câmp numai pentru scriere, nu poate ap\u0103rea în date +contentEncoding = nu se potrive\u0219te cu codificarea con\u021Binutului {0} +contentMediaType = nu este un con\u021Binut eu diff --git a/src/main/resources/jsv-messages_ru.properties b/src/main/resources/jsv-messages_ru.properties index 2ea8b4ef4..b0e9eaf13 100644 --- a/src/main/resources/jsv-messages_ru.properties +++ b/src/main/resources/jsv-messages_ru.properties @@ -1,70 +1,70 @@ -$ref = {0}: \u0438\u043C\u0435\u0435\u0442\u0441\u044F \u043E\u0448\u0438\u0431\u043A\u0430 \u0441 «refs». -additionalItems = {0}: \u0438\u043D\u0434\u0435\u043A\u0441 ''{1}'' \u043D\u0435 \u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0435\u043D \u0432 \u0441\u0445\u0435\u043C\u0435, \u0438 \u0441\u0445\u0435\u043C\u0430 \u043D\u0435 \u0434\u043E\u043F\u0443\u0441\u043A\u0430\u0435\u0442 \u0434\u043E\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u0445 \u044D\u043B\u0435\u043C\u0435\u043D\u0442\u043E\u0432. -additionalProperties = {0}: \u0441\u0432\u043E\u0439\u0441\u0442\u0432\u043E ''{1}'' \u043D\u0435 \u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0435\u043D\u043E \u0432 \u0441\u0445\u0435\u043C\u0435, \u0438 \u0441\u0445\u0435\u043C\u0430 \u043D\u0435 \u0434\u043E\u043F\u0443\u0441\u043A\u0430\u0435\u0442 \u0434\u043E\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u0445 \u0441\u0432\u043E\u0439\u0441\u0442\u0432. -allOf = {0}: \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u043E \u0434\u043B\u044F \u0432\u0441\u0435\u0445 \u0441\u0445\u0435\u043C {1}. -anyOf = {0}: \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u043E \u0434\u043B\u044F \u043B\u044E\u0431\u043E\u0439 \u0438\u0437 \u0441\u0445\u0435\u043C {1}. -const = {0}: \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u043F\u043E\u0441\u0442\u043E\u044F\u043D\u043D\u044B\u043C \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435\u043C ''{1}'' -contains = {0}: \u043D\u0435 \u0441\u043E\u0434\u0435\u0440\u0436\u0438\u0442 \u044D\u043B\u0435\u043C\u0435\u043D\u0442\u0430, \u043A\u043E\u0442\u043E\u0440\u044B\u0439 \u043F\u0440\u043E\u0445\u043E\u0434\u0438\u0442 \u044D\u0442\u0438 \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438: {2} -contains.max = {0}: \u0434\u043E\u043B\u0436\u0435\u043D \u0441\u043E\u0434\u0435\u0440\u0436\u0430\u0442\u044C \u043D\u0435 \u0431\u043E\u043B\u0435\u0435 {1} \u044D\u043B\u0435\u043C\u0435\u043D\u0442\u043E\u0432, \u043F\u0440\u043E\u0448\u0435\u0434\u0448\u0438\u0445 \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0438\u0435 \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438: {2} -contains.min = {0}: \u0434\u043E\u043B\u0436\u0435\u043D \u0441\u043E\u0434\u0435\u0440\u0436\u0430\u0442\u044C \u043A\u0430\u043A \u043C\u0438\u043D\u0438\u043C\u0443\u043C {1} \u044D\u043B\u0435\u043C\u0435\u043D\u0442\u043E\u0432, \u043F\u0440\u043E\u0448\u0435\u0434\u0448\u0438\u0445 \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0438\u0435 \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438: {2} -dependencies = {0}: \u0438\u043C\u0435\u0435\u0442\u0441\u044F \u043E\u0448\u0438\u0431\u043A\u0430 \u0441 \u0437\u0430\u0432\u0438\u0441\u0438\u043C\u043E\u0441\u0442\u044F\u043C\u0438 {1}. -dependentRequired = {0}: \u0438\u043C\u0435\u0435\u0442 \u043E\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u044E\u0449\u0435\u0435 \u0441\u0432\u043E\u0439\u0441\u0442\u0432\u043E ''{1}'', \u043A\u043E\u0442\u043E\u0440\u043E\u0435 \u044F\u0432\u043B\u044F\u0435\u0442\u0441\u044F \u0437\u0430\u0432\u0438\u0441\u0438\u043C\u044B\u043C, \u043F\u043E\u0441\u043A\u043E\u043B\u044C\u043A\u0443 \u043F\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 ''{2}''. -dependentSchemas = {0}: \u0438\u043C\u0435\u0435\u0442\u0441\u044F \u043E\u0448\u0438\u0431\u043A\u0430 \u0441dependentSchemas {1}. -enum = {0}: \u043D\u0435 \u0438\u043C\u0435\u0435\u0442 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u044F \u0432 \u043F\u0435\u0440\u0435\u0447\u0438\u0441\u043B\u0435\u043D\u0438\u0438 {1} -exclusiveMaximum = {0}: \u0434\u043E\u043B\u0436\u043D\u043E \u0438\u043C\u0435\u0442\u044C \u044D\u043A\u0441\u043A\u043B\u044E\u0437\u0438\u0432\u043D\u043E\u0435 \u043C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 {1}. -exclusiveMinimum = {0}: \u0434\u043E\u043B\u0436\u043D\u043E \u0438\u043C\u0435\u0442\u044C \u0438\u0441\u043A\u043B\u044E\u0447\u0438\u0442\u0435\u043B\u044C\u043D\u043E\u0435 \u043C\u0438\u043D\u0438\u043C\u0430\u043B\u044C\u043D\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 {1}. -false = {0}: \u0441\u0445\u0435\u043C\u0430 \u0434\u043B\u044F ''{1}'' \u043D\u0435\u0432\u0435\u0440\u043D\u0430 -format = {0}: \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {1} {2} -format.date = {0}: \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {1}, \u0434\u043E\u043B\u0436\u043D\u0430 \u0431\u044B\u0442\u044C \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043B\u044C\u043D\u0430\u044F \u043F\u043E\u043B\u043D\u0430\u044F \u0434\u0430\u0442\u0430 RFC 3339. -format.date-time = {0}: \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {1}, \u0434\u043E\u043B\u0436\u043D\u0430 \u0431\u044B\u0442\u044C \u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u0430\u044F \u0434\u0430\u0442\u0430-\u0432\u0440\u0435\u043C\u044F RFC 3339. -format.duration = {0}: \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {1}, \u0434\u043E\u043B\u0436\u043D\u0430 \u0431\u044B\u0442\u044C \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043B\u044C\u043D\u0430\u044F \u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0438\u0442\u0435\u043B\u044C\u043D\u043E\u0441\u0442\u044C ISO 8601. -format.email = {0}: \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {1}, \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u043C \u043F\u043E\u0447\u0442\u043E\u0432\u044B\u043C \u044F\u0449\u0438\u043A\u043E\u043C RFC 5321. -format.ipv4 = {0}: \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {1}, \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u043C IP-\u0430\u0434\u0440\u0435\u0441\u043E\u043C RFC 2673. -format.ipv6 = {0}: \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {1}, \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u043C IP-\u0430\u0434\u0440\u0435\u0441\u043E\u043C RFC 4291. -format.idn-email = {0}: \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {1}, \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u043C \u043F\u043E\u0447\u0442\u043E\u0432\u044B\u043C \u044F\u0449\u0438\u043A\u043E\u043C RFC 6531. -format.idn-hostname = {0}: \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {1}, \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u043C \u0438\u043D\u0442\u0435\u0440\u043D\u0430\u0446\u0438\u043E\u043D\u0430\u043B\u0438\u0437\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u044B\u043C \u0438\u043C\u0435\u043D\u0435\u043C \u0445\u043E\u0441\u0442\u0430 RFC 5890. -format.iri = {0}: \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {1}, \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u043C IRI RFC 3987. -format.iri-reference = {0}: \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {1}, \u0434\u043E\u043B\u0436\u043D\u0430 \u0431\u044B\u0442\u044C \u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u043E\u0439 \u0441\u0441\u044B\u043B\u043A\u043E\u0439 RFC 3987 IRI. -format.uri = {0}: \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {1}, \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u043C URI RFC 3986. -format.uri-reference = {0}: \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {1}, \u0434\u043E\u043B\u0436\u043D\u0430 \u0431\u044B\u0442\u044C \u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u043E\u0439 \u0441\u0441\u044B\u043B\u043A\u043E\u0439 URI RFC 3986. -format.uri-template = {0}: \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {1}, \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u044B\u043C \u0448\u0430\u0431\u043B\u043E\u043D\u043E\u043C URI RFC 6570. -format.uuid = {0}: \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {1}, \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u043C UUID RFC 4122. -format.regex = {0}: \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {1}, \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u044B\u043C \u0440\u0435\u0433\u0443\u043B\u044F\u0440\u043D\u044B\u043C \u0432\u044B\u0440\u0430\u0436\u0435\u043D\u0438\u0435\u043C ECMA-262. -format.time = {0}: \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {1}, \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u043E\u0435 \u0432\u0440\u0435\u043C\u044F RFC 3339. -format.hostname = {0}: \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {1}, \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u043C \u0438\u043C\u0435\u043D\u0435\u043C \u0445\u043E\u0441\u0442\u0430 RFC 1123. -format.json-pointer = {0}: \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {1}, \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u043C \u0443\u043A\u0430\u0437\u0430\u0442\u0435\u043B\u0435\u043C JSON RFC 6901. -format.relative-json-pointer = {0}: \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {1}, \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u044B\u043C \u043E\u0442\u043D\u043E\u0441\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u043C \u0443\u043A\u0430\u0437\u0430\u0442\u0435\u043B\u0435\u043C JSON IETF -format.unknown = {0}: \u0438\u043C\u0435\u0435\u0442 \u043D\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043D\u044B\u0439 \u0444\u043E\u0440\u043C\u0430\u0442 ''{1}'' -id = {0}: ''{1}'' \u043D\u0435 \u044F\u0432\u043B\u044F\u0435\u0442\u0441\u044F \u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u044B\u043C {2} -items = {0}: \u0438\u043D\u0434\u0435\u043A\u0441 ''{1}'' \u043D\u0435 \u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0435\u043D \u0432 \u0441\u0445\u0435\u043C\u0435, \u0438 \u0441\u0445\u0435\u043C\u0430 \u043D\u0435 \u0434\u043E\u043F\u0443\u0441\u043A\u0430\u0435\u0442 \u0434\u043E\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u0445 \u044D\u043B\u0435\u043C\u0435\u043D\u0442\u043E\u0432. -maxContains = {0}: \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u043D\u0435\u043E\u0442\u0440\u0438\u0446\u0430\u0442\u0435\u043B\u044C\u043D\u044B\u043C \u0446\u0435\u043B\u044B\u043C \u0447\u0438\u0441\u043B\u043E\u043C \u0432 {1}. -maxItems = {0}: \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u043D\u0435 \u0431\u043E\u043B\u0435\u0435 {1} \u044D\u043B\u0435\u043C\u0435\u043D\u0442\u043E\u0432, \u043D\u043E \u043D\u0430\u0439\u0434\u0435\u043D\u043E {2} -maxLength = {0}: \u0434\u043B\u0438\u043D\u0430 \u0434\u043E\u043B\u0436\u043D\u0430 \u0431\u044B\u0442\u044C \u043D\u0435 \u0431\u043E\u043B\u0435\u0435 {1} \u0441\u0438\u043C\u0432\u043E\u043B\u043E\u0432. -maxProperties = {0}: \u0434\u043E\u043B\u0436\u043D\u043E \u0438\u043C\u0435\u0442\u044C \u043D\u0435 \u0431\u043E\u043B\u0435\u0435 {1} \u0441\u0432\u043E\u0439\u0441\u0442\u0432. -maximum = {0}: \u043C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C {1}. -minContains = {0}: \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u043D\u0435\u043E\u0442\u0440\u0438\u0446\u0430\u0442\u0435\u043B\u044C\u043D\u044B\u043C \u0446\u0435\u043B\u044B\u043C \u0447\u0438\u0441\u043B\u043E\u043C \u0432 {1}. -minContainsVsMaxContains = {0}: minContains \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u043C\u0435\u043D\u044C\u0448\u0435 \u0438\u043B\u0438 \u0440\u0430\u0432\u043D\u043E maxContains \u0432 {1}. -minItems = {0}: \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u043D\u0435 \u043C\u0435\u043D\u0435\u0435 {1} \u044D\u043B\u0435\u043C\u0435\u043D\u0442\u043E\u0432, \u043D\u043E \u043D\u0430\u0439\u0434\u0435\u043D\u043E {2} -minLength = {0}: \u0434\u043B\u0438\u043D\u0430 \u0434\u043E\u043B\u0436\u043D\u0430 \u0431\u044B\u0442\u044C \u043D\u0435 \u043C\u0435\u043D\u0435\u0435 {1} \u0441\u0438\u043C\u0432\u043E\u043B\u043E\u0432. -minProperties = {0}: \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u043D\u0435 \u043C\u0435\u043D\u0435\u0435 {1} \u0441\u0432\u043E\u0439\u0441\u0442\u0432. -minimum = {0}: \u043C\u0438\u043D\u0438\u043C\u0430\u043B\u044C\u043D\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C {1}. -multipleOf = {0}: \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u043A\u0440\u0430\u0442\u043D\u043E {1} -not = {0}: \u043D\u0435 \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u043E \u0434\u043B\u044F \u0441\u0445\u0435\u043C\u044B {1} -notAllowed = {0}: \u0441\u0432\u043E\u0439\u0441\u0442\u0432\u043E ''{1}'' \u043D\u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043D\u043E, \u043D\u043E \u043E\u043D\u043E \u0435\u0441\u0442\u044C \u0432 \u0434\u0430\u043D\u043D\u044B\u0445 -oneOf = {0}: \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u043E \u0434\u043B\u044F \u043E\u0434\u043D\u043E\u0439 \u0438 \u0442\u043E\u043B\u044C\u043A\u043E \u043E\u0434\u043D\u043E\u0439 \u0441\u0445\u0435\u043C\u044B, \u043D\u043E {1} \u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u043E. -oneOf.indexes = {0}: \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u043E \u0434\u043B\u044F \u043E\u0434\u043D\u043E\u0439 \u0438 \u0442\u043E\u043B\u044C\u043A\u043E \u043E\u0434\u043D\u043E\u0439 \u0441\u0445\u0435\u043C\u044B, \u043D\u043E {1} \u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u043E \u0441 \u0438\u043D\u0434\u0435\u043A\u0441\u0430\u043C\u0438 ''{2}'' -pattern = {0}: \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 \u0440\u0435\u0433\u0443\u043B\u044F\u0440\u043D\u043E\u0433\u043E \u0432\u044B\u0440\u0430\u0436\u0435\u043D\u0438\u044F {1} -patternProperties = {0}: \u0438\u043C\u0435\u0435\u0442\u0441\u044F \u043D\u0435\u043A\u043E\u0442\u043E\u0440\u0430\u044F \u043E\u0448\u0438\u0431\u043A\u0430 \u0441\u043E «\u0441\u0432\u043E\u0439\u0441\u0442\u0432\u0430\u043C\u0438 \u0448\u0430\u0431\u043B\u043E\u043D\u0430». -prefixItems = {0}: \u043F\u043E \u044D\u0442\u043E\u043C\u0443 \u0438\u043D\u0434\u0435\u043A\u0441\u0443 \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D \u0432\u0430\u043B\u0438\u0434\u0430\u0442\u043E\u0440 -properties = {0}: \u0438\u043C\u0435\u0435\u0442\u0441\u044F \u043E\u0448\u0438\u0431\u043A\u0430 \u0441\u043E \u0441\u0432\u043E\u0439\u0441\u0442\u0432\u0430\u043C\u0438. -propertyNames = {0}: \u0438\u043C\u044F \u0441\u0432\u043E\u0439\u0441\u0442\u0432\u0430 ''{1}'' \u043D\u0435\u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u043E: {2} -readOnly = {0}: \u043F\u043E\u043B\u0435 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u043E \u0442\u043E\u043B\u044C\u043A\u043E \u0434\u043B\u044F \u0447\u0442\u0435\u043D\u0438\u044F, \u0435\u0433\u043E \u043D\u0435\u043B\u044C\u0437\u044F \u0438\u0437\u043C\u0435\u043D\u0438\u0442\u044C. -required = {0}: \u043D\u0435\u043E\u0431\u0445\u043E\u0434\u0438\u043C\u043E\u0435 \u0441\u0432\u043E\u0439\u0441\u0442\u0432\u043E ''{1}'' \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u043E -type = {0}: \u043D\u0430\u0439\u0434\u0435\u043D\u043E {1}, \u043E\u0436\u0438\u0434\u0430\u0435\u0442\u0441\u044F {2} -unevaluatedItems = {0}: \u0438\u043D\u0434\u0435\u043A\u0441 ''{1}'' \u043D\u0435 \u043E\u0446\u0435\u043D\u0438\u0432\u0430\u0435\u0442\u0441\u044F, \u0438 \u0441\u0445\u0435\u043C\u0430 \u043D\u0435 \u0434\u043E\u043F\u0443\u0441\u043A\u0430\u0435\u0442 \u043D\u0435\u043E\u0446\u0435\u043D\u0435\u043D\u043D\u044B\u0445 \u044D\u043B\u0435\u043C\u0435\u043D\u0442\u043E\u0432. -unevaluatedProperties = {0}: \u0441\u0432\u043E\u0439\u0441\u0442\u0432\u043E ''{1}'' \u043D\u0435 \u043E\u0446\u0435\u043D\u0438\u0432\u0430\u0435\u0442\u0441\u044F, \u0438 \u0441\u0445\u0435\u043C\u0430 \u043D\u0435 \u0434\u043E\u043F\u0443\u0441\u043A\u0430\u0435\u0442 \u043D\u0435\u043E\u0446\u0435\u043D\u0435\u043D\u043D\u044B\u0445 \u0441\u0432\u043E\u0439\u0441\u0442\u0432. -unionType = {0}: \u043D\u0430\u0439\u0434\u0435\u043D\u043E {1}, \u043E\u0436\u0438\u0434\u0430\u0435\u0442\u0441\u044F {2} -uniqueItems = {0}: \u043C\u0430\u0441\u0441\u0438\u0432 \u0434\u043E\u043B\u0436\u0435\u043D \u0441\u043E\u0434\u0435\u0440\u0436\u0430\u0442\u044C \u0442\u043E\u043B\u044C\u043A\u043E \u0443\u043D\u0438\u043A\u0430\u043B\u044C\u043D\u044B\u0435 \u044D\u043B\u0435\u043C\u0435\u043D\u0442\u044B. -writeOnly = {0}: \u043F\u043E\u043B\u0435 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u043E \u0442\u043E\u043B\u044C\u043A\u043E \u0434\u043B\u044F \u0437\u0430\u043F\u0438\u0441\u0438, \u043E\u043D\u043E \u043D\u0435 \u043C\u043E\u0436\u0435\u0442 \u043E\u0442\u043E\u0431\u0440\u0430\u0436\u0430\u0442\u044C\u0441\u044F \u0432 \u0434\u0430\u043D\u043D\u044B\u0445. -contentEncoding = {0}: \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u043A\u043E\u0434\u0438\u0440\u043E\u0432\u043A\u0435 \u043A\u043E\u043D\u0442\u0435\u043D\u0442\u0430 {1} -contentMediaType = {0}: \u043C\u0435\u043D\u044F \u043D\u0435 \u0443\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u0442 +$ref = \u0438\u043C\u0435\u0435\u0442\u0441\u044F \u043E\u0448\u0438\u0431\u043A\u0430 \u0441 «refs». +additionalItems = \u0438\u043D\u0434\u0435\u043A\u0441 ''{0}'' \u043D\u0435 \u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0435\u043D \u0432 \u0441\u0445\u0435\u043C\u0435, \u0438 \u0441\u0445\u0435\u043C\u0430 \u043D\u0435 \u0434\u043E\u043F\u0443\u0441\u043A\u0430\u0435\u0442 \u0434\u043E\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u0445 \u044D\u043B\u0435\u043C\u0435\u043D\u0442\u043E\u0432. +additionalProperties = \u0441\u0432\u043E\u0439\u0441\u0442\u0432\u043E ''{0}'' \u043D\u0435 \u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0435\u043D\u043E \u0432 \u0441\u0445\u0435\u043C\u0435, \u0438 \u0441\u0445\u0435\u043C\u0430 \u043D\u0435 \u0434\u043E\u043F\u0443\u0441\u043A\u0430\u0435\u0442 \u0434\u043E\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u0445 \u0441\u0432\u043E\u0439\u0441\u0442\u0432. +allOf = \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u043E \u0434\u043B\u044F \u0432\u0441\u0435\u0445 \u0441\u0445\u0435\u043C {0}. +anyOf = \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u043E \u0434\u043B\u044F \u043B\u044E\u0431\u043E\u0439 \u0438\u0437 \u0441\u0445\u0435\u043C {0}. +const = \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u043F\u043E\u0441\u0442\u043E\u044F\u043D\u043D\u044B\u043C \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435\u043C ''{0}'' +contains = \u043D\u0435 \u0441\u043E\u0434\u0435\u0440\u0436\u0438\u0442 \u044D\u043B\u0435\u043C\u0435\u043D\u0442\u0430, \u043A\u043E\u0442\u043E\u0440\u044B\u0439 \u043F\u0440\u043E\u0445\u043E\u0434\u0438\u0442 \u044D\u0442\u0438 \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438: {1} +contains.max = \u0434\u043E\u043B\u0436\u0435\u043D \u0441\u043E\u0434\u0435\u0440\u0436\u0430\u0442\u044C \u043D\u0435 \u0431\u043E\u043B\u0435\u0435 {0} \u044D\u043B\u0435\u043C\u0435\u043D\u0442\u043E\u0432, \u043F\u0440\u043E\u0448\u0435\u0434\u0448\u0438\u0445 \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0438\u0435 \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438: {1} +contains.min = \u0434\u043E\u043B\u0436\u0435\u043D \u0441\u043E\u0434\u0435\u0440\u0436\u0430\u0442\u044C \u043A\u0430\u043A \u043C\u0438\u043D\u0438\u043C\u0443\u043C {0} \u044D\u043B\u0435\u043C\u0435\u043D\u0442\u043E\u0432, \u043F\u0440\u043E\u0448\u0435\u0434\u0448\u0438\u0445 \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0438\u0435 \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438: {1} +dependencies = \u0438\u043C\u0435\u0435\u0442\u0441\u044F \u043E\u0448\u0438\u0431\u043A\u0430 \u0441 \u0437\u0430\u0432\u0438\u0441\u0438\u043C\u043E\u0441\u0442\u044F\u043C\u0438 {0}. +dependentRequired = \u0438\u043C\u0435\u0435\u0442 \u043E\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u044E\u0449\u0435\u0435 \u0441\u0432\u043E\u0439\u0441\u0442\u0432\u043E ''{0}'', \u043A\u043E\u0442\u043E\u0440\u043E\u0435 \u044F\u0432\u043B\u044F\u0435\u0442\u0441\u044F \u0437\u0430\u0432\u0438\u0441\u0438\u043C\u044B\u043C, \u043F\u043E\u0441\u043A\u043E\u043B\u044C\u043A\u0443 \u043F\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 ''{1}''. +dependentSchemas = \u0438\u043C\u0435\u0435\u0442\u0441\u044F \u043E\u0448\u0438\u0431\u043A\u0430 \u0441dependentSchemas {0}. +enum = \u043D\u0435 \u0438\u043C\u0435\u0435\u0442 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u044F \u0432 \u043F\u0435\u0440\u0435\u0447\u0438\u0441\u043B\u0435\u043D\u0438\u0438 {0} +exclusiveMaximum = \u0434\u043E\u043B\u0436\u043D\u043E \u0438\u043C\u0435\u0442\u044C \u044D\u043A\u0441\u043A\u043B\u044E\u0437\u0438\u0432\u043D\u043E\u0435 \u043C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 {0}. +exclusiveMinimum = \u0434\u043E\u043B\u0436\u043D\u043E \u0438\u043C\u0435\u0442\u044C \u0438\u0441\u043A\u043B\u044E\u0447\u0438\u0442\u0435\u043B\u044C\u043D\u043E\u0435 \u043C\u0438\u043D\u0438\u043C\u0430\u043B\u044C\u043D\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 {0}. +false = \u0441\u0445\u0435\u043C\u0430 \u0434\u043B\u044F ''{0}'' \u043D\u0435\u0432\u0435\u0440\u043D\u0430 +format = \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {0} +format.date = \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {0}, \u0434\u043E\u043B\u0436\u043D\u0430 \u0431\u044B\u0442\u044C \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043B\u044C\u043D\u0430\u044F \u043F\u043E\u043B\u043D\u0430\u044F \u0434\u0430\u0442\u0430 RFC 3339. +format.date-time = \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {0}, \u0434\u043E\u043B\u0436\u043D\u0430 \u0431\u044B\u0442\u044C \u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u0430\u044F \u0434\u0430\u0442\u0430-\u0432\u0440\u0435\u043C\u044F RFC 3339. +format.duration = \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {0}, \u0434\u043E\u043B\u0436\u043D\u0430 \u0431\u044B\u0442\u044C \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043B\u044C\u043D\u0430\u044F \u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0438\u0442\u0435\u043B\u044C\u043D\u043E\u0441\u0442\u044C ISO 8601. +format.email = \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {0}, \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u043C \u043F\u043E\u0447\u0442\u043E\u0432\u044B\u043C \u044F\u0449\u0438\u043A\u043E\u043C RFC 5321. +format.ipv4 = \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {0}, \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u043C IP-\u0430\u0434\u0440\u0435\u0441\u043E\u043C RFC 2673. +format.ipv6 = \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {0}, \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u043C IP-\u0430\u0434\u0440\u0435\u0441\u043E\u043C RFC 4291. +format.idn-email = \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {0}, \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u043C \u043F\u043E\u0447\u0442\u043E\u0432\u044B\u043C \u044F\u0449\u0438\u043A\u043E\u043C RFC 6531. +format.idn-hostname = \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {0}, \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u043C \u0438\u043D\u0442\u0435\u0440\u043D\u0430\u0446\u0438\u043E\u043D\u0430\u043B\u0438\u0437\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u044B\u043C \u0438\u043C\u0435\u043D\u0435\u043C \u0445\u043E\u0441\u0442\u0430 RFC 5890. +format.iri = \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {0}, \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u043C IRI RFC 3987. +format.iri-reference = \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {0}, \u0434\u043E\u043B\u0436\u043D\u0430 \u0431\u044B\u0442\u044C \u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u043E\u0439 \u0441\u0441\u044B\u043B\u043A\u043E\u0439 RFC 3987 IRI. +format.uri = \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {0}, \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u043C URI RFC 3986. +format.uri-reference = \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {0}, \u0434\u043E\u043B\u0436\u043D\u0430 \u0431\u044B\u0442\u044C \u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u043E\u0439 \u0441\u0441\u044B\u043B\u043A\u043E\u0439 URI RFC 3986. +format.uri-template = \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {0}, \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u044B\u043C \u0448\u0430\u0431\u043B\u043E\u043D\u043E\u043C URI RFC 6570. +format.uuid = \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {0}, \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u043C UUID RFC 4122. +format.regex = \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {0}, \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u044B\u043C \u0440\u0435\u0433\u0443\u043B\u044F\u0440\u043D\u044B\u043C \u0432\u044B\u0440\u0430\u0436\u0435\u043D\u0438\u0435\u043C ECMA-262. +format.time = \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {0}, \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u043E\u0435 \u0432\u0440\u0435\u043C\u044F RFC 3339. +format.hostname = \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {0}, \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u043C \u0438\u043C\u0435\u043D\u0435\u043C \u0445\u043E\u0441\u0442\u0430 RFC 1123. +format.json-pointer = \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {0}, \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u043C \u0443\u043A\u0430\u0437\u0430\u0442\u0435\u043B\u0435\u043C JSON RFC 6901. +format.relative-json-pointer = \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {0}, \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u044B\u043C \u043E\u0442\u043D\u043E\u0441\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u043C \u0443\u043A\u0430\u0437\u0430\u0442\u0435\u043B\u0435\u043C JSON IETF +format.unknown = \u0438\u043C\u0435\u0435\u0442 \u043D\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043D\u044B\u0439 \u0444\u043E\u0440\u043C\u0430\u0442 ''{0}'' +id = ''{0}'' \u043D\u0435 \u044F\u0432\u043B\u044F\u0435\u0442\u0441\u044F \u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u044B\u043C {1} +items = \u0438\u043D\u0434\u0435\u043A\u0441 ''{0}'' \u043D\u0435 \u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0435\u043D \u0432 \u0441\u0445\u0435\u043C\u0435, \u0438 \u0441\u0445\u0435\u043C\u0430 \u043D\u0435 \u0434\u043E\u043F\u0443\u0441\u043A\u0430\u0435\u0442 \u0434\u043E\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u0445 \u044D\u043B\u0435\u043C\u0435\u043D\u0442\u043E\u0432. +maxContains = \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u043D\u0435\u043E\u0442\u0440\u0438\u0446\u0430\u0442\u0435\u043B\u044C\u043D\u044B\u043C \u0446\u0435\u043B\u044B\u043C \u0447\u0438\u0441\u043B\u043E\u043C \u0432 {0}. +maxItems = \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u043D\u0435 \u0431\u043E\u043B\u0435\u0435 {0} \u044D\u043B\u0435\u043C\u0435\u043D\u0442\u043E\u0432, \u043D\u043E \u043D\u0430\u0439\u0434\u0435\u043D\u043E {1} +maxLength = \u0434\u043B\u0438\u043D\u0430 \u0434\u043E\u043B\u0436\u043D\u0430 \u0431\u044B\u0442\u044C \u043D\u0435 \u0431\u043E\u043B\u0435\u0435 {0} \u0441\u0438\u043C\u0432\u043E\u043B\u043E\u0432. +maxProperties = \u0434\u043E\u043B\u0436\u043D\u043E \u0438\u043C\u0435\u0442\u044C \u043D\u0435 \u0431\u043E\u043B\u0435\u0435 {0} \u0441\u0432\u043E\u0439\u0441\u0442\u0432. +maximum = \u043C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C {0}. +minContains = \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u043D\u0435\u043E\u0442\u0440\u0438\u0446\u0430\u0442\u0435\u043B\u044C\u043D\u044B\u043C \u0446\u0435\u043B\u044B\u043C \u0447\u0438\u0441\u043B\u043E\u043C \u0432 {0}. +minContainsVsMaxContains = minContains \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u043C\u0435\u043D\u044C\u0448\u0435 \u0438\u043B\u0438 \u0440\u0430\u0432\u043D\u043E maxContains \u0432 {0}. +minItems = \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u043D\u0435 \u043C\u0435\u043D\u0435\u0435 {0} \u044D\u043B\u0435\u043C\u0435\u043D\u0442\u043E\u0432, \u043D\u043E \u043D\u0430\u0439\u0434\u0435\u043D\u043E {1} +minLength = \u0434\u043B\u0438\u043D\u0430 \u0434\u043E\u043B\u0436\u043D\u0430 \u0431\u044B\u0442\u044C \u043D\u0435 \u043C\u0435\u043D\u0435\u0435 {0} \u0441\u0438\u043C\u0432\u043E\u043B\u043E\u0432. +minProperties = \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u043D\u0435 \u043C\u0435\u043D\u0435\u0435 {0} \u0441\u0432\u043E\u0439\u0441\u0442\u0432. +minimum = \u043C\u0438\u043D\u0438\u043C\u0430\u043B\u044C\u043D\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C {0}. +multipleOf = \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u043A\u0440\u0430\u0442\u043D\u043E {0} +not = \u043D\u0435 \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u043E \u0434\u043B\u044F \u0441\u0445\u0435\u043C\u044B {0} +notAllowed = \u0441\u0432\u043E\u0439\u0441\u0442\u0432\u043E ''{0}'' \u043D\u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043D\u043E, \u043D\u043E \u043E\u043D\u043E \u0435\u0441\u0442\u044C \u0432 \u0434\u0430\u043D\u043D\u044B\u0445 +oneOf = \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u043E \u0434\u043B\u044F \u043E\u0434\u043D\u043E\u0439 \u0438 \u0442\u043E\u043B\u044C\u043A\u043E \u043E\u0434\u043D\u043E\u0439 \u0441\u0445\u0435\u043C\u044B, \u043D\u043E {0} \u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u043E. +oneOf.indexes = \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u043E \u0434\u043B\u044F \u043E\u0434\u043D\u043E\u0439 \u0438 \u0442\u043E\u043B\u044C\u043A\u043E \u043E\u0434\u043D\u043E\u0439 \u0441\u0445\u0435\u043C\u044B, \u043D\u043E {0} \u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u043E \u0441 \u0438\u043D\u0434\u0435\u043A\u0441\u0430\u043C\u0438 ''{1}'' +pattern = \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 \u0440\u0435\u0433\u0443\u043B\u044F\u0440\u043D\u043E\u0433\u043E \u0432\u044B\u0440\u0430\u0436\u0435\u043D\u0438\u044F {0} +patternProperties = \u0438\u043C\u0435\u0435\u0442\u0441\u044F \u043D\u0435\u043A\u043E\u0442\u043E\u0440\u0430\u044F \u043E\u0448\u0438\u0431\u043A\u0430 \u0441\u043E «\u0441\u0432\u043E\u0439\u0441\u0442\u0432\u0430\u043C\u0438 \u0448\u0430\u0431\u043B\u043E\u043D\u0430». +prefixItems = \u043F\u043E \u044D\u0442\u043E\u043C\u0443 \u0438\u043D\u0434\u0435\u043A\u0441\u0443 \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D \u0432\u0430\u043B\u0438\u0434\u0430\u0442\u043E\u0440 +properties = \u0438\u043C\u0435\u0435\u0442\u0441\u044F \u043E\u0448\u0438\u0431\u043A\u0430 \u0441\u043E \u0441\u0432\u043E\u0439\u0441\u0442\u0432\u0430\u043C\u0438. +propertyNames = \u0438\u043C\u044F \u0441\u0432\u043E\u0439\u0441\u0442\u0432\u0430 ''{0}'' \u043D\u0435\u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u043E: {1} +readOnly = \u043F\u043E\u043B\u0435 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u043E \u0442\u043E\u043B\u044C\u043A\u043E \u0434\u043B\u044F \u0447\u0442\u0435\u043D\u0438\u044F, \u0435\u0433\u043E \u043D\u0435\u043B\u044C\u0437\u044F \u0438\u0437\u043C\u0435\u043D\u0438\u0442\u044C. +required = \u043D\u0435\u043E\u0431\u0445\u043E\u0434\u0438\u043C\u043E\u0435 \u0441\u0432\u043E\u0439\u0441\u0442\u0432\u043E ''{0}'' \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u043E +type = \u043D\u0430\u0439\u0434\u0435\u043D\u043E {0}, \u043E\u0436\u0438\u0434\u0430\u0435\u0442\u0441\u044F {1} +unevaluatedItems = \u0438\u043D\u0434\u0435\u043A\u0441 ''{0}'' \u043D\u0435 \u043E\u0446\u0435\u043D\u0438\u0432\u0430\u0435\u0442\u0441\u044F, \u0438 \u0441\u0445\u0435\u043C\u0430 \u043D\u0435 \u0434\u043E\u043F\u0443\u0441\u043A\u0430\u0435\u0442 \u043D\u0435\u043E\u0446\u0435\u043D\u0435\u043D\u043D\u044B\u0445 \u044D\u043B\u0435\u043C\u0435\u043D\u0442\u043E\u0432. +unevaluatedProperties = \u0441\u0432\u043E\u0439\u0441\u0442\u0432\u043E ''{0}'' \u043D\u0435 \u043E\u0446\u0435\u043D\u0438\u0432\u0430\u0435\u0442\u0441\u044F, \u0438 \u0441\u0445\u0435\u043C\u0430 \u043D\u0435 \u0434\u043E\u043F\u0443\u0441\u043A\u0430\u0435\u0442 \u043D\u0435\u043E\u0446\u0435\u043D\u0435\u043D\u043D\u044B\u0445 \u0441\u0432\u043E\u0439\u0441\u0442\u0432. +unionType = \u043D\u0430\u0439\u0434\u0435\u043D\u043E {0}, \u043E\u0436\u0438\u0434\u0430\u0435\u0442\u0441\u044F {1} +uniqueItems = \u043C\u0430\u0441\u0441\u0438\u0432 \u0434\u043E\u043B\u0436\u0435\u043D \u0441\u043E\u0434\u0435\u0440\u0436\u0430\u0442\u044C \u0442\u043E\u043B\u044C\u043A\u043E \u0443\u043D\u0438\u043A\u0430\u043B\u044C\u043D\u044B\u0435 \u044D\u043B\u0435\u043C\u0435\u043D\u0442\u044B. +writeOnly = \u043F\u043E\u043B\u0435 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u043E \u0442\u043E\u043B\u044C\u043A\u043E \u0434\u043B\u044F \u0437\u0430\u043F\u0438\u0441\u0438, \u043E\u043D\u043E \u043D\u0435 \u043C\u043E\u0436\u0435\u0442 \u043E\u0442\u043E\u0431\u0440\u0430\u0436\u0430\u0442\u044C\u0441\u044F \u0432 \u0434\u0430\u043D\u043D\u044B\u0445. +contentEncoding = \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u043A\u043E\u0434\u0438\u0440\u043E\u0432\u043A\u0435 \u043A\u043E\u043D\u0442\u0435\u043D\u0442\u0430 {0} +contentMediaType = \u043C\u0435\u043D\u044F \u043D\u0435 \u0443\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u0442 diff --git a/src/main/resources/jsv-messages_sk.properties b/src/main/resources/jsv-messages_sk.properties index 63e3329e9..68a4d5732 100644 --- a/src/main/resources/jsv-messages_sk.properties +++ b/src/main/resources/jsv-messages_sk.properties @@ -1,70 +1,70 @@ -$ref = {0}: obsahuje chybu s ''refs'' -additionalItems = {0}: index ''{1}'' nie je definovaný v schéme a schéma nepovo\u013Euje \u010Fal\u0161ie polo\u017Eky -additionalProperties = {0}: vlastnos\u0165 ''{1}'' nie je definovaná v schéme a schéma neumo\u017E\u0148uje \u010Fal\u0161ie vlastnosti -allOf = {0}: musí by\u0165 platné pre v\u0161etky schémy {1} -anyOf = {0}: musí by\u0165 platné pre ktorúko\u013Evek schému {1} -const = {0}: musí by\u0165 kon\u0161tantná hodnota ''{1}'' -contains = {0}: neobsahuje prvok, ktorý vyhovuje týmto overeniam: {2} -contains.max = {0}: musí obsahova\u0165 najviac {1} prvkov, ktoré prejdú týmito overeniami: {2} -contains.min = {0}: musí obsahova\u0165 aspo\u0148 {1} prvkov, ktoré prejdú týmito overeniami: {2} -dependencies = {0}: obsahuje chybu so závislos\u0165ami {1} -dependentRequired = {0}: má chýbajúcu vlastnos\u0165 ''{1}'', ktorá je závislá vy\u017Eadovaná, preto\u017Ee ''{2}'' je prítomná -dependentSchemas = {0}: obsahuje chybu s dependentSchemas {1} -enum = {0}: nemá hodnotu v enumerácii {1} -exclusiveMaximum = {0}: musí ma\u0165 výlu\u010Dnú maximálnu hodnotu {1} -exclusiveMinimum = {0}: musí ma\u0165 výlu\u010Dnú minimálnu hodnotu {1} -false = {0}: schéma pre ''{1}'' je nepravda -format = {0}: nezhoduje sa so vzorom {1} {2} -format.date = {0}: nezhoduje sa so vzorom {1}, musí to by\u0165 platný úplný dátum RFC 3339 -format.date-time = {0}: nezhoduje sa so vzorom {1}, musí to by\u0165 platný dátum a \u010Das RFC 3339 -format.duration = {0}: nezhoduje sa so vzorom {1}, musí ma\u0165 platné trvanie ISO 8601 -format.email = {0}: nezhoduje sa so vzorom {1}, musí to by\u0165 platná po\u0161tová schránka RFC 5321 -format.ipv4 = {0}: nezhoduje sa so vzorom {1}, musí to by\u0165 platná adresa IP RFC 2673 -format.ipv6 = {0}: nezhoduje sa so vzorom {1}, musí to by\u0165 platná adresa IP RFC 4291 -format.idn-email = {0}: nezhoduje sa so vzorom {1}, musí to by\u0165 platná po\u0161tová schránka RFC 6531 -format.idn-hostname = {0}: nezhoduje sa so vzorom {1}, musí to by\u0165 platný medzinárodný názov hostite\u013Ea pod\u013Ea RFC 5890 -format.iri = {0}: nezhoduje sa so vzorom {1} musí by\u0165 platný RFC 3987 IRI -format.iri-reference = {0}: nezhoduje sa so vzorom {1}, musí to by\u0165 platný RFC 3987 IRI-reference -format.uri = {0}: nezhoduje sa so vzorom {1}, musí by\u0165 platný RFC 3986 URI -format.uri-reference = {0}: nezhoduje sa so vzorom {1}, musí to by\u0165 platný odkaz URI RFC 3986 -format.uri-template = {0}: nezhoduje sa so vzorom {1}, musí to by\u0165 platná \u0161ablóna URI RFC 6570 -format.uuid = {0}: nezhoduje sa so vzorom {1}, musí to by\u0165 platný UUID RFC 4122 -format.regex = {0}: nezhoduje sa so vzorom {1}, musí to by\u0165 platný regulárny výraz ECMA-262 -format.time = {0}: nezhoduje sa so vzorom {1}, musí to by\u0165 platný \u010Das RFC 3339 -format.hostname = {0}: nezhoduje sa so vzorom {1}, musí to by\u0165 platný názov hostite\u013Ea RFC 1123 -format.json-pointer = {0}: nezhoduje sa so vzorom {1}, musí to by\u0165 platný ukazovate\u013E RFC 6901 JSON -format.relative-json-pointer = {0}: nezhoduje sa so vzorom {1}, musí by\u0165 platným IETF relatívnym ukazovate\u013Eom JSON -format.unknown = {0}: má neznámy formát ''{1}'' -id = {0}: ''{1}'' nie je platný {2} -items = {0}: index ''{1}'' nie je definovaný v schéme a schéma nepovo\u013Euje \u010Fal\u0161ie polo\u017Eky -maxContains = {0}: musí by\u0165 nezáporné celé \u010Díslo v {1} -maxItems = {0}: musí ma\u0165 najviac {1} polo\u017Eiek, ale nájdených {2} -maxLength = {0}: musí ma\u0165 maximálne {1} znakov -maxProperties = {0}: musí ma\u0165 najviac {1} vlastností -maximum = {0}: musí ma\u0165 maximálnu hodnotu {1} -minContains = {0}: musí by\u0165 nezáporné celé \u010Díslo v {1} -minContainsVsMaxContains = {0}: minContains musí by\u0165 men\u0161í alebo rovný maxContains v {1} -minItems = {0}: musí ma\u0165 aspo\u0148 {1} polo\u017Eiek, ale nájdených {2} -minLength = {0}: musí ma\u0165 aspo\u0148 {1} znakov -minProperties = {0}: musí ma\u0165 aspo\u0148 {1} vlastností -minimum = {0}: musí ma\u0165 minimálnu hodnotu {1} -multipleOf = {0}: musí by\u0165 násobkom {1} -not = {0}: nesmie by\u0165 platné pre schému {1} -notAllowed = {0}: vlastnos\u0165 ''{1}'' nie je povolená, ale je v údajoch -oneOf = {0}: musí by\u0165 platné pre jednu a iba jednu schému, ale {1} sú platné -oneOf.indexes = {0}: musí by\u0165 platné pre jednu a iba jednu schému, ale {1} sú platné s indexmi ''{2}'' -pattern = {0}: nezodpovedá vzoru regulárneho výrazu {1} -patternProperties = {0}: obsahuje nejakú chybu s ''vlastnos\u0165ami vzoru'' -prefixItems = {0}: v tomto indexe sa nena\u0161iel \u017Eiadny validátor -properties = {0}: obsahuje chybu s ''vlastnosti'' -propertyNames = {0}: názov vlastnosti ''{1}'' nie je platný: {2} -readOnly = {0}: je pole len na \u010Dítanie, nemo\u017Eno ho zmeni\u0165 -required = {0}: po\u017Eadovaná vlastnos\u0165 ''{1}'' sa nena\u0161la -type = {0}: nájdených {1}, o\u010Dakávaných {2} -unevaluatedItems = {0}: index ''{1}'' nie je vyhodnotený a schéma nepovo\u013Euje nehodnotené polo\u017Eky -unevaluatedProperties = {0}: vlastnos\u0165 ''{1}'' nie je vyhodnotená a schéma nepovo\u013Euje nehodnotené vlastnosti -unionType = {0}: nájdených {1}, o\u010Dakávaných {2} -uniqueItems = {0}: v poli musia by\u0165 iba jedine\u010Dné polo\u017Eky -writeOnly = {0}: je pole ur\u010Dené len na zápis, nemô\u017Ee sa objavi\u0165 v údajoch -contentEncoding = {0}: nezhoduje sa s kódovaním obsahu {1} -contentMediaType = {0}: nie je obsah ja +$ref = obsahuje chybu s ''refs'' +additionalItems = index ''{0}'' nie je definovaný v schéme a schéma nepovo\u013Euje \u010Fal\u0161ie polo\u017Eky +additionalProperties = vlastnos\u0165 ''{0}'' nie je definovaná v schéme a schéma neumo\u017E\u0148uje \u010Fal\u0161ie vlastnosti +allOf = musí by\u0165 platné pre v\u0161etky schémy {0} +anyOf = musí by\u0165 platné pre ktorúko\u013Evek schému {0} +const = musí by\u0165 kon\u0161tantná hodnota ''{0}'' +contains = neobsahuje prvok, ktorý vyhovuje týmto overeniam: {1} +contains.max = musí obsahova\u0165 najviac {0} prvkov, ktoré prejdú týmito overeniami: {1} +contains.min = musí obsahova\u0165 aspo\u0148 {0} prvkov, ktoré prejdú týmito overeniami: {1} +dependencies = obsahuje chybu so závislos\u0165ami {0} +dependentRequired = má chýbajúcu vlastnos\u0165 ''{0}'', ktorá je závislá vy\u017Eadovaná, preto\u017Ee ''{1}'' je prítomná +dependentSchemas = obsahuje chybu s dependentSchemas {0} +enum = nemá hodnotu v enumerácii {0} +exclusiveMaximum = musí ma\u0165 výlu\u010Dnú maximálnu hodnotu {0} +exclusiveMinimum = musí ma\u0165 výlu\u010Dnú minimálnu hodnotu {0} +false = schéma pre ''{0}'' je nepravda +format = nezhoduje sa so vzorom {0} +format.date = nezhoduje sa so vzorom {0}, musí to by\u0165 platný úplný dátum RFC 3339 +format.date-time = nezhoduje sa so vzorom {0}, musí to by\u0165 platný dátum a \u010Das RFC 3339 +format.duration = nezhoduje sa so vzorom {0}, musí ma\u0165 platné trvanie ISO 8601 +format.email = nezhoduje sa so vzorom {0}, musí to by\u0165 platná po\u0161tová schránka RFC 5321 +format.ipv4 = nezhoduje sa so vzorom {0}, musí to by\u0165 platná adresa IP RFC 2673 +format.ipv6 = nezhoduje sa so vzorom {0}, musí to by\u0165 platná adresa IP RFC 4291 +format.idn-email = nezhoduje sa so vzorom {0}, musí to by\u0165 platná po\u0161tová schránka RFC 6531 +format.idn-hostname = nezhoduje sa so vzorom {0}, musí to by\u0165 platný medzinárodný názov hostite\u013Ea pod\u013Ea RFC 5890 +format.iri = nezhoduje sa so vzorom {0} musí by\u0165 platný RFC 3987 IRI +format.iri-reference = nezhoduje sa so vzorom {0}, musí to by\u0165 platný RFC 3987 IRI-reference +format.uri = nezhoduje sa so vzorom {0}, musí by\u0165 platný RFC 3986 URI +format.uri-reference = nezhoduje sa so vzorom {0}, musí to by\u0165 platný odkaz URI RFC 3986 +format.uri-template = nezhoduje sa so vzorom {0}, musí to by\u0165 platná \u0161ablóna URI RFC 6570 +format.uuid = nezhoduje sa so vzorom {0}, musí to by\u0165 platný UUID RFC 4122 +format.regex = nezhoduje sa so vzorom {0}, musí to by\u0165 platný regulárny výraz ECMA-262 +format.time = nezhoduje sa so vzorom {0}, musí to by\u0165 platný \u010Das RFC 3339 +format.hostname = nezhoduje sa so vzorom {0}, musí to by\u0165 platný názov hostite\u013Ea RFC 1123 +format.json-pointer = nezhoduje sa so vzorom {0}, musí to by\u0165 platný ukazovate\u013E RFC 6901 JSON +format.relative-json-pointer = nezhoduje sa so vzorom {0}, musí by\u0165 platným IETF relatívnym ukazovate\u013Eom JSON +format.unknown = má neznámy formát ''{0}'' +id = ''{0}'' nie je platný {1} +items = index ''{0}'' nie je definovaný v schéme a schéma nepovo\u013Euje \u010Fal\u0161ie polo\u017Eky +maxContains = musí by\u0165 nezáporné celé \u010Díslo v {0} +maxItems = musí ma\u0165 najviac {0} polo\u017Eiek, ale nájdených {1} +maxLength = musí ma\u0165 maximálne {0} znakov +maxProperties = musí ma\u0165 najviac {0} vlastností +maximum = musí ma\u0165 maximálnu hodnotu {0} +minContains = musí by\u0165 nezáporné celé \u010Díslo v {0} +minContainsVsMaxContains = minContains musí by\u0165 men\u0161í alebo rovný maxContains v {0} +minItems = musí ma\u0165 aspo\u0148 {0} polo\u017Eiek, ale nájdených {1} +minLength = musí ma\u0165 aspo\u0148 {0} znakov +minProperties = musí ma\u0165 aspo\u0148 {0} vlastností +minimum = musí ma\u0165 minimálnu hodnotu {0} +multipleOf = musí by\u0165 násobkom {0} +not = nesmie by\u0165 platné pre schému {0} +notAllowed = vlastnos\u0165 ''{0}'' nie je povolená, ale je v údajoch +oneOf = musí by\u0165 platné pre jednu a iba jednu schému, ale {0} sú platné +oneOf.indexes = musí by\u0165 platné pre jednu a iba jednu schému, ale {0} sú platné s indexmi ''{1}'' +pattern = nezodpovedá vzoru regulárneho výrazu {0} +patternProperties = obsahuje nejakú chybu s ''vlastnos\u0165ami vzoru'' +prefixItems = v tomto indexe sa nena\u0161iel \u017Eiadny validátor +properties = obsahuje chybu s ''vlastnosti'' +propertyNames = názov vlastnosti ''{0}'' nie je platný: {1} +readOnly = je pole len na \u010Dítanie, nemo\u017Eno ho zmeni\u0165 +required = po\u017Eadovaná vlastnos\u0165 ''{0}'' sa nena\u0161la +type = nájdených {0}, o\u010Dakávaných {1} +unevaluatedItems = index ''{0}'' nie je vyhodnotený a schéma nepovo\u013Euje nehodnotené polo\u017Eky +unevaluatedProperties = vlastnos\u0165 ''{0}'' nie je vyhodnotená a schéma nepovo\u013Euje nehodnotené vlastnosti +unionType = nájdených {0}, o\u010Dakávaných {1} +uniqueItems = v poli musia by\u0165 iba jedine\u010Dné polo\u017Eky +writeOnly = je pole ur\u010Dené len na zápis, nemô\u017Ee sa objavi\u0165 v údajoch +contentEncoding = nezhoduje sa s kódovaním obsahu {0} +contentMediaType = nie je obsah ja diff --git a/src/main/resources/jsv-messages_sv.properties b/src/main/resources/jsv-messages_sv.properties index b9dc6ffc0..7d969a797 100644 --- a/src/main/resources/jsv-messages_sv.properties +++ b/src/main/resources/jsv-messages_sv.properties @@ -1,70 +1,70 @@ -$ref = {0}: har ett fel med ''refs'' -additionalItems = {0}: index ''{1}'' är inte definierat i schemat och schemat tillåter inte ytterligare objekt -additionalProperties = {0}: egenskapen ''{1}'' är inte definierad i schemat och schemat tillåter inte ytterligare egenskaper -allOf = {0}: måste vara giltig för alla scheman {1} -anyOf = {0}: måste vara giltigt för något av schemana {1} -const = {0}: måste vara det konstanta värdet ''{1}'' -contains = {0}: innehåller inte ett element som klarar dessa valideringar: {2} -contains.max = {0}: måste innehålla högst {1} element som klarar dessa valideringar: {2} -contains.min = {0}: måste innehålla minst {1} element som klarar dessa valideringar: {2} -dependencies = {0}: har ett fel med beroenden {1} -dependentRequired = {0}: har en saknad egenskap ''{1}'' som är beroende krävs eftersom ''{2}'' är närvarande -dependentSchemas = {0}: har ett fel med dependentSchemas {1} -enum = {0}: har inget värde i uppräkningen {1} -exclusiveMaximum = {0}: måste ha ett exklusivt maxvärde på {1} -exclusiveMinimum = {0}: måste ha ett exklusivt lägsta värde på {1} -false = {0}: schemat för ''{1}'' är falskt -format = {0}: matchar inte {1}-mönstret {2} -format.date = {0}: matchar inte {1}-mönstret måste vara ett giltigt RFC 3339 fulldatum -format.date-time = {0}: matchar inte {1}-mönstret måste vara ett giltigt RFC 3339 datum-tid -format.duration = {0}: matchar inte {1}-mönstret måste vara en giltig ISO 8601-varaktighet -format.email = {0}: matchar inte {1}-mönstret måste vara en giltig RFC 5321-postlåda -format.ipv4 = {0}: matchar inte mönstret {1} måste vara en giltig RFC 2673 IP-adress -format.ipv6 = {0}: matchar inte {1}-mönstret måste vara en giltig RFC 4291 IP-adress -format.idn-email = {0}: matchar inte {1}-mönstret måste vara en giltig RFC 6531-postlåda -format.idn-hostname = {0}: matchar inte mönstret {1} måste vara ett giltigt RFC 5890 internationaliserat värdnamn -format.iri = {0}: matchar inte {1}-mönstret måste vara en giltig RFC 3987 IRI -format.iri-reference = {0}: matchar inte {1}-mönstret måste vara en giltig RFC 3987 IRI-referens -format.uri = {0}: matchar inte {1}-mönstret måste vara en giltig RFC 3986 URI -format.uri-reference = {0}: matchar inte {1}-mönstret måste vara en giltig RFC 3986 URI-referens -format.uri-template = {0}: matchar inte {1}-mönstret måste vara en giltig RFC 6570 URI-mall -format.uuid = {0}: matchar inte {1}-mönstret måste vara ett giltigt RFC 4122 UUID -format.regex = {0}: matchar inte {1}-mönstret måste vara ett giltigt ECMA-262 reguljärt uttryck -format.time = {0}: matchar inte {1}-mönstret måste vara en giltig RFC 3339-tid -format.hostname = {0}: matchar inte {1}-mönstret måste vara ett giltigt RFC 1123-värdnamn -format.json-pointer = {0}: matchar inte {1}-mönstret måste vara en giltig RFC 6901 JSON-pekare -format.relative-json-pointer = {0}: matchar inte {1}-mönstret måste vara en giltig IETF Relativ JSON-pekare -format.unknown = {0}: har ett okänt format ''{1}'' -id = {0}: ''{1}'' är inte en giltig {2} -items = {0}: index ''{1}'' är inte definierat i schemat och schemat tillåter inte ytterligare objekt -maxContains = {0}: måste vara ett icke-negativt heltal i {1} -maxItems = {0}: måste ha högst {1} objekt men hittade {2} -maxLength = {0}: får vara högst {1} tecken lång -maxProperties = {0}: måste ha högst {1} egenskaper -maximum = {0}: måste ha ett maximalt värde på {1} -minContains = {0}: måste vara ett icke-negativt heltal i {1} -minContainsVsMaxContains = {0}: minContains måste vara mindre än eller lika med maxContains i {1} -minItems = {0}: måste ha minst {1} objekt men hittade {2} -minLength = {0}: måste vara minst {1} tecken lång -minProperties = {0}: måste ha minst {1} egenskaper -minimum = {0}: måste ha ett lägsta värde på {1} -multipleOf = {0}: måste vara multipel av {1} -not = {0}: får inte vara giltigt för schemat {1} -notAllowed = {0}: egenskapen ''{1}'' är inte tillåten men den finns i data -oneOf = {0}: måste vara giltigt för ett och endast ett schema, men {1} är giltiga -oneOf.indexes = {0}: måste vara giltigt för ett och endast ett schema, men {1} är giltiga med index ''{2}'' -pattern = {0}: matchar inte regexmönstret {1} -patternProperties = {0}: har något fel med ''mönsteregenskaper'' -prefixItems = {0}: ingen validator hittades i detta index -properties = {0}: har ett fel med ''egenskaper'' -propertyNames = {0}: egenskapen ''{1}'' namn är inte giltigt: {2} -readOnly = {0}: är ett skrivskyddat fält, det kan inte ändras -required = {0}: den obligatoriska egenskapen ''{1}'' hittades inte -type = {0}: {1} hittades, {2} förväntas -unevaluatedItems = {0}: index ''{1}'' utvärderas inte och schemat tillåter inte oevaluerade objekt -unevaluatedProperties = {0}: egenskapen ''{1}'' utvärderas inte och schemat tillåter inte oevaluerade egenskaper -unionType = {0}: {1} hittades, {2} förväntas -uniqueItems = {0}: får endast ha unika objekt i arrayen -writeOnly = {0}: är ett skrivskyddat fält, det kan inte visas i data -contentEncoding = {0}: matchar inte innehållskodning {1} -contentMediaType = {0}: är inte ett innehåll jag +$ref = har ett fel med ''refs'' +additionalItems = index ''{0}'' är inte definierat i schemat och schemat tillåter inte ytterligare objekt +additionalProperties = egenskapen ''{0}'' är inte definierad i schemat och schemat tillåter inte ytterligare egenskaper +allOf = måste vara giltig för alla scheman {0} +anyOf = måste vara giltigt för något av schemana {0} +const = måste vara det konstanta värdet ''{0}'' +contains = innehåller inte ett element som klarar dessa valideringar: {1} +contains.max = måste innehålla högst {0} element som klarar dessa valideringar: {1} +contains.min = måste innehålla minst {0} element som klarar dessa valideringar: {1} +dependencies = har ett fel med beroenden {0} +dependentRequired = har en saknad egenskap ''{0}'' som är beroende krävs eftersom ''{1}'' är närvarande +dependentSchemas = har ett fel med dependentSchemas {0} +enum = har inget värde i uppräkningen {0} +exclusiveMaximum = måste ha ett exklusivt maxvärde på {0} +exclusiveMinimum = måste ha ett exklusivt lägsta värde på {0} +false = schemat för ''{0}'' är falskt +format = matchar inte {0}-mönstret +format.date = matchar inte {0}-mönstret måste vara ett giltigt RFC 3339 fulldatum +format.date-time = matchar inte {0}-mönstret måste vara ett giltigt RFC 3339 datum-tid +format.duration = matchar inte {0}-mönstret måste vara en giltig ISO 8601-varaktighet +format.email = matchar inte {0}-mönstret måste vara en giltig RFC 5321-postlåda +format.ipv4 = matchar inte mönstret {0} måste vara en giltig RFC 2673 IP-adress +format.ipv6 = matchar inte {0}-mönstret måste vara en giltig RFC 4291 IP-adress +format.idn-email = matchar inte {0}-mönstret måste vara en giltig RFC 6531-postlåda +format.idn-hostname = matchar inte mönstret {0} måste vara ett giltigt RFC 5890 internationaliserat värdnamn +format.iri = matchar inte {0}-mönstret måste vara en giltig RFC 3987 IRI +format.iri-reference = matchar inte {0}-mönstret måste vara en giltig RFC 3987 IRI-referens +format.uri = matchar inte {0}-mönstret måste vara en giltig RFC 3986 URI +format.uri-reference = matchar inte {0}-mönstret måste vara en giltig RFC 3986 URI-referens +format.uri-template = matchar inte {0}-mönstret måste vara en giltig RFC 6570 URI-mall +format.uuid = matchar inte {0}-mönstret måste vara ett giltigt RFC 4122 UUID +format.regex = matchar inte {0}-mönstret måste vara ett giltigt ECMA-262 reguljärt uttryck +format.time = matchar inte {0}-mönstret måste vara en giltig RFC 3339-tid +format.hostname = matchar inte {0}-mönstret måste vara ett giltigt RFC 1123-värdnamn +format.json-pointer = matchar inte {0}-mönstret måste vara en giltig RFC 6901 JSON-pekare +format.relative-json-pointer = matchar inte {0}-mönstret måste vara en giltig IETF Relativ JSON-pekare +format.unknown = har ett okänt format ''{0}'' +id = ''{0}'' är inte en giltig {1} +items = index ''{0}'' är inte definierat i schemat och schemat tillåter inte ytterligare objekt +maxContains = måste vara ett icke-negativt heltal i {0} +maxItems = måste ha högst {0} objekt men hittade {1} +maxLength = får vara högst {0} tecken lång +maxProperties = måste ha högst {0} egenskaper +maximum = måste ha ett maximalt värde på {0} +minContains = måste vara ett icke-negativt heltal i {0} +minContainsVsMaxContains = minContains måste vara mindre än eller lika med maxContains i {0} +minItems = måste ha minst {0} objekt men hittade {1} +minLength = måste vara minst {0} tecken lång +minProperties = måste ha minst {0} egenskaper +minimum = måste ha ett lägsta värde på {0} +multipleOf = måste vara multipel av {0} +not = får inte vara giltigt för schemat {0} +notAllowed = egenskapen ''{0}'' är inte tillåten men den finns i data +oneOf = måste vara giltigt för ett och endast ett schema, men {0} är giltiga +oneOf.indexes = måste vara giltigt för ett och endast ett schema, men {0} är giltiga med index ''{1}'' +pattern = matchar inte regexmönstret {0} +patternProperties = har något fel med ''mönsteregenskaper'' +prefixItems = ingen validator hittades i detta index +properties = har ett fel med ''egenskaper'' +propertyNames = egenskapen ''{0}'' namn är inte giltigt: {1} +readOnly = är ett skrivskyddat fält, det kan inte ändras +required = den obligatoriska egenskapen ''{0}'' hittades inte +type = {0} hittades, {1} förväntas +unevaluatedItems = index ''{0}'' utvärderas inte och schemat tillåter inte oevaluerade objekt +unevaluatedProperties = egenskapen ''{0}'' utvärderas inte och schemat tillåter inte oevaluerade egenskaper +unionType = {0} hittades, {1} förväntas +uniqueItems = får endast ha unika objekt i arrayen +writeOnly = är ett skrivskyddat fält, det kan inte visas i data +contentEncoding = matchar inte innehållskodning {0} +contentMediaType = är inte ett innehåll jag diff --git a/src/main/resources/jsv-messages_th.properties b/src/main/resources/jsv-messages_th.properties index d13a67b2e..214954654 100644 --- a/src/main/resources/jsv-messages_th.properties +++ b/src/main/resources/jsv-messages_th.properties @@ -1,70 +1,70 @@ -$ref = {0}: \u0E21\u0E35\u0E02\u0E49\u0E2D\u0E1C\u0E34\u0E14\u0E1E\u0E25\u0E32\u0E14\u0E01\u0E31\u0E1A ''refs'' -additionalItems = {0}: \u0E14\u0E31\u0E0A\u0E19\u0E35 ''{1}'' \u0E44\u0E21\u0E48\u0E44\u0E14\u0E49\u0E16\u0E39\u0E01\u0E01\u0E33\u0E2B\u0E19\u0E14\u0E44\u0E27\u0E49\u0E43\u0E19\u0E2A\u0E04\u0E35\u0E21\u0E32 \u0E41\u0E25\u0E30\u0E2A\u0E04\u0E35\u0E21\u0E32\u0E44\u0E21\u0E48\u0E2D\u0E19\u0E38\u0E0D\u0E32\u0E15\u0E43\u0E2B\u0E49\u0E21\u0E35\u0E23\u0E32\u0E22\u0E01\u0E32\u0E23\u0E40\u0E1E\u0E34\u0E48\u0E21\u0E40\u0E15\u0E34\u0E21 -additionalProperties = {0}: \u0E04\u0E38\u0E13\u0E2A\u0E21\u0E1A\u0E31\u0E15\u0E34 ''{1}'' \u0E44\u0E21\u0E48\u0E44\u0E14\u0E49\u0E16\u0E39\u0E01\u0E01\u0E33\u0E2B\u0E19\u0E14\u0E44\u0E27\u0E49\u0E43\u0E19\u0E2A\u0E04\u0E35\u0E21\u0E32 \u0E41\u0E25\u0E30\u0E2A\u0E04\u0E35\u0E21\u0E32\u0E44\u0E21\u0E48\u0E2D\u0E19\u0E38\u0E0D\u0E32\u0E15\u0E43\u0E2B\u0E49\u0E21\u0E35\u0E04\u0E38\u0E13\u0E2A\u0E21\u0E1A\u0E31\u0E15\u0E34\u0E40\u0E1E\u0E34\u0E48\u0E21\u0E40\u0E15\u0E34\u0E21 -allOf = {0}: \u0E15\u0E49\u0E2D\u0E07\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07\u0E01\u0E31\u0E1A\u0E2A\u0E04\u0E35\u0E21\u0E32\u0E17\u0E31\u0E49\u0E07\u0E2B\u0E21\u0E14 {1} -anyOf = {0}: \u0E15\u0E49\u0E2D\u0E07\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07\u0E01\u0E31\u0E1A\u0E2A\u0E04\u0E35\u0E21\u0E32\u0E43\u0E14\u0E46 {1} -const = {0}: \u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19\u0E04\u0E48\u0E32\u0E04\u0E07\u0E17\u0E35\u0E48 ''{1}'' -contains = {0}: \u0E44\u0E21\u0E48\u0E21\u0E35\u0E2D\u0E07\u0E04\u0E4C\u0E1B\u0E23\u0E30\u0E01\u0E2D\u0E1A\u0E17\u0E35\u0E48\u0E1C\u0E48\u0E32\u0E19\u0E01\u0E32\u0E23\u0E15\u0E23\u0E27\u0E08\u0E2A\u0E2D\u0E1A\u0E40\u0E2B\u0E25\u0E48\u0E32\u0E19\u0E35\u0E49: {2} -contains.max = {0}: \u0E15\u0E49\u0E2D\u0E07\u0E21\u0E35\u0E2D\u0E07\u0E04\u0E4C\u0E1B\u0E23\u0E30\u0E01\u0E2D\u0E1A\u0E21\u0E32\u0E01\u0E17\u0E35\u0E48\u0E2A\u0E38\u0E14 {1} \u0E17\u0E35\u0E48\u0E1C\u0E48\u0E32\u0E19\u0E01\u0E32\u0E23\u0E15\u0E23\u0E27\u0E08\u0E2A\u0E2D\u0E1A\u0E40\u0E2B\u0E25\u0E48\u0E32\u0E19\u0E35\u0E49: {2} -contains.min = {0}: \u0E15\u0E49\u0E2D\u0E07\u0E21\u0E35\u0E2D\u0E22\u0E48\u0E32\u0E07\u0E19\u0E49\u0E2D\u0E22 {1} \u0E2D\u0E07\u0E04\u0E4C\u0E1B\u0E23\u0E30\u0E01\u0E2D\u0E1A\u0E17\u0E35\u0E48\u0E1C\u0E48\u0E32\u0E19\u0E01\u0E32\u0E23\u0E15\u0E23\u0E27\u0E08\u0E2A\u0E2D\u0E1A\u0E40\u0E2B\u0E25\u0E48\u0E32\u0E19\u0E35\u0E49: {2} -dependencies = {0}: \u0E21\u0E35\u0E02\u0E49\u0E2D\u0E1C\u0E34\u0E14\u0E1E\u0E25\u0E32\u0E14\u0E01\u0E31\u0E1A\u0E01\u0E32\u0E23\u0E02\u0E36\u0E49\u0E19\u0E15\u0E48\u0E2D\u0E01\u0E31\u0E19 {1} -dependentRequired = {0}: \u0E21\u0E35\u0E04\u0E38\u0E13\u0E2A\u0E21\u0E1A\u0E31\u0E15\u0E34\u0E02\u0E32\u0E14\u0E2B\u0E32\u0E22\u0E44\u0E1B ''{1}'' \u0E0B\u0E36\u0E48\u0E07\u0E08\u0E33\u0E40\u0E1B\u0E47\u0E19\u0E15\u0E49\u0E2D\u0E07\u0E1E\u0E36\u0E48\u0E07\u0E1E\u0E32\u0E40\u0E19\u0E37\u0E48\u0E2D\u0E07\u0E08\u0E32\u0E01\u0E21\u0E35 ''{2}'' \u0E2D\u0E22\u0E39\u0E48 -dependentSchemas = {0}: \u0E21\u0E35\u0E02\u0E49\u0E2D\u0E1C\u0E34\u0E14\u0E1E\u0E25\u0E32\u0E14\u0E01\u0E31\u0E1A dependentSchemas {1} -enum = {0}: \u0E44\u0E21\u0E48\u0E21\u0E35\u0E04\u0E48\u0E32\u0E43\u0E19\u0E01\u0E32\u0E23\u0E41\u0E08\u0E07\u0E19\u0E31\u0E1A {1} -exclusiveMaximum = {0}: \u0E15\u0E49\u0E2D\u0E07\u0E21\u0E35\u0E04\u0E48\u0E32\u0E2A\u0E39\u0E07\u0E2A\u0E38\u0E14\u0E1E\u0E34\u0E40\u0E28\u0E29\u0E40\u0E1B\u0E47\u0E19 {1} -exclusiveMinimum = {0}: \u0E15\u0E49\u0E2D\u0E07\u0E21\u0E35\u0E04\u0E48\u0E32\u0E15\u0E48\u0E33\u0E2A\u0E38\u0E14\u0E1E\u0E34\u0E40\u0E28\u0E29\u0E40\u0E1B\u0E47\u0E19 {1} -false = {0}: \u0E2A\u0E04\u0E35\u0E21\u0E32\u0E2A\u0E33\u0E2B\u0E23\u0E31\u0E1A ''{1}'' \u0E40\u0E1B\u0E47\u0E19\u0E40\u0E17\u0E47\u0E08 -format = {0}: \u0E44\u0E21\u0E48\u0E15\u0E23\u0E07\u0E01\u0E31\u0E1A\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A {1} {2} -format.date = {0}: \u0E44\u0E21\u0E48\u0E15\u0E23\u0E07\u0E01\u0E31\u0E1A\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A {1} \u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19\u0E27\u0E31\u0E19\u0E17\u0E35\u0E48\u0E40\u0E15\u0E47\u0E21 RFC 3339 \u0E17\u0E35\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 -format.date-time = {0}: \u0E44\u0E21\u0E48\u0E15\u0E23\u0E07\u0E01\u0E31\u0E1A\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A {1} \u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19\u0E27\u0E31\u0E19\u0E17\u0E35\u0E48-\u0E40\u0E27\u0E25\u0E32 RFC 3339 \u0E17\u0E35\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 -format.duration = {0}: \u0E44\u0E21\u0E48\u0E15\u0E23\u0E07\u0E01\u0E31\u0E1A\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A {1} \u0E08\u0E30\u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19\u0E23\u0E30\u0E22\u0E30\u0E40\u0E27\u0E25\u0E32 ISO 8601 \u0E17\u0E35\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 -format.email = {0}: \u0E44\u0E21\u0E48\u0E15\u0E23\u0E07\u0E01\u0E31\u0E1A\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A {1} \u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19\u0E01\u0E25\u0E48\u0E2D\u0E07\u0E08\u0E14\u0E2B\u0E21\u0E32\u0E22 RFC 5321 \u0E17\u0E35\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 -format.ipv4 = {0}: \u0E44\u0E21\u0E48\u0E15\u0E23\u0E07\u0E01\u0E31\u0E1A\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A {1} \u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19\u0E17\u0E35\u0E48\u0E2D\u0E22\u0E39\u0E48 IP RFC 2673 \u0E17\u0E35\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 -format.ipv6 = {0}: \u0E44\u0E21\u0E48\u0E15\u0E23\u0E07\u0E01\u0E31\u0E1A\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A {1} \u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19\u0E17\u0E35\u0E48\u0E2D\u0E22\u0E39\u0E48 IP RFC 4291 \u0E17\u0E35\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 -format.idn-email = {0}: \u0E44\u0E21\u0E48\u0E15\u0E23\u0E07\u0E01\u0E31\u0E1A\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A {1} \u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19\u0E01\u0E25\u0E48\u0E2D\u0E07\u0E08\u0E14\u0E2B\u0E21\u0E32\u0E22 RFC 6531 \u0E17\u0E35\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 -format.idn-hostname = {0}: \u0E44\u0E21\u0E48\u0E15\u0E23\u0E07\u0E01\u0E31\u0E1A\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A {1} \u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19\u0E0A\u0E37\u0E48\u0E2D\u0E42\u0E2E\u0E2A\u0E15\u0E4C\u0E2A\u0E32\u0E01\u0E25 RFC 5890 \u0E17\u0E35\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 -format.iri = {0}: \u0E44\u0E21\u0E48\u0E15\u0E23\u0E07\u0E01\u0E31\u0E1A\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A {1} \u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19 RFC 3987 IRI \u0E17\u0E35\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 -format.iri-reference = {0}: \u0E44\u0E21\u0E48\u0E15\u0E23\u0E07\u0E01\u0E31\u0E1A\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A {1} \u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19 RFC 3987 IRI-reference \u0E17\u0E35\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 -format.uri = {0}: \u0E44\u0E21\u0E48\u0E15\u0E23\u0E07\u0E01\u0E31\u0E1A\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A {1} \u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19 RFC 3986 URI \u0E17\u0E35\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 -format.uri-reference = {0}: \u0E44\u0E21\u0E48\u0E15\u0E23\u0E07\u0E01\u0E31\u0E1A\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A {1} \u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19\u0E01\u0E32\u0E23\u0E2D\u0E49\u0E32\u0E07\u0E2D\u0E34\u0E07 RFC 3986 URI \u0E17\u0E35\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 -format.uri-template = {0}: \u0E44\u0E21\u0E48\u0E15\u0E23\u0E07\u0E01\u0E31\u0E1A\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A {1} \u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19\u0E40\u0E17\u0E21\u0E40\u0E1E\u0E25\u0E15 RFC 6570 URI \u0E17\u0E35\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 -format.uuid = {0}: \u0E44\u0E21\u0E48\u0E15\u0E23\u0E07\u0E01\u0E31\u0E1A\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A {1} \u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19 RFC 4122 UUID \u0E17\u0E35\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 -format.regex = {0}: \u0E44\u0E21\u0E48\u0E15\u0E23\u0E07\u0E01\u0E31\u0E1A\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A {1} \u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19\u0E19\u0E34\u0E1E\u0E08\u0E19\u0E4C\u0E17\u0E31\u0E48\u0E27\u0E44\u0E1B ECMA-262 \u0E17\u0E35\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 -format.time = {0}: \u0E44\u0E21\u0E48\u0E15\u0E23\u0E07\u0E01\u0E31\u0E1A\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A {1} \u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19\u0E40\u0E27\u0E25\u0E32 RFC 3339 \u0E17\u0E35\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 -format.hostname = {0}: \u0E44\u0E21\u0E48\u0E15\u0E23\u0E07\u0E01\u0E31\u0E1A\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A {1} \u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19\u0E0A\u0E37\u0E48\u0E2D\u0E42\u0E2E\u0E2A\u0E15\u0E4C RFC 1123 \u0E17\u0E35\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 -format.json-pointer = {0}: \u0E44\u0E21\u0E48\u0E15\u0E23\u0E07\u0E01\u0E31\u0E1A\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A {1} \u0E08\u0E30\u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19\u0E15\u0E31\u0E27\u0E0A\u0E35\u0E49 RFC 6901 JSON \u0E17\u0E35\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 -format.relative-json-pointer = {0}: \u0E44\u0E21\u0E48\u0E15\u0E23\u0E07\u0E01\u0E31\u0E1A\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A {1} \u0E08\u0E30\u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19\u0E15\u0E31\u0E27\u0E0A\u0E35\u0E49 JSON \u0E41\u0E1A\u0E1A\u0E2A\u0E31\u0E21\u0E1E\u0E31\u0E19\u0E18\u0E4C\u0E02\u0E2D\u0E07 IETF \u0E17\u0E35\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 -format.unknown = {0}: \u0E21\u0E35\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A\u0E17\u0E35\u0E48\u0E44\u0E21\u0E48\u0E23\u0E39\u0E49\u0E08\u0E31\u0E01 ''{1}'' -id = {0}: ''{1}'' \u0E44\u0E21\u0E48\u0E43\u0E0A\u0E48 {2} \u0E17\u0E35\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 -items = {0}: \u0E14\u0E31\u0E0A\u0E19\u0E35 ''{1}'' \u0E44\u0E21\u0E48\u0E44\u0E14\u0E49\u0E16\u0E39\u0E01\u0E01\u0E33\u0E2B\u0E19\u0E14\u0E44\u0E27\u0E49\u0E43\u0E19\u0E2A\u0E04\u0E35\u0E21\u0E32 \u0E41\u0E25\u0E30\u0E2A\u0E04\u0E35\u0E21\u0E32\u0E44\u0E21\u0E48\u0E2D\u0E19\u0E38\u0E0D\u0E32\u0E15\u0E43\u0E2B\u0E49\u0E21\u0E35\u0E23\u0E32\u0E22\u0E01\u0E32\u0E23\u0E40\u0E1E\u0E34\u0E48\u0E21\u0E40\u0E15\u0E34\u0E21 -maxContains = {0}: \u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19\u0E08\u0E33\u0E19\u0E27\u0E19\u0E40\u0E15\u0E47\u0E21\u0E17\u0E35\u0E48\u0E44\u0E21\u0E48\u0E40\u0E1B\u0E47\u0E19\u0E25\u0E1A\u0E43\u0E19 {1} -maxItems = {0}: \u0E15\u0E49\u0E2D\u0E07\u0E21\u0E35\u0E21\u0E32\u0E01\u0E17\u0E35\u0E48\u0E2A\u0E38\u0E14 {1} \u0E23\u0E32\u0E22\u0E01\u0E32\u0E23 \u0E41\u0E15\u0E48\u0E1E\u0E1A {2} -maxLength = {0}: \u0E15\u0E49\u0E2D\u0E07\u0E21\u0E35\u0E04\u0E27\u0E32\u0E21\u0E22\u0E32\u0E27\u0E2A\u0E39\u0E07\u0E2A\u0E38\u0E14 {1} \u0E2D\u0E31\u0E01\u0E02\u0E23\u0E30 -maxProperties = {0}: \u0E15\u0E49\u0E2D\u0E07\u0E21\u0E35\u0E04\u0E38\u0E13\u0E2A\u0E21\u0E1A\u0E31\u0E15\u0E34\u0E2A\u0E39\u0E07\u0E2A\u0E38\u0E14 {1} -maximum = {0}: \u0E15\u0E49\u0E2D\u0E07\u0E21\u0E35\u0E04\u0E48\u0E32\u0E2A\u0E39\u0E07\u0E2A\u0E38\u0E14\u0E40\u0E1B\u0E47\u0E19 {1} -minContains = {0}: \u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19\u0E08\u0E33\u0E19\u0E27\u0E19\u0E40\u0E15\u0E47\u0E21\u0E17\u0E35\u0E48\u0E44\u0E21\u0E48\u0E40\u0E1B\u0E47\u0E19\u0E25\u0E1A\u0E43\u0E19 {1} -minContainsVsMaxContains = {0}: minContains \u0E15\u0E49\u0E2D\u0E07\u0E19\u0E49\u0E2D\u0E22\u0E01\u0E27\u0E48\u0E32\u0E2B\u0E23\u0E37\u0E2D\u0E40\u0E17\u0E48\u0E32\u0E01\u0E31\u0E1A maxContains \u0E43\u0E19 {1} -minItems = {0}: \u0E15\u0E49\u0E2D\u0E07\u0E21\u0E35\u0E2D\u0E22\u0E48\u0E32\u0E07\u0E19\u0E49\u0E2D\u0E22 {1} \u0E23\u0E32\u0E22\u0E01\u0E32\u0E23 \u0E41\u0E15\u0E48\u0E1E\u0E1A {2} -minLength = {0}: \u0E15\u0E49\u0E2D\u0E07\u0E21\u0E35\u0E04\u0E27\u0E32\u0E21\u0E22\u0E32\u0E27\u0E2D\u0E22\u0E48\u0E32\u0E07\u0E19\u0E49\u0E2D\u0E22 {1} \u0E2D\u0E31\u0E01\u0E02\u0E23\u0E30 -minProperties = {0}: \u0E15\u0E49\u0E2D\u0E07\u0E21\u0E35\u0E04\u0E38\u0E13\u0E2A\u0E21\u0E1A\u0E31\u0E15\u0E34\u0E2D\u0E22\u0E48\u0E32\u0E07\u0E19\u0E49\u0E2D\u0E22 {1} -minimum = {0}: \u0E15\u0E49\u0E2D\u0E07\u0E21\u0E35\u0E04\u0E48\u0E32\u0E15\u0E48\u0E33\u0E2A\u0E38\u0E14\u0E40\u0E1B\u0E47\u0E19 {1} -multipleOf = {0}: \u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19\u0E1C\u0E25\u0E04\u0E39\u0E13\u0E02\u0E2D\u0E07 {1} -not = {0}: \u0E15\u0E49\u0E2D\u0E07\u0E44\u0E21\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07\u0E01\u0E31\u0E1A\u0E2A\u0E04\u0E35\u0E21\u0E32 {1} -notAllowed = {0}: \u0E44\u0E21\u0E48\u0E2D\u0E19\u0E38\u0E0D\u0E32\u0E15\u0E43\u0E2B\u0E49\u0E43\u0E0A\u0E49\u0E04\u0E38\u0E13\u0E2A\u0E21\u0E1A\u0E31\u0E15\u0E34 ''{1}'' \u0E41\u0E15\u0E48\u0E2D\u0E22\u0E39\u0E48\u0E43\u0E19\u0E02\u0E49\u0E2D\u0E21\u0E39\u0E25 -oneOf = {0}: \u0E15\u0E49\u0E2D\u0E07\u0E43\u0E0A\u0E49\u0E44\u0E14\u0E49\u0E01\u0E31\u0E1A\u0E2A\u0E04\u0E35\u0E21\u0E32\u0E40\u0E14\u0E35\u0E22\u0E27\u0E40\u0E17\u0E48\u0E32\u0E19\u0E31\u0E49\u0E19 \u0E41\u0E15\u0E48 {1} \u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 -oneOf.indexes = {0}: \u0E15\u0E49\u0E2D\u0E07\u0E43\u0E0A\u0E49\u0E44\u0E14\u0E49\u0E01\u0E31\u0E1A\u0E2A\u0E04\u0E35\u0E21\u0E32\u0E40\u0E14\u0E35\u0E22\u0E27\u0E40\u0E17\u0E48\u0E32\u0E19\u0E31\u0E49\u0E19 \u0E41\u0E15\u0E48 {1} \u0E43\u0E0A\u0E49\u0E44\u0E14\u0E49\u0E01\u0E31\u0E1A\u0E14\u0E31\u0E0A\u0E19\u0E35 ''{2}'' -pattern = {0}: \u0E44\u0E21\u0E48\u0E15\u0E23\u0E07\u0E01\u0E31\u0E1A\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A regex {1} -patternProperties = {0}: \u0E21\u0E35\u0E02\u0E49\u0E2D\u0E1C\u0E34\u0E14\u0E1E\u0E25\u0E32\u0E14\u0E1A\u0E32\u0E07\u0E2D\u0E22\u0E48\u0E32\u0E07\u0E01\u0E31\u0E1A ''\u0E04\u0E38\u0E13\u0E2A\u0E21\u0E1A\u0E31\u0E15\u0E34\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A'' -prefixItems = {0}: \u0E44\u0E21\u0E48\u0E1E\u0E1A\u0E40\u0E04\u0E23\u0E37\u0E48\u0E2D\u0E07\u0E21\u0E37\u0E2D\u0E15\u0E23\u0E27\u0E08\u0E2A\u0E2D\u0E1A\u0E04\u0E27\u0E32\u0E21\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07\u0E43\u0E19\u0E14\u0E31\u0E0A\u0E19\u0E35\u0E19\u0E35\u0E49 -properties = {0}: \u0E21\u0E35\u0E02\u0E49\u0E2D\u0E1C\u0E34\u0E14\u0E1E\u0E25\u0E32\u0E14\u0E01\u0E31\u0E1A ''\u0E04\u0E38\u0E13\u0E2A\u0E21\u0E1A\u0E31\u0E15\u0E34'' -propertyNames = {0}: \u0E0A\u0E37\u0E48\u0E2D\u0E04\u0E38\u0E13\u0E2A\u0E21\u0E1A\u0E31\u0E15\u0E34 ''{1}'' \u0E44\u0E21\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07: {2} -readOnly = {0}: \u0E40\u0E1B\u0E47\u0E19\u0E1F\u0E34\u0E25\u0E14\u0E4C\u0E41\u0E1A\u0E1A\u0E2D\u0E48\u0E32\u0E19\u0E2D\u0E22\u0E48\u0E32\u0E07\u0E40\u0E14\u0E35\u0E22\u0E27 \u0E44\u0E21\u0E48\u0E2A\u0E32\u0E21\u0E32\u0E23\u0E16\u0E40\u0E1B\u0E25\u0E35\u0E48\u0E22\u0E19\u0E41\u0E1B\u0E25\u0E07\u0E44\u0E14\u0E49 -required = {0}: \u0E44\u0E21\u0E48\u0E1E\u0E1A\u0E04\u0E38\u0E13\u0E2A\u0E21\u0E1A\u0E31\u0E15\u0E34\u0E17\u0E35\u0E48\u0E15\u0E49\u0E2D\u0E07\u0E01\u0E32\u0E23 ''{1}'' -type = {0}: \u0E1E\u0E1A {1}, \u0E04\u0E32\u0E14\u0E2B\u0E27\u0E31\u0E07 {2} -unevaluatedItems = {0}: \u0E14\u0E31\u0E0A\u0E19\u0E35 ''{1}'' \u0E44\u0E21\u0E48\u0E44\u0E14\u0E49\u0E23\u0E31\u0E1A\u0E01\u0E32\u0E23\u0E1B\u0E23\u0E30\u0E40\u0E21\u0E34\u0E19 \u0E41\u0E25\u0E30\u0E2A\u0E04\u0E35\u0E21\u0E32\u0E44\u0E21\u0E48\u0E2D\u0E19\u0E38\u0E0D\u0E32\u0E15\u0E23\u0E32\u0E22\u0E01\u0E32\u0E23\u0E17\u0E35\u0E48\u0E44\u0E21\u0E48\u0E44\u0E14\u0E49\u0E23\u0E31\u0E1A\u0E01\u0E32\u0E23\u0E1B\u0E23\u0E30\u0E40\u0E21\u0E34\u0E19 -unevaluatedProperties = {0}: \u0E04\u0E38\u0E13\u0E2A\u0E21\u0E1A\u0E31\u0E15\u0E34 ''{1}'' \u0E44\u0E21\u0E48\u0E44\u0E14\u0E49\u0E23\u0E31\u0E1A\u0E01\u0E32\u0E23\u0E1B\u0E23\u0E30\u0E40\u0E21\u0E34\u0E19 \u0E41\u0E25\u0E30\u0E2A\u0E04\u0E35\u0E21\u0E32\u0E44\u0E21\u0E48\u0E2D\u0E19\u0E38\u0E0D\u0E32\u0E15\u0E43\u0E2B\u0E49\u0E21\u0E35\u0E04\u0E38\u0E13\u0E2A\u0E21\u0E1A\u0E31\u0E15\u0E34\u0E17\u0E35\u0E48\u0E44\u0E21\u0E48\u0E44\u0E14\u0E49\u0E23\u0E31\u0E1A\u0E01\u0E32\u0E23\u0E1B\u0E23\u0E30\u0E40\u0E21\u0E34\u0E19 -unionType = {0}: \u0E1E\u0E1A {1}, \u0E15\u0E49\u0E2D\u0E07\u0E01\u0E32\u0E23 {2} -uniqueItems = {0}: \u0E15\u0E49\u0E2D\u0E07\u0E21\u0E35\u0E40\u0E09\u0E1E\u0E32\u0E30\u0E23\u0E32\u0E22\u0E01\u0E32\u0E23\u0E17\u0E35\u0E48\u0E44\u0E21\u0E48\u0E0B\u0E49\u0E33\u0E43\u0E19\u0E2D\u0E32\u0E23\u0E4C\u0E40\u0E23\u0E22\u0E4C -writeOnly = {0}: \u0E40\u0E1B\u0E47\u0E19\u0E1F\u0E34\u0E25\u0E14\u0E4C\u0E41\u0E1A\u0E1A\u0E40\u0E02\u0E35\u0E22\u0E19\u0E40\u0E17\u0E48\u0E32\u0E19\u0E31\u0E49\u0E19 \u0E44\u0E21\u0E48\u0E2A\u0E32\u0E21\u0E32\u0E23\u0E16\u0E1B\u0E23\u0E32\u0E01\u0E0F\u0E43\u0E19\u0E02\u0E49\u0E2D\u0E21\u0E39\u0E25\u0E44\u0E14\u0E49 -contentEncoding = {0}: \u0E44\u0E21\u0E48\u0E15\u0E23\u0E07\u0E01\u0E31\u0E1A\u0E01\u0E32\u0E23\u0E40\u0E02\u0E49\u0E32\u0E23\u0E2B\u0E31\u0E2A\u0E40\u0E19\u0E37\u0E49\u0E2D\u0E2B\u0E32 {1} -contentMediaType = {0}: \u0E44\u0E21\u0E48\u0E43\u0E0A\u0E48\u0E40\u0E19\u0E37\u0E49\u0E2D\u0E2B\u0E32\u0E02\u0E2D\u0E07\u0E09\u0E31\u0E19 +$ref = \u0E21\u0E35\u0E02\u0E49\u0E2D\u0E1C\u0E34\u0E14\u0E1E\u0E25\u0E32\u0E14\u0E01\u0E31\u0E1A ''refs'' +additionalItems = \u0E14\u0E31\u0E0A\u0E19\u0E35 ''{0}'' \u0E44\u0E21\u0E48\u0E44\u0E14\u0E49\u0E16\u0E39\u0E01\u0E01\u0E33\u0E2B\u0E19\u0E14\u0E44\u0E27\u0E49\u0E43\u0E19\u0E2A\u0E04\u0E35\u0E21\u0E32 \u0E41\u0E25\u0E30\u0E2A\u0E04\u0E35\u0E21\u0E32\u0E44\u0E21\u0E48\u0E2D\u0E19\u0E38\u0E0D\u0E32\u0E15\u0E43\u0E2B\u0E49\u0E21\u0E35\u0E23\u0E32\u0E22\u0E01\u0E32\u0E23\u0E40\u0E1E\u0E34\u0E48\u0E21\u0E40\u0E15\u0E34\u0E21 +additionalProperties = \u0E04\u0E38\u0E13\u0E2A\u0E21\u0E1A\u0E31\u0E15\u0E34 ''{0}'' \u0E44\u0E21\u0E48\u0E44\u0E14\u0E49\u0E16\u0E39\u0E01\u0E01\u0E33\u0E2B\u0E19\u0E14\u0E44\u0E27\u0E49\u0E43\u0E19\u0E2A\u0E04\u0E35\u0E21\u0E32 \u0E41\u0E25\u0E30\u0E2A\u0E04\u0E35\u0E21\u0E32\u0E44\u0E21\u0E48\u0E2D\u0E19\u0E38\u0E0D\u0E32\u0E15\u0E43\u0E2B\u0E49\u0E21\u0E35\u0E04\u0E38\u0E13\u0E2A\u0E21\u0E1A\u0E31\u0E15\u0E34\u0E40\u0E1E\u0E34\u0E48\u0E21\u0E40\u0E15\u0E34\u0E21 +allOf = \u0E15\u0E49\u0E2D\u0E07\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07\u0E01\u0E31\u0E1A\u0E2A\u0E04\u0E35\u0E21\u0E32\u0E17\u0E31\u0E49\u0E07\u0E2B\u0E21\u0E14 {0} +anyOf = \u0E15\u0E49\u0E2D\u0E07\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07\u0E01\u0E31\u0E1A\u0E2A\u0E04\u0E35\u0E21\u0E32\u0E43\u0E14\u0E46 {0} +const = \u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19\u0E04\u0E48\u0E32\u0E04\u0E07\u0E17\u0E35\u0E48 ''{0}'' +contains = \u0E44\u0E21\u0E48\u0E21\u0E35\u0E2D\u0E07\u0E04\u0E4C\u0E1B\u0E23\u0E30\u0E01\u0E2D\u0E1A\u0E17\u0E35\u0E48\u0E1C\u0E48\u0E32\u0E19\u0E01\u0E32\u0E23\u0E15\u0E23\u0E27\u0E08\u0E2A\u0E2D\u0E1A\u0E40\u0E2B\u0E25\u0E48\u0E32\u0E19\u0E35\u0E49: {1} +contains.max = \u0E15\u0E49\u0E2D\u0E07\u0E21\u0E35\u0E2D\u0E07\u0E04\u0E4C\u0E1B\u0E23\u0E30\u0E01\u0E2D\u0E1A\u0E21\u0E32\u0E01\u0E17\u0E35\u0E48\u0E2A\u0E38\u0E14 {0} \u0E17\u0E35\u0E48\u0E1C\u0E48\u0E32\u0E19\u0E01\u0E32\u0E23\u0E15\u0E23\u0E27\u0E08\u0E2A\u0E2D\u0E1A\u0E40\u0E2B\u0E25\u0E48\u0E32\u0E19\u0E35\u0E49: {1} +contains.min = \u0E15\u0E49\u0E2D\u0E07\u0E21\u0E35\u0E2D\u0E22\u0E48\u0E32\u0E07\u0E19\u0E49\u0E2D\u0E22 {0} \u0E2D\u0E07\u0E04\u0E4C\u0E1B\u0E23\u0E30\u0E01\u0E2D\u0E1A\u0E17\u0E35\u0E48\u0E1C\u0E48\u0E32\u0E19\u0E01\u0E32\u0E23\u0E15\u0E23\u0E27\u0E08\u0E2A\u0E2D\u0E1A\u0E40\u0E2B\u0E25\u0E48\u0E32\u0E19\u0E35\u0E49: {1} +dependencies = \u0E21\u0E35\u0E02\u0E49\u0E2D\u0E1C\u0E34\u0E14\u0E1E\u0E25\u0E32\u0E14\u0E01\u0E31\u0E1A\u0E01\u0E32\u0E23\u0E02\u0E36\u0E49\u0E19\u0E15\u0E48\u0E2D\u0E01\u0E31\u0E19 {0} +dependentRequired = \u0E21\u0E35\u0E04\u0E38\u0E13\u0E2A\u0E21\u0E1A\u0E31\u0E15\u0E34\u0E02\u0E32\u0E14\u0E2B\u0E32\u0E22\u0E44\u0E1B ''{0}'' \u0E0B\u0E36\u0E48\u0E07\u0E08\u0E33\u0E40\u0E1B\u0E47\u0E19\u0E15\u0E49\u0E2D\u0E07\u0E1E\u0E36\u0E48\u0E07\u0E1E\u0E32\u0E40\u0E19\u0E37\u0E48\u0E2D\u0E07\u0E08\u0E32\u0E01\u0E21\u0E35 ''{1}'' \u0E2D\u0E22\u0E39\u0E48 +dependentSchemas = \u0E21\u0E35\u0E02\u0E49\u0E2D\u0E1C\u0E34\u0E14\u0E1E\u0E25\u0E32\u0E14\u0E01\u0E31\u0E1A dependentSchemas {0} +enum = \u0E44\u0E21\u0E48\u0E21\u0E35\u0E04\u0E48\u0E32\u0E43\u0E19\u0E01\u0E32\u0E23\u0E41\u0E08\u0E07\u0E19\u0E31\u0E1A {0} +exclusiveMaximum = \u0E15\u0E49\u0E2D\u0E07\u0E21\u0E35\u0E04\u0E48\u0E32\u0E2A\u0E39\u0E07\u0E2A\u0E38\u0E14\u0E1E\u0E34\u0E40\u0E28\u0E29\u0E40\u0E1B\u0E47\u0E19 {0} +exclusiveMinimum = \u0E15\u0E49\u0E2D\u0E07\u0E21\u0E35\u0E04\u0E48\u0E32\u0E15\u0E48\u0E33\u0E2A\u0E38\u0E14\u0E1E\u0E34\u0E40\u0E28\u0E29\u0E40\u0E1B\u0E47\u0E19 {0} +false = \u0E2A\u0E04\u0E35\u0E21\u0E32\u0E2A\u0E33\u0E2B\u0E23\u0E31\u0E1A ''{0}'' \u0E40\u0E1B\u0E47\u0E19\u0E40\u0E17\u0E47\u0E08 +format = \u0E44\u0E21\u0E48\u0E15\u0E23\u0E07\u0E01\u0E31\u0E1A\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A {0} +format.date = \u0E44\u0E21\u0E48\u0E15\u0E23\u0E07\u0E01\u0E31\u0E1A\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A {0} \u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19\u0E27\u0E31\u0E19\u0E17\u0E35\u0E48\u0E40\u0E15\u0E47\u0E21 RFC 3339 \u0E17\u0E35\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 +format.date-time = \u0E44\u0E21\u0E48\u0E15\u0E23\u0E07\u0E01\u0E31\u0E1A\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A {0} \u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19\u0E27\u0E31\u0E19\u0E17\u0E35\u0E48-\u0E40\u0E27\u0E25\u0E32 RFC 3339 \u0E17\u0E35\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 +format.duration = \u0E44\u0E21\u0E48\u0E15\u0E23\u0E07\u0E01\u0E31\u0E1A\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A {0} \u0E08\u0E30\u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19\u0E23\u0E30\u0E22\u0E30\u0E40\u0E27\u0E25\u0E32 ISO 8601 \u0E17\u0E35\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 +format.email = \u0E44\u0E21\u0E48\u0E15\u0E23\u0E07\u0E01\u0E31\u0E1A\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A {0} \u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19\u0E01\u0E25\u0E48\u0E2D\u0E07\u0E08\u0E14\u0E2B\u0E21\u0E32\u0E22 RFC 5321 \u0E17\u0E35\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 +format.ipv4 = \u0E44\u0E21\u0E48\u0E15\u0E23\u0E07\u0E01\u0E31\u0E1A\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A {0} \u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19\u0E17\u0E35\u0E48\u0E2D\u0E22\u0E39\u0E48 IP RFC 2673 \u0E17\u0E35\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 +format.ipv6 = \u0E44\u0E21\u0E48\u0E15\u0E23\u0E07\u0E01\u0E31\u0E1A\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A {0} \u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19\u0E17\u0E35\u0E48\u0E2D\u0E22\u0E39\u0E48 IP RFC 4291 \u0E17\u0E35\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 +format.idn-email = \u0E44\u0E21\u0E48\u0E15\u0E23\u0E07\u0E01\u0E31\u0E1A\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A {0} \u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19\u0E01\u0E25\u0E48\u0E2D\u0E07\u0E08\u0E14\u0E2B\u0E21\u0E32\u0E22 RFC 6531 \u0E17\u0E35\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 +format.idn-hostname = \u0E44\u0E21\u0E48\u0E15\u0E23\u0E07\u0E01\u0E31\u0E1A\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A {0} \u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19\u0E0A\u0E37\u0E48\u0E2D\u0E42\u0E2E\u0E2A\u0E15\u0E4C\u0E2A\u0E32\u0E01\u0E25 RFC 5890 \u0E17\u0E35\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 +format.iri = \u0E44\u0E21\u0E48\u0E15\u0E23\u0E07\u0E01\u0E31\u0E1A\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A {0} \u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19 RFC 3987 IRI \u0E17\u0E35\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 +format.iri-reference = \u0E44\u0E21\u0E48\u0E15\u0E23\u0E07\u0E01\u0E31\u0E1A\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A {0} \u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19 RFC 3987 IRI-reference \u0E17\u0E35\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 +format.uri = \u0E44\u0E21\u0E48\u0E15\u0E23\u0E07\u0E01\u0E31\u0E1A\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A {0} \u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19 RFC 3986 URI \u0E17\u0E35\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 +format.uri-reference = \u0E44\u0E21\u0E48\u0E15\u0E23\u0E07\u0E01\u0E31\u0E1A\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A {0} \u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19\u0E01\u0E32\u0E23\u0E2D\u0E49\u0E32\u0E07\u0E2D\u0E34\u0E07 RFC 3986 URI \u0E17\u0E35\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 +format.uri-template = \u0E44\u0E21\u0E48\u0E15\u0E23\u0E07\u0E01\u0E31\u0E1A\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A {0} \u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19\u0E40\u0E17\u0E21\u0E40\u0E1E\u0E25\u0E15 RFC 6570 URI \u0E17\u0E35\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 +format.uuid = \u0E44\u0E21\u0E48\u0E15\u0E23\u0E07\u0E01\u0E31\u0E1A\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A {0} \u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19 RFC 4122 UUID \u0E17\u0E35\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 +format.regex = \u0E44\u0E21\u0E48\u0E15\u0E23\u0E07\u0E01\u0E31\u0E1A\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A {0} \u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19\u0E19\u0E34\u0E1E\u0E08\u0E19\u0E4C\u0E17\u0E31\u0E48\u0E27\u0E44\u0E1B ECMA-262 \u0E17\u0E35\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 +format.time = \u0E44\u0E21\u0E48\u0E15\u0E23\u0E07\u0E01\u0E31\u0E1A\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A {0} \u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19\u0E40\u0E27\u0E25\u0E32 RFC 3339 \u0E17\u0E35\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 +format.hostname = \u0E44\u0E21\u0E48\u0E15\u0E23\u0E07\u0E01\u0E31\u0E1A\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A {0} \u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19\u0E0A\u0E37\u0E48\u0E2D\u0E42\u0E2E\u0E2A\u0E15\u0E4C RFC 1123 \u0E17\u0E35\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 +format.json-pointer = \u0E44\u0E21\u0E48\u0E15\u0E23\u0E07\u0E01\u0E31\u0E1A\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A {0} \u0E08\u0E30\u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19\u0E15\u0E31\u0E27\u0E0A\u0E35\u0E49 RFC 6901 JSON \u0E17\u0E35\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 +format.relative-json-pointer = \u0E44\u0E21\u0E48\u0E15\u0E23\u0E07\u0E01\u0E31\u0E1A\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A {0} \u0E08\u0E30\u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19\u0E15\u0E31\u0E27\u0E0A\u0E35\u0E49 JSON \u0E41\u0E1A\u0E1A\u0E2A\u0E31\u0E21\u0E1E\u0E31\u0E19\u0E18\u0E4C\u0E02\u0E2D\u0E07 IETF \u0E17\u0E35\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 +format.unknown = \u0E21\u0E35\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A\u0E17\u0E35\u0E48\u0E44\u0E21\u0E48\u0E23\u0E39\u0E49\u0E08\u0E31\u0E01 ''{0}'' +id = ''{0}'' \u0E44\u0E21\u0E48\u0E43\u0E0A\u0E48 {1} \u0E17\u0E35\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 +items = \u0E14\u0E31\u0E0A\u0E19\u0E35 ''{0}'' \u0E44\u0E21\u0E48\u0E44\u0E14\u0E49\u0E16\u0E39\u0E01\u0E01\u0E33\u0E2B\u0E19\u0E14\u0E44\u0E27\u0E49\u0E43\u0E19\u0E2A\u0E04\u0E35\u0E21\u0E32 \u0E41\u0E25\u0E30\u0E2A\u0E04\u0E35\u0E21\u0E32\u0E44\u0E21\u0E48\u0E2D\u0E19\u0E38\u0E0D\u0E32\u0E15\u0E43\u0E2B\u0E49\u0E21\u0E35\u0E23\u0E32\u0E22\u0E01\u0E32\u0E23\u0E40\u0E1E\u0E34\u0E48\u0E21\u0E40\u0E15\u0E34\u0E21 +maxContains = \u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19\u0E08\u0E33\u0E19\u0E27\u0E19\u0E40\u0E15\u0E47\u0E21\u0E17\u0E35\u0E48\u0E44\u0E21\u0E48\u0E40\u0E1B\u0E47\u0E19\u0E25\u0E1A\u0E43\u0E19 {0} +maxItems = \u0E15\u0E49\u0E2D\u0E07\u0E21\u0E35\u0E21\u0E32\u0E01\u0E17\u0E35\u0E48\u0E2A\u0E38\u0E14 {0} \u0E23\u0E32\u0E22\u0E01\u0E32\u0E23 \u0E41\u0E15\u0E48\u0E1E\u0E1A {1} +maxLength = \u0E15\u0E49\u0E2D\u0E07\u0E21\u0E35\u0E04\u0E27\u0E32\u0E21\u0E22\u0E32\u0E27\u0E2A\u0E39\u0E07\u0E2A\u0E38\u0E14 {0} \u0E2D\u0E31\u0E01\u0E02\u0E23\u0E30 +maxProperties = \u0E15\u0E49\u0E2D\u0E07\u0E21\u0E35\u0E04\u0E38\u0E13\u0E2A\u0E21\u0E1A\u0E31\u0E15\u0E34\u0E2A\u0E39\u0E07\u0E2A\u0E38\u0E14 {0} +maximum = \u0E15\u0E49\u0E2D\u0E07\u0E21\u0E35\u0E04\u0E48\u0E32\u0E2A\u0E39\u0E07\u0E2A\u0E38\u0E14\u0E40\u0E1B\u0E47\u0E19 {0} +minContains = \u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19\u0E08\u0E33\u0E19\u0E27\u0E19\u0E40\u0E15\u0E47\u0E21\u0E17\u0E35\u0E48\u0E44\u0E21\u0E48\u0E40\u0E1B\u0E47\u0E19\u0E25\u0E1A\u0E43\u0E19 {0} +minContainsVsMaxContains = minContains \u0E15\u0E49\u0E2D\u0E07\u0E19\u0E49\u0E2D\u0E22\u0E01\u0E27\u0E48\u0E32\u0E2B\u0E23\u0E37\u0E2D\u0E40\u0E17\u0E48\u0E32\u0E01\u0E31\u0E1A maxContains \u0E43\u0E19 {0} +minItems = \u0E15\u0E49\u0E2D\u0E07\u0E21\u0E35\u0E2D\u0E22\u0E48\u0E32\u0E07\u0E19\u0E49\u0E2D\u0E22 {0} \u0E23\u0E32\u0E22\u0E01\u0E32\u0E23 \u0E41\u0E15\u0E48\u0E1E\u0E1A {1} +minLength = \u0E15\u0E49\u0E2D\u0E07\u0E21\u0E35\u0E04\u0E27\u0E32\u0E21\u0E22\u0E32\u0E27\u0E2D\u0E22\u0E48\u0E32\u0E07\u0E19\u0E49\u0E2D\u0E22 {0} \u0E2D\u0E31\u0E01\u0E02\u0E23\u0E30 +minProperties = \u0E15\u0E49\u0E2D\u0E07\u0E21\u0E35\u0E04\u0E38\u0E13\u0E2A\u0E21\u0E1A\u0E31\u0E15\u0E34\u0E2D\u0E22\u0E48\u0E32\u0E07\u0E19\u0E49\u0E2D\u0E22 {0} +minimum = \u0E15\u0E49\u0E2D\u0E07\u0E21\u0E35\u0E04\u0E48\u0E32\u0E15\u0E48\u0E33\u0E2A\u0E38\u0E14\u0E40\u0E1B\u0E47\u0E19 {0} +multipleOf = \u0E15\u0E49\u0E2D\u0E07\u0E40\u0E1B\u0E47\u0E19\u0E1C\u0E25\u0E04\u0E39\u0E13\u0E02\u0E2D\u0E07 {0} +not = \u0E15\u0E49\u0E2D\u0E07\u0E44\u0E21\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07\u0E01\u0E31\u0E1A\u0E2A\u0E04\u0E35\u0E21\u0E32 {0} +notAllowed = \u0E44\u0E21\u0E48\u0E2D\u0E19\u0E38\u0E0D\u0E32\u0E15\u0E43\u0E2B\u0E49\u0E43\u0E0A\u0E49\u0E04\u0E38\u0E13\u0E2A\u0E21\u0E1A\u0E31\u0E15\u0E34 ''{0}'' \u0E41\u0E15\u0E48\u0E2D\u0E22\u0E39\u0E48\u0E43\u0E19\u0E02\u0E49\u0E2D\u0E21\u0E39\u0E25 +oneOf = \u0E15\u0E49\u0E2D\u0E07\u0E43\u0E0A\u0E49\u0E44\u0E14\u0E49\u0E01\u0E31\u0E1A\u0E2A\u0E04\u0E35\u0E21\u0E32\u0E40\u0E14\u0E35\u0E22\u0E27\u0E40\u0E17\u0E48\u0E32\u0E19\u0E31\u0E49\u0E19 \u0E41\u0E15\u0E48 {0} \u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07 +oneOf.indexes = \u0E15\u0E49\u0E2D\u0E07\u0E43\u0E0A\u0E49\u0E44\u0E14\u0E49\u0E01\u0E31\u0E1A\u0E2A\u0E04\u0E35\u0E21\u0E32\u0E40\u0E14\u0E35\u0E22\u0E27\u0E40\u0E17\u0E48\u0E32\u0E19\u0E31\u0E49\u0E19 \u0E41\u0E15\u0E48 {0} \u0E43\u0E0A\u0E49\u0E44\u0E14\u0E49\u0E01\u0E31\u0E1A\u0E14\u0E31\u0E0A\u0E19\u0E35 ''{1}'' +pattern = \u0E44\u0E21\u0E48\u0E15\u0E23\u0E07\u0E01\u0E31\u0E1A\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A regex {0} +patternProperties = \u0E21\u0E35\u0E02\u0E49\u0E2D\u0E1C\u0E34\u0E14\u0E1E\u0E25\u0E32\u0E14\u0E1A\u0E32\u0E07\u0E2D\u0E22\u0E48\u0E32\u0E07\u0E01\u0E31\u0E1A ''\u0E04\u0E38\u0E13\u0E2A\u0E21\u0E1A\u0E31\u0E15\u0E34\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A'' +prefixItems = \u0E44\u0E21\u0E48\u0E1E\u0E1A\u0E40\u0E04\u0E23\u0E37\u0E48\u0E2D\u0E07\u0E21\u0E37\u0E2D\u0E15\u0E23\u0E27\u0E08\u0E2A\u0E2D\u0E1A\u0E04\u0E27\u0E32\u0E21\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07\u0E43\u0E19\u0E14\u0E31\u0E0A\u0E19\u0E35\u0E19\u0E35\u0E49 +properties = \u0E21\u0E35\u0E02\u0E49\u0E2D\u0E1C\u0E34\u0E14\u0E1E\u0E25\u0E32\u0E14\u0E01\u0E31\u0E1A ''\u0E04\u0E38\u0E13\u0E2A\u0E21\u0E1A\u0E31\u0E15\u0E34'' +propertyNames = \u0E0A\u0E37\u0E48\u0E2D\u0E04\u0E38\u0E13\u0E2A\u0E21\u0E1A\u0E31\u0E15\u0E34 ''{0}'' \u0E44\u0E21\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07: {1} +readOnly = \u0E40\u0E1B\u0E47\u0E19\u0E1F\u0E34\u0E25\u0E14\u0E4C\u0E41\u0E1A\u0E1A\u0E2D\u0E48\u0E32\u0E19\u0E2D\u0E22\u0E48\u0E32\u0E07\u0E40\u0E14\u0E35\u0E22\u0E27 \u0E44\u0E21\u0E48\u0E2A\u0E32\u0E21\u0E32\u0E23\u0E16\u0E40\u0E1B\u0E25\u0E35\u0E48\u0E22\u0E19\u0E41\u0E1B\u0E25\u0E07\u0E44\u0E14\u0E49 +required = \u0E44\u0E21\u0E48\u0E1E\u0E1A\u0E04\u0E38\u0E13\u0E2A\u0E21\u0E1A\u0E31\u0E15\u0E34\u0E17\u0E35\u0E48\u0E15\u0E49\u0E2D\u0E07\u0E01\u0E32\u0E23 ''{0}'' +type = \u0E1E\u0E1A {0}, \u0E04\u0E32\u0E14\u0E2B\u0E27\u0E31\u0E07 {1} +unevaluatedItems = \u0E14\u0E31\u0E0A\u0E19\u0E35 ''{0}'' \u0E44\u0E21\u0E48\u0E44\u0E14\u0E49\u0E23\u0E31\u0E1A\u0E01\u0E32\u0E23\u0E1B\u0E23\u0E30\u0E40\u0E21\u0E34\u0E19 \u0E41\u0E25\u0E30\u0E2A\u0E04\u0E35\u0E21\u0E32\u0E44\u0E21\u0E48\u0E2D\u0E19\u0E38\u0E0D\u0E32\u0E15\u0E23\u0E32\u0E22\u0E01\u0E32\u0E23\u0E17\u0E35\u0E48\u0E44\u0E21\u0E48\u0E44\u0E14\u0E49\u0E23\u0E31\u0E1A\u0E01\u0E32\u0E23\u0E1B\u0E23\u0E30\u0E40\u0E21\u0E34\u0E19 +unevaluatedProperties = \u0E04\u0E38\u0E13\u0E2A\u0E21\u0E1A\u0E31\u0E15\u0E34 ''{0}'' \u0E44\u0E21\u0E48\u0E44\u0E14\u0E49\u0E23\u0E31\u0E1A\u0E01\u0E32\u0E23\u0E1B\u0E23\u0E30\u0E40\u0E21\u0E34\u0E19 \u0E41\u0E25\u0E30\u0E2A\u0E04\u0E35\u0E21\u0E32\u0E44\u0E21\u0E48\u0E2D\u0E19\u0E38\u0E0D\u0E32\u0E15\u0E43\u0E2B\u0E49\u0E21\u0E35\u0E04\u0E38\u0E13\u0E2A\u0E21\u0E1A\u0E31\u0E15\u0E34\u0E17\u0E35\u0E48\u0E44\u0E21\u0E48\u0E44\u0E14\u0E49\u0E23\u0E31\u0E1A\u0E01\u0E32\u0E23\u0E1B\u0E23\u0E30\u0E40\u0E21\u0E34\u0E19 +unionType = \u0E1E\u0E1A {0}, \u0E15\u0E49\u0E2D\u0E07\u0E01\u0E32\u0E23 {1} +uniqueItems = \u0E15\u0E49\u0E2D\u0E07\u0E21\u0E35\u0E40\u0E09\u0E1E\u0E32\u0E30\u0E23\u0E32\u0E22\u0E01\u0E32\u0E23\u0E17\u0E35\u0E48\u0E44\u0E21\u0E48\u0E0B\u0E49\u0E33\u0E43\u0E19\u0E2D\u0E32\u0E23\u0E4C\u0E40\u0E23\u0E22\u0E4C +writeOnly = \u0E40\u0E1B\u0E47\u0E19\u0E1F\u0E34\u0E25\u0E14\u0E4C\u0E41\u0E1A\u0E1A\u0E40\u0E02\u0E35\u0E22\u0E19\u0E40\u0E17\u0E48\u0E32\u0E19\u0E31\u0E49\u0E19 \u0E44\u0E21\u0E48\u0E2A\u0E32\u0E21\u0E32\u0E23\u0E16\u0E1B\u0E23\u0E32\u0E01\u0E0F\u0E43\u0E19\u0E02\u0E49\u0E2D\u0E21\u0E39\u0E25\u0E44\u0E14\u0E49 +contentEncoding = \u0E44\u0E21\u0E48\u0E15\u0E23\u0E07\u0E01\u0E31\u0E1A\u0E01\u0E32\u0E23\u0E40\u0E02\u0E49\u0E32\u0E23\u0E2B\u0E31\u0E2A\u0E40\u0E19\u0E37\u0E49\u0E2D\u0E2B\u0E32 {0} +contentMediaType = \u0E44\u0E21\u0E48\u0E43\u0E0A\u0E48\u0E40\u0E19\u0E37\u0E49\u0E2D\u0E2B\u0E32\u0E02\u0E2D\u0E07\u0E09\u0E31\u0E19 diff --git a/src/main/resources/jsv-messages_tr.properties b/src/main/resources/jsv-messages_tr.properties index 20e9b3a48..f9e69bf7a 100644 --- a/src/main/resources/jsv-messages_tr.properties +++ b/src/main/resources/jsv-messages_tr.properties @@ -1,70 +1,70 @@ -$ref = {0}: ''refs'' ile ilgili bir hata var -additionalItems = {0}: ''{1}'' dizini \u015Femada tan\u0131ml\u0131 de\u011Fil ve \u015Fema ek ö\u011Felere izin vermiyor -additionalProperties = {0}: ''{1}'' özelli\u011Fi \u015Femada tan\u0131ml\u0131 de\u011Fil ve \u015Fema ek özelliklere izin vermiyor -allOf = {0}: tüm {1} \u015Femalar\u0131 için geçerli olmal\u0131d\u0131r -anyOf = {0}: {1} \u015Femalar\u0131ndan herhangi biri için geçerli olmal\u0131d\u0131r -const = {0}: ''{1}'' sabit de\u011Feri olmal\u0131d\u0131r -contains = {0}: bu do\u011Frulamalar\u0131 geçen bir ö\u011Fe içermiyor: {2} -contains.max = {0}: \u015Fu do\u011Frulamalar\u0131 geçen en fazla {1} ö\u011Fe içermelidir: {2} -contains.min = {0}: \u015Fu do\u011Frulamalar\u0131 geçen en az {1} ö\u011Fe içermelidir: {2} -dependencies = {0}: ba\u011F\u0131ml\u0131l\u0131klarda hata var {1} -dependentRequired = {0}: ''{1}'' eksik bir özelli\u011Fi var ve ''{2}'' mevcut oldu\u011Fundan ba\u011F\u0131ml\u0131 gerekli -dependentSchemas = {0}: DependedSchemas {1} ile ilgili bir hata var -enum = {0}: {1} numaraland\u0131rmas\u0131nda bir de\u011Fer yok -exclusiveMaximum = {0}: özel maksimum de\u011Feri {1} olmal\u0131d\u0131r -exclusiveMinimum = {0}: özel minimum de\u011Feri {1} olmal\u0131d\u0131r -false = {0}: ''{1}'' \u015Femas\u0131 yanl\u0131\u015F -format = {0}: {1} modeliyle {2} e\u015Fle\u015Fmiyor -format.date = {0}: {1} modeliyle e\u015Fle\u015Fmiyor, geçerli bir RFC 3339 tam tarihi olmal\u0131d\u0131r -format.date-time = {0}: {1} modeliyle e\u015Fle\u015Fmiyor, geçerli bir RFC 3339 tarih-saat olmal\u0131d\u0131r -format.duration = {0}: {1} modeliyle e\u015Fle\u015Fmiyor, geçerli bir ISO 8601 süresi olmal\u0131d\u0131r -format.email = {0}: {1} modeliyle e\u015Fle\u015Fmiyor, geçerli bir RFC 5321 Posta Kutusu olmal\u0131d\u0131r -format.ipv4 = {0}: {1} modeliyle e\u015Fle\u015Fmiyor, geçerli bir RFC 2673 IP adresi olmal\u0131d\u0131r -format.ipv6 = {0}: {1} modeliyle e\u015Fle\u015Fmiyor, geçerli bir RFC 4291 IP adresi olmal\u0131d\u0131r -format.idn-email = {0}: {1} modeliyle e\u015Fle\u015Fmiyor, geçerli bir RFC 6531 Posta Kutusu olmal\u0131d\u0131r -format.idn-hostname = {0}: {1} modeliyle e\u015Fle\u015Fmiyor, geçerli bir RFC 5890 uluslararas\u0131la\u015Ft\u0131r\u0131lm\u0131\u015F ana bilgisayar ad\u0131 olmal\u0131d\u0131r -format.iri = {0}: {1} modeliyle e\u015Fle\u015Fmiyor, geçerli bir RFC 3987 IRI olmal\u0131d\u0131r -format.iri-reference = {0}: {1} modeliyle e\u015Fle\u015Fmiyor, geçerli bir RFC 3987 IRI referans\u0131 olmal\u0131d\u0131r -format.uri = {0}: {1} modeliyle e\u015Fle\u015Fmiyor, geçerli bir RFC 3986 URI olmal\u0131d\u0131r -format.uri-reference = {0}: {1} modeliyle e\u015Fle\u015Fmiyor, geçerli bir RFC 3986 URI referans\u0131 olmal\u0131d\u0131r -format.uri-template = {0}: {1} modeliyle e\u015Fle\u015Fmiyor, geçerli bir RFC 6570 URI \u015Eablonu olmal\u0131d\u0131r -format.uuid = {0}: {1} modeliyle e\u015Fle\u015Fmiyor, geçerli bir RFC 4122 UUID olmal\u0131d\u0131r -format.regex = {0}: {1} modeliyle e\u015Fle\u015Fmiyor, geçerli bir ECMA-262 normal ifadesi olmal\u0131d\u0131r -format.time = {0}: {1} modeliyle e\u015Fle\u015Fmiyor, geçerli bir RFC 3339 saati olmal\u0131d\u0131r -format.hostname = {0}: {1} modeliyle e\u015Fle\u015Fmiyor, geçerli bir RFC 1123 ana bilgisayar ad\u0131 olmal\u0131d\u0131r -format.json-pointer = {0}: {1} modeliyle e\u015Fle\u015Fmiyor, geçerli bir RFC 6901 JSON \u0130\u015Faretçisi olmal\u0131d\u0131r -format.relative-json-pointer = {0}: {1} modeliyle e\u015Fle\u015Fmiyor, geçerli bir IETF Göreli JSON \u0130\u015Faretçisi olmal\u0131d\u0131r -format.unknown = {0}: bilinmeyen bir formata sahip ''{1}'' -id = {0}: ''{1}'' geçerli bir {2} de\u011Fil -items = {0}: ''{1}'' dizini \u015Femada tan\u0131ml\u0131 de\u011Fil ve \u015Fema ek ö\u011Felere izin vermiyor -maxContains = {0}: {1}''de negatif olmayan bir tamsay\u0131 olmal\u0131d\u0131r -maxItems = {0}: en fazla {1} ö\u011Feye sahip olmal\u0131 ancak {2} bulundu -maxLength = {0}: en fazla {1} karakter uzunlu\u011Funda olmal\u0131d\u0131r -maxProperties = {0}: en fazla {1} özelli\u011Fe sahip olmal\u0131d\u0131r -maximum = {0}: maksimum de\u011Feri {1} olmal\u0131d\u0131r -minContains = {0}: {1}''de negatif olmayan bir tam say\u0131 olmal\u0131d\u0131r -minContainsVsMaxContains = {0}: minContains, {1} içindeki maxContains de\u011Ferinden küçük veya ona e\u015Fit olmal\u0131d\u0131r -minItems = {0}: en az {1} ö\u011Feye sahip olmal\u0131 ancak {2} bulundu -minLength = {0}: en az {1} karakter uzunlu\u011Funda olmal\u0131d\u0131r -minProperties = {0}: en az {1} özelli\u011Fe sahip olmal\u0131d\u0131r -minimum = {0}: minimum de\u011Feri {1} olmal\u0131d\u0131r -multipleOf = {0}: {1}''\u0131n kat\u0131 olmal\u0131d\u0131r -not = {0}: {1} \u015Femas\u0131 için geçerli olmamal\u0131d\u0131r -notAllowed = {0}: ''{1}'' özelli\u011Fine izin verilmiyor ancak verilerde mevcut -oneOf = {0}: yaln\u0131zca bir \u015Fema için geçerli olmal\u0131d\u0131r, ancak {1} geçerlidir -oneOf.indexes = {0}: yaln\u0131zca bir \u015Fema için geçerli olmal\u0131d\u0131r, ancak {1} ''{2}'' dizinleriyle geçerlidir -pattern = {0}: normal ifade modeli {1} ile e\u015Fle\u015Fmiyor -patternProperties = {0}: ''desen özelliklerinde'' baz\u0131 hatalar var -prefixItems = {0}: bu dizinde do\u011Frulay\u0131c\u0131 bulunamad\u0131 -properties = {0}: ''özellikler'' ile ilgili bir hata var -propertyNames = {0}: ''{1}'' özelli\u011Finin ad\u0131 geçerli de\u011Fil: {2} -readOnly = {0}: salt okunur bir aland\u0131r, de\u011Fi\u015Ftirilemez -required = {0}: gerekli ''{1}'' özelli\u011Fi bulunamad\u0131 -type = {0}: {1} bulundu, {2} bekleniyor -unevaluatedItems = {0}: ''{1}'' dizini de\u011Ferlendirilmez ve \u015Fema, de\u011Ferlendirilmemi\u015F ö\u011Felere izin vermez -unevaluatedProperties = {0}: ''{1}'' özelli\u011Fi de\u011Ferlendirilmez ve \u015Fema, de\u011Ferlendirilmemi\u015F özelliklere izin vermez -unionType = {0}: {1} bulundu, {2} bekleniyor -uniqueItems = {0}: dizide yaln\u0131zca benzersiz ö\u011Feler bulunmal\u0131d\u0131r -writeOnly = {0}: salt yaz\u0131l\u0131r bir aland\u0131r, verilerde görünemez -contentEncoding = {0}: içerik kodlamas\u0131 {1} ile e\u015Fle\u015Fmiyor -contentMediaType = {0}: bir içerik de\u011Fil +$ref = ''refs'' ile ilgili bir hata var +additionalItems = ''{0}'' dizini \u015Femada tan\u0131ml\u0131 de\u011Fil ve \u015Fema ek ö\u011Felere izin vermiyor +additionalProperties = ''{0}'' özelli\u011Fi \u015Femada tan\u0131ml\u0131 de\u011Fil ve \u015Fema ek özelliklere izin vermiyor +allOf = tüm {0} \u015Femalar\u0131 için geçerli olmal\u0131d\u0131r +anyOf = {0} \u015Femalar\u0131ndan herhangi biri için geçerli olmal\u0131d\u0131r +const = ''{0}'' sabit de\u011Feri olmal\u0131d\u0131r +contains = bu do\u011Frulamalar\u0131 geçen bir ö\u011Fe içermiyor: {1} +contains.max = \u015Fu do\u011Frulamalar\u0131 geçen en fazla {0} ö\u011Fe içermelidir: {1} +contains.min = \u015Fu do\u011Frulamalar\u0131 geçen en az {0} ö\u011Fe içermelidir: {1} +dependencies = ba\u011F\u0131ml\u0131l\u0131klarda hata var {0} +dependentRequired = ''{0}'' eksik bir özelli\u011Fi var ve ''{1}'' mevcut oldu\u011Fundan ba\u011F\u0131ml\u0131 gerekli +dependentSchemas = DependedSchemas {0} ile ilgili bir hata var +enum = {0} numaraland\u0131rmas\u0131nda bir de\u011Fer yok +exclusiveMaximum = özel maksimum de\u011Feri {0} olmal\u0131d\u0131r +exclusiveMinimum = özel minimum de\u011Feri {0} olmal\u0131d\u0131r +false = ''{0}'' \u015Femas\u0131 yanl\u0131\u015F +format = {0} modeliyle e\u015Fle\u015Fmiyor +format.date = {0} modeliyle e\u015Fle\u015Fmiyor, geçerli bir RFC 3339 tam tarihi olmal\u0131d\u0131r +format.date-time = {0} modeliyle e\u015Fle\u015Fmiyor, geçerli bir RFC 3339 tarih-saat olmal\u0131d\u0131r +format.duration = {0} modeliyle e\u015Fle\u015Fmiyor, geçerli bir ISO 8601 süresi olmal\u0131d\u0131r +format.email = {0} modeliyle e\u015Fle\u015Fmiyor, geçerli bir RFC 5321 Posta Kutusu olmal\u0131d\u0131r +format.ipv4 = {0} modeliyle e\u015Fle\u015Fmiyor, geçerli bir RFC 2673 IP adresi olmal\u0131d\u0131r +format.ipv6 = {0} modeliyle e\u015Fle\u015Fmiyor, geçerli bir RFC 4291 IP adresi olmal\u0131d\u0131r +format.idn-email = {0} modeliyle e\u015Fle\u015Fmiyor, geçerli bir RFC 6531 Posta Kutusu olmal\u0131d\u0131r +format.idn-hostname = {0} modeliyle e\u015Fle\u015Fmiyor, geçerli bir RFC 5890 uluslararas\u0131la\u015Ft\u0131r\u0131lm\u0131\u015F ana bilgisayar ad\u0131 olmal\u0131d\u0131r +format.iri = {0} modeliyle e\u015Fle\u015Fmiyor, geçerli bir RFC 3987 IRI olmal\u0131d\u0131r +format.iri-reference = {0} modeliyle e\u015Fle\u015Fmiyor, geçerli bir RFC 3987 IRI referans\u0131 olmal\u0131d\u0131r +format.uri = {0} modeliyle e\u015Fle\u015Fmiyor, geçerli bir RFC 3986 URI olmal\u0131d\u0131r +format.uri-reference = {0} modeliyle e\u015Fle\u015Fmiyor, geçerli bir RFC 3986 URI referans\u0131 olmal\u0131d\u0131r +format.uri-template = {0} modeliyle e\u015Fle\u015Fmiyor, geçerli bir RFC 6570 URI \u015Eablonu olmal\u0131d\u0131r +format.uuid = {0} modeliyle e\u015Fle\u015Fmiyor, geçerli bir RFC 4122 UUID olmal\u0131d\u0131r +format.regex = {0} modeliyle e\u015Fle\u015Fmiyor, geçerli bir ECMA-262 normal ifadesi olmal\u0131d\u0131r +format.time = {0} modeliyle e\u015Fle\u015Fmiyor, geçerli bir RFC 3339 saati olmal\u0131d\u0131r +format.hostname = {0} modeliyle e\u015Fle\u015Fmiyor, geçerli bir RFC 1123 ana bilgisayar ad\u0131 olmal\u0131d\u0131r +format.json-pointer = {0} modeliyle e\u015Fle\u015Fmiyor, geçerli bir RFC 6901 JSON \u0130\u015Faretçisi olmal\u0131d\u0131r +format.relative-json-pointer = {0} modeliyle e\u015Fle\u015Fmiyor, geçerli bir IETF Göreli JSON \u0130\u015Faretçisi olmal\u0131d\u0131r +format.unknown = bilinmeyen bir formata sahip ''{0}'' +id = ''{0}'' geçerli bir {1} de\u011Fil +items = ''{0}'' dizini \u015Femada tan\u0131ml\u0131 de\u011Fil ve \u015Fema ek ö\u011Felere izin vermiyor +maxContains = {0}''de negatif olmayan bir tamsay\u0131 olmal\u0131d\u0131r +maxItems = en fazla {0} ö\u011Feye sahip olmal\u0131 ancak {1} bulundu +maxLength = en fazla {0} karakter uzunlu\u011Funda olmal\u0131d\u0131r +maxProperties = en fazla {0} özelli\u011Fe sahip olmal\u0131d\u0131r +maximum = maksimum de\u011Feri {0} olmal\u0131d\u0131r +minContains = {0}''de negatif olmayan bir tam say\u0131 olmal\u0131d\u0131r +minContainsVsMaxContains = minContains, {0} içindeki maxContains de\u011Ferinden küçük veya ona e\u015Fit olmal\u0131d\u0131r +minItems = en az {0} ö\u011Feye sahip olmal\u0131 ancak {1} bulundu +minLength = en az {0} karakter uzunlu\u011Funda olmal\u0131d\u0131r +minProperties = en az {0} özelli\u011Fe sahip olmal\u0131d\u0131r +minimum = minimum de\u011Feri {0} olmal\u0131d\u0131r +multipleOf = {0}''\u0131n kat\u0131 olmal\u0131d\u0131r +not = {0} \u015Femas\u0131 için geçerli olmamal\u0131d\u0131r +notAllowed = ''{0}'' özelli\u011Fine izin verilmiyor ancak verilerde mevcut +oneOf = yaln\u0131zca bir \u015Fema için geçerli olmal\u0131d\u0131r, ancak {0} geçerlidir +oneOf.indexes = yaln\u0131zca bir \u015Fema için geçerli olmal\u0131d\u0131r, ancak {0} ''{1}'' dizinleriyle geçerlidir +pattern = normal ifade modeli {0} ile e\u015Fle\u015Fmiyor +patternProperties = ''desen özelliklerinde'' baz\u0131 hatalar var +prefixItems = bu dizinde do\u011Frulay\u0131c\u0131 bulunamad\u0131 +properties = ''özellikler'' ile ilgili bir hata var +propertyNames = ''{0}'' özelli\u011Finin ad\u0131 geçerli de\u011Fil: {1} +readOnly = salt okunur bir aland\u0131r, de\u011Fi\u015Ftirilemez +required = gerekli ''{0}'' özelli\u011Fi bulunamad\u0131 +type = {0} bulundu, {1} bekleniyor +unevaluatedItems = ''{0}'' dizini de\u011Ferlendirilmez ve \u015Fema, de\u011Ferlendirilmemi\u015F ö\u011Felere izin vermez +unevaluatedProperties = ''{0}'' özelli\u011Fi de\u011Ferlendirilmez ve \u015Fema, de\u011Ferlendirilmemi\u015F özelliklere izin vermez +unionType = {0} bulundu, {1} bekleniyor +uniqueItems = dizide yaln\u0131zca benzersiz ö\u011Feler bulunmal\u0131d\u0131r +writeOnly = salt yaz\u0131l\u0131r bir aland\u0131r, verilerde görünemez +contentEncoding = içerik kodlamas\u0131 {0} ile e\u015Fle\u015Fmiyor +contentMediaType = bir içerik de\u011Fil diff --git a/src/main/resources/jsv-messages_uk.properties b/src/main/resources/jsv-messages_uk.properties index ee627824a..0a2734405 100644 --- a/src/main/resources/jsv-messages_uk.properties +++ b/src/main/resources/jsv-messages_uk.properties @@ -1,70 +1,70 @@ -$ref = {0}: \u043C\u0456\u0441\u0442\u0438\u0442\u044C \u043F\u043E\u043C\u0438\u043B\u043A\u0443 \u0437 ''refs'' -additionalItems = {0}: \u0456\u043D\u0434\u0435\u043A\u0441 ''{1}'' \u043D\u0435 \u0432\u0438\u0437\u043D\u0430\u0447\u0435\u043D\u043E \u0432 \u0441\u0445\u0435\u043C\u0456, \u0456 \u0441\u0445\u0435\u043C\u0430 \u043D\u0435 \u0434\u043E\u0437\u0432\u043E\u043B\u044F\u0454 \u0434\u043E\u0434\u0430\u0442\u043A\u043E\u0432\u0456 \u0435\u043B\u0435\u043C\u0435\u043D\u0442\u0438 -additionalProperties = {0}: \u0432\u043B\u0430\u0441\u0442\u0438\u0432\u0456\u0441\u0442\u044C ''{1}'' \u043D\u0435 \u0432\u0438\u0437\u043D\u0430\u0447\u0435\u043D\u043E \u0432 \u0441\u0445\u0435\u043C\u0456, \u0456 \u0441\u0445\u0435\u043C\u0430 \u043D\u0435 \u0434\u043E\u0437\u0432\u043E\u043B\u044F\u0454 \u0434\u043E\u0434\u0430\u0442\u043A\u043E\u0432\u0456 \u0432\u043B\u0430\u0441\u0442\u0438\u0432\u043E\u0441\u0442\u0456 -allOf = {0}: \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u0438\u043C \u0434\u043B\u044F \u0432\u0441\u0456\u0445 \u0441\u0445\u0435\u043C {1} -anyOf = {0}: \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u0438\u043C \u0434\u043B\u044F \u0431\u0443\u0434\u044C-\u044F\u043A\u043E\u0457 \u0437\u0456 \u0441\u0445\u0435\u043C {1} -const = {0}: \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u043F\u043E\u0441\u0442\u0456\u0439\u043D\u0438\u043C \u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F\u043C ''{1}'' -contains = {0}: \u043D\u0435 \u043C\u0456\u0441\u0442\u0438\u0442\u044C \u0435\u043B\u0435\u043C\u0435\u043D\u0442, \u044F\u043A\u0438\u0439 \u043F\u0440\u043E\u0445\u043E\u0434\u0438\u0442\u044C \u0446\u0456 \u043F\u0435\u0440\u0435\u0432\u0456\u0440\u043A\u0438: {2} -contains.max = {0}: \u043C\u0430\u0454 \u043C\u0456\u0441\u0442\u0438\u0442\u0438 \u0449\u043E\u043D\u0430\u0439\u0431\u0456\u043B\u044C\u0448\u0435 {1} \u0435\u043B\u0435\u043C\u0435\u043D\u0442(\u0456\u0432), \u044F\u043A\u0456 \u043F\u0440\u043E\u0445\u043E\u0434\u044F\u0442\u044C \u0446\u0456 \u043F\u0435\u0440\u0435\u0432\u0456\u0440\u043A\u0438: {2} -contains.min = {0}: \u043C\u0430\u0454 \u043C\u0456\u0441\u0442\u0438\u0442\u0438 \u043F\u0440\u0438\u043D\u0430\u0439\u043C\u043D\u0456 {1} \u0435\u043B\u0435\u043C\u0435\u043D\u0442(\u0456\u0432), \u044F\u043A\u0456 \u043F\u0440\u043E\u0445\u043E\u0434\u044F\u0442\u044C \u0446\u0456 \u043F\u0435\u0440\u0435\u0432\u0456\u0440\u043A\u0438: {2} -dependencies = {0}: \u043C\u0456\u0441\u0442\u0438\u0442\u044C \u043F\u043E\u043C\u0438\u043B\u043A\u0443 \u0456\u0437 \u0437\u0430\u043B\u0435\u0436\u043D\u043E\u0441\u0442\u044F\u043C\u0438 {1} -dependentRequired = {0}: \u043C\u0430\u0454 \u0432\u0456\u0434\u0441\u0443\u0442\u043D\u044E \u0432\u043B\u0430\u0441\u0442\u0438\u0432\u0456\u0441\u0442\u044C ''{1}'', \u044F\u043A\u0430 \u0454 \u0437\u0430\u043B\u0435\u0436\u043D\u043E\u044E, \u043E\u0441\u043A\u0456\u043B\u044C\u043A\u0438 \u043F\u0440\u0438\u0441\u0443\u0442\u043D\u044F ''{2}'' -dependentSchemas = {0}: \u0454 \u043F\u043E\u043C\u0438\u043B\u043A\u0430 \u0437 dependentSchemas {1} -enum = {0}: \u043D\u0435 \u043C\u0430\u0454 \u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u0432 \u043F\u0435\u0440\u0435\u043B\u0456\u043A\u0443 {1} -exclusiveMaximum = {0}: \u043C\u0430\u0454 \u043C\u0430\u0442\u0438 \u0432\u0438\u043D\u044F\u0442\u043A\u043E\u0432\u0435 \u043C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F {1} -exclusiveMinimum = {0}: \u043F\u043E\u0432\u0438\u043D\u043D\u043E \u043C\u0430\u0442\u0438 \u0432\u0438\u043D\u044F\u0442\u043A\u043E\u0432\u0435 \u043C\u0456\u043D\u0456\u043C\u0430\u043B\u044C\u043D\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F {1} -false = {0}: \u0441\u0445\u0435\u043C\u0430 \u0434\u043B\u044F ''{1}'' \u043D\u0435\u0432\u0456\u0440\u043D\u0430 -format = {0}: \u043D\u0435 \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u0430\u0454 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {1} {2} -format.date = {0}: \u043D\u0435 \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u0430\u0454 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {1}, \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u043E\u044E \u043F\u043E\u0432\u043D\u043E\u044E \u0434\u0430\u0442\u043E\u044E RFC 3339 -format.date-time = {0}: \u043D\u0435 \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u0430\u0454 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {1} \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u043E\u044E \u0434\u0430\u0442\u043E\u044E-\u0447\u0430\u0441\u043E\u043C RFC 3339 -format.duration = {0}: \u043D\u0435 \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u0430\u0454 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {1}, \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u043E\u044E \u0442\u0440\u0438\u0432\u0430\u043B\u0456\u0441\u0442\u044E ISO 8601 -format.email = {0}: \u043D\u0435 \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u0430\u0454 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {1}, \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u043E\u044E \u043F\u043E\u0448\u0442\u043E\u0432\u043E\u044E \u0441\u043A\u0440\u0438\u043D\u044C\u043A\u043E\u044E RFC 5321 -format.ipv4 = {0}: \u043D\u0435 \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u0430\u0454 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {1} \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u043E\u044E IP-\u0430\u0434\u0440\u0435\u0441\u043E\u044E RFC 2673 -format.ipv6 = {0}: \u043D\u0435 \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u0430\u0454 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {1} \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u043E\u044E IP-\u0430\u0434\u0440\u0435\u0441\u043E\u044E RFC 4291 -format.idn-email = {0}: \u043D\u0435 \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u0430\u0454 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {1}, \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u043E\u044E \u043F\u043E\u0448\u0442\u043E\u0432\u043E\u044E \u0441\u043A\u0440\u0438\u043D\u044C\u043A\u043E\u044E RFC 6531 -format.idn-hostname = {0}: \u043D\u0435 \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u0430\u0454 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {1} \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u0438\u043C \u0456\u043D\u0442\u0435\u0440\u043D\u0430\u0446\u0456\u043E\u043D\u0430\u043B\u0456\u0437\u043E\u0432\u0430\u043D\u0438\u043C \u0456\u043C\u2019\u044F\u043C \u0445\u043E\u0441\u0442\u0430 RFC 5890 -format.iri = {0}: \u043D\u0435 \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u0430\u0454 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {1}, \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u0438\u043C RFC 3987 IRI -format.iri-reference = {0}: \u043D\u0435 \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u0430\u0454 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {1}, \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u0438\u043C \u043F\u043E\u0441\u0438\u043B\u0430\u043D\u043D\u044F\u043C IRI RFC 3987 -format.uri = {0}: \u043D\u0435 \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u0430\u0454 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {1}, \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u0438\u043C URI RFC 3986 -format.uri-reference = {0}: \u043D\u0435 \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u0430\u0454 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {1}, \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u0438\u043C \u043F\u043E\u0441\u0438\u043B\u0430\u043D\u043D\u044F\u043C URI RFC 3986 -format.uri-template = {0}: \u043D\u0435 \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u0430\u0454 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {1}, \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u0438\u043C \u0448\u0430\u0431\u043B\u043E\u043D\u043E\u043C URI RFC 6570 -format.uuid = {0}: \u043D\u0435 \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u0430\u0454 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {1}, \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u0438\u043C UUID RFC 4122 -format.regex = {0}: \u043D\u0435 \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u0430\u0454 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {1}, \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u0438\u043C \u0440\u0435\u0433\u0443\u043B\u044F\u0440\u043D\u0438\u043C \u0432\u0438\u0440\u0430\u0437\u043E\u043C ECMA-262 -format.time = {0}: \u043D\u0435 \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u0430\u0454 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {1}, \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u0438\u043C \u0447\u0430\u0441\u043E\u043C RFC 3339 -format.hostname = {0}: \u043D\u0435 \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u0430\u0454 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {1} \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u0438\u043C \u0456\u043C\u2019\u044F\u043C \u0445\u043E\u0441\u0442\u0430 RFC 1123 -format.json-pointer = {0}: \u043D\u0435 \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u0430\u0454 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {1}, \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u0438\u043C RFC 6901 JSON Pointer -format.relative-json-pointer = {0}: \u043D\u0435 \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u0430\u0454 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {1}, \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u0438\u043C \u0432\u0456\u0434\u043D\u043E\u0441\u043D\u0438\u043C \u043F\u043E\u043A\u0430\u0436\u0447\u0438\u043A\u043E\u043C JSON IETF -format.unknown = {0}: \u043C\u0430\u0454 \u043D\u0435\u0432\u0456\u0434\u043E\u043C\u0438\u0439 \u0444\u043E\u0440\u043C\u0430\u0442 ''{1}'' -id = {0}: ''{1}'' \u043D\u0435\u0434\u0456\u0439\u0441\u043D\u0438\u0439 {2} -items = {0}: \u0456\u043D\u0434\u0435\u043A\u0441 ''{1}'' \u043D\u0435 \u0432\u0438\u0437\u043D\u0430\u0447\u0435\u043D\u043E \u0432 \u0441\u0445\u0435\u043C\u0456, \u0456 \u0441\u0445\u0435\u043C\u0430 \u043D\u0435 \u0434\u043E\u0437\u0432\u043E\u043B\u044F\u0454 \u0434\u043E\u0434\u0430\u0442\u043A\u043E\u0432\u0438\u0445 \u0435\u043B\u0435\u043C\u0435\u043D\u0442\u0456\u0432 -maxContains = {0}: \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u043D\u0435\u0432\u0456\u0434\u2019\u0454\u043C\u043D\u0438\u043C \u0446\u0456\u043B\u0438\u043C \u0447\u0438\u0441\u043B\u043E\u043C \u0443 {1} -maxItems = {0}: \u043C\u0430\u0454 \u043C\u0430\u0442\u0438 \u0449\u043E\u043D\u0430\u0439\u0431\u0456\u043B\u044C\u0448\u0435 {1} \u0435\u043B\u0435\u043C\u0435\u043D\u0442\u0456\u0432, \u0430\u043B\u0435 \u0437\u043D\u0430\u0439\u0434\u0435\u043D\u043E {2} -maxLength = {0}: \u043D\u0435 \u0431\u0456\u043B\u044C\u0448\u0435 \u043D\u0456\u0436 {1} \u0441\u0438\u043C\u0432\u043E\u043B\u0456\u0432 -maxProperties = {0}: \u043C\u0430\u0454 \u043C\u0430\u0442\u0438 \u0449\u043E\u043D\u0430\u0439\u0431\u0456\u043B\u044C\u0448\u0435 {1} \u0432\u043B\u0430\u0441\u0442\u0438\u0432\u043E\u0441\u0442\u0435\u0439 -maximum = {0}: \u043C\u0430\u0454 \u043C\u0430\u0442\u0438 \u043C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F {1} -minContains = {0}: \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u043D\u0435\u0432\u0456\u0434\u2019\u0454\u043C\u043D\u0438\u043C \u0446\u0456\u043B\u0438\u043C \u0447\u0438\u0441\u043B\u043E\u043C \u0443 {1} -minContainsVsMaxContains = {0}: minContains \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u043C\u0435\u043D\u0448\u0438\u043C \u0430\u0431\u043E \u0434\u043E\u0440\u0456\u0432\u043D\u044E\u0432\u0430\u0442\u0438 maxContains \u0443 {1} -minItems = {0}: \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u043F\u0440\u0438\u043D\u0430\u0439\u043C\u043D\u0456 {1} \u0435\u043B\u0435\u043C\u0435\u043D\u0442\u0456\u0432, \u0430\u043B\u0435 \u0437\u043D\u0430\u0439\u0434\u0435\u043D\u043E {2} -minLength = {0}: \u043C\u0430\u0454 \u043C\u0456\u0441\u0442\u0438\u0442\u0438 \u043F\u0440\u0438\u043D\u0430\u0439\u043C\u043D\u0456 {1} \u0441\u0438\u043C\u0432\u043E\u043B\u0456\u0432 -minProperties = {0}: \u043C\u0430\u0454 \u043C\u0430\u0442\u0438 \u043F\u0440\u0438\u043D\u0430\u0439\u043C\u043D\u0456 {1} \u0432\u043B\u0430\u0441\u0442\u0438\u0432\u043E\u0441\u0442\u0435\u0439 -minimum = {0}: \u043C\u0430\u0454 \u043C\u0430\u0442\u0438 \u043C\u0456\u043D\u0456\u043C\u0430\u043B\u044C\u043D\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F {1} -multipleOf = {0}: \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u043A\u0440\u0430\u0442\u043D\u0438\u043C {1} -not = {0}: \u043D\u0435 \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u0438\u043C \u0434\u043B\u044F \u0441\u0445\u0435\u043C\u0438 {1} -notAllowed = {0}: \u0432\u043B\u0430\u0441\u0442\u0438\u0432\u0456\u0441\u0442\u044C ''{1}'' \u043D\u0435 \u0434\u043E\u0437\u0432\u043E\u043B\u0435\u043D\u0430, \u0430\u043B\u0435 \u0432\u043E\u043D\u0430 \u0454 \u0432 \u0434\u0430\u043D\u0438\u0445 -oneOf = {0}: \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u0438\u043C \u0434\u043B\u044F \u043E\u0434\u043D\u0456\u0454\u0457 \u0439 \u043B\u0438\u0448\u0435 \u043E\u0434\u043D\u0456\u0454\u0457 \u0441\u0445\u0435\u043C\u0438, \u0430\u043B\u0435 {1} \u0454 \u0434\u0456\u0439\u0441\u043D\u0438\u043C\u0438 -oneOf.indexes = {0}: \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u0438\u043C \u0434\u043B\u044F \u043E\u0434\u043D\u0456\u0454\u0457 \u0439 \u043B\u0438\u0448\u0435 \u043E\u0434\u043D\u0456\u0454\u0457 \u0441\u0445\u0435\u043C\u0438, \u0430\u043B\u0435 {1} \u0454 \u0434\u0456\u0439\u0441\u043D\u0438\u043C\u0438 \u0437 \u0456\u043D\u0434\u0435\u043A\u0441\u0430\u043C\u0438 ''{2}'' -pattern = {0}: \u043D\u0435 \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u0430\u0454 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 \u0440\u0435\u0433\u0443\u043B\u044F\u0440\u043D\u043E\u0433\u043E \u0432\u0438\u0440\u0430\u0437\u0443 {1} -patternProperties = {0}: \u0454 \u0434\u0435\u044F\u043A\u0430 \u043F\u043E\u043C\u0438\u043B\u043A\u0430 \u0437 ''\u0432\u043B\u0430\u0441\u0442\u0438\u0432\u043E\u0441\u0442\u0456 \u0448\u0430\u0431\u043B\u043E\u043D\u0443'' -prefixItems = {0}: \u0437\u0430 \u0446\u0438\u043C \u0456\u043D\u0434\u0435\u043A\u0441\u043E\u043C \u043D\u0435 \u0437\u043D\u0430\u0439\u0434\u0435\u043D\u043E \u0432\u0430\u043B\u0456\u0434\u0430\u0442\u043E\u0440\u0430 -properties = {0}: \u043C\u0456\u0441\u0442\u0438\u0442\u044C \u043F\u043E\u043C\u0438\u043B\u043A\u0443 \u0437 ''\u0432\u043B\u0430\u0441\u0442\u0438\u0432\u043E\u0441\u0442\u0456'' -propertyNames = {0}: \u043D\u0430\u0437\u0432\u0430 \u0432\u043B\u0430\u0441\u0442\u0438\u0432\u043E\u0441\u0442\u0456 ''{1}'' \u043D\u0435\u0434\u0456\u0439\u0441\u043D\u0430: {2} -readOnly = {0}: \u0446\u0435 \u043F\u043E\u043B\u0435 \u043B\u0438\u0448\u0435 \u0434\u043B\u044F \u0447\u0438\u0442\u0430\u043D\u043D\u044F, \u0439\u043E\u0433\u043E \u043D\u0435 \u043C\u043E\u0436\u043D\u0430 \u0437\u043C\u0456\u043D\u0438\u0442\u0438 -required = {0}: \u043D\u0435\u043E\u0431\u0445\u0456\u0434\u043D\u0430 \u0432\u043B\u0430\u0441\u0442\u0438\u0432\u0456\u0441\u0442\u044C ''{1}'' \u043D\u0435 \u0437\u043D\u0430\u0439\u0434\u0435\u043D\u0430 -type = {0}: \u0437\u043D\u0430\u0439\u0434\u0435\u043D\u043E {1}, \u043E\u0447\u0456\u043A\u0443\u0454\u0442\u044C\u0441\u044F {2} -unevaluatedItems = {0}: \u0456\u043D\u0434\u0435\u043A\u0441 ''{1}'' \u043D\u0435 \u043E\u0446\u0456\u043D\u044E\u0454\u0442\u044C\u0441\u044F, \u0456 \u0441\u0445\u0435\u043C\u0430 \u043D\u0435 \u0434\u043E\u0437\u0432\u043E\u043B\u044F\u0454 \u043D\u0435 \u043E\u0446\u0456\u043D\u0435\u043D\u0456 \u0435\u043B\u0435\u043C\u0435\u043D\u0442\u0438 -unevaluatedProperties = {0}: \u0432\u043B\u0430\u0441\u0442\u0438\u0432\u0456\u0441\u0442\u044C ''{1}'' \u043D\u0435 \u043E\u0446\u0456\u043D\u044E\u0454\u0442\u044C\u0441\u044F, \u0430 \u0441\u0445\u0435\u043C\u0430 \u043D\u0435 \u0434\u043E\u0437\u0432\u043E\u043B\u044F\u0454 \u0432\u043B\u0430\u0441\u0442\u0438\u0432\u043E\u0441\u0442\u0456 \u0431\u0435\u0437 \u043E\u0446\u0456\u043D\u043A\u0438 -unionType = {0}: \u0437\u043D\u0430\u0439\u0434\u0435\u043D\u043E {1}, \u043E\u0447\u0456\u043A\u0443\u0454\u0442\u044C\u0441\u044F {2} -uniqueItems = {0}: \u0443 \u043C\u0430\u0441\u0438\u0432\u0456 \u043F\u043E\u0432\u0438\u043D\u043D\u0456 \u0431\u0443\u0442\u0438 \u043B\u0438\u0448\u0435 \u0443\u043D\u0456\u043A\u0430\u043B\u044C\u043D\u0456 \u0435\u043B\u0435\u043C\u0435\u043D\u0442\u0438 -writeOnly = {0}: \u0446\u0435 \u043F\u043E\u043B\u0435 \u043B\u0438\u0448\u0435 \u0434\u043B\u044F \u0437\u0430\u043F\u0438\u0441\u0443, \u0432\u043E\u043D\u043E \u043D\u0435 \u043C\u043E\u0436\u0435 \u0432\u0456\u0434\u043E\u0431\u0440\u0430\u0436\u0430\u0442\u0438\u0441\u044F \u0432 \u0434\u0430\u043D\u0438\u0445 -contentEncoding = {0}: \u043D\u0435 \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u0430\u0454 \u043A\u043E\u0434\u0443\u0432\u0430\u043D\u043D\u044E \u0432\u043C\u0456\u0441\u0442\u0443 {1} -contentMediaType = {0}: \u043D\u0435 \u0454 \u0432\u043C\u0456\u0441\u0442\u043E\u043C me +$ref = \u043C\u0456\u0441\u0442\u0438\u0442\u044C \u043F\u043E\u043C\u0438\u043B\u043A\u0443 \u0437 ''refs'' +additionalItems = \u0456\u043D\u0434\u0435\u043A\u0441 ''{0}'' \u043D\u0435 \u0432\u0438\u0437\u043D\u0430\u0447\u0435\u043D\u043E \u0432 \u0441\u0445\u0435\u043C\u0456, \u0456 \u0441\u0445\u0435\u043C\u0430 \u043D\u0435 \u0434\u043E\u0437\u0432\u043E\u043B\u044F\u0454 \u0434\u043E\u0434\u0430\u0442\u043A\u043E\u0432\u0456 \u0435\u043B\u0435\u043C\u0435\u043D\u0442\u0438 +additionalProperties = \u0432\u043B\u0430\u0441\u0442\u0438\u0432\u0456\u0441\u0442\u044C ''{0}'' \u043D\u0435 \u0432\u0438\u0437\u043D\u0430\u0447\u0435\u043D\u043E \u0432 \u0441\u0445\u0435\u043C\u0456, \u0456 \u0441\u0445\u0435\u043C\u0430 \u043D\u0435 \u0434\u043E\u0437\u0432\u043E\u043B\u044F\u0454 \u0434\u043E\u0434\u0430\u0442\u043A\u043E\u0432\u0456 \u0432\u043B\u0430\u0441\u0442\u0438\u0432\u043E\u0441\u0442\u0456 +allOf = \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u0438\u043C \u0434\u043B\u044F \u0432\u0441\u0456\u0445 \u0441\u0445\u0435\u043C {0} +anyOf = \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u0438\u043C \u0434\u043B\u044F \u0431\u0443\u0434\u044C-\u044F\u043A\u043E\u0457 \u0437\u0456 \u0441\u0445\u0435\u043C {0} +const = \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u043F\u043E\u0441\u0442\u0456\u0439\u043D\u0438\u043C \u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F\u043C ''{0}'' +contains = \u043D\u0435 \u043C\u0456\u0441\u0442\u0438\u0442\u044C \u0435\u043B\u0435\u043C\u0435\u043D\u0442, \u044F\u043A\u0438\u0439 \u043F\u0440\u043E\u0445\u043E\u0434\u0438\u0442\u044C \u0446\u0456 \u043F\u0435\u0440\u0435\u0432\u0456\u0440\u043A\u0438: {1} +contains.max = \u043C\u0430\u0454 \u043C\u0456\u0441\u0442\u0438\u0442\u0438 \u0449\u043E\u043D\u0430\u0439\u0431\u0456\u043B\u044C\u0448\u0435 {0} \u0435\u043B\u0435\u043C\u0435\u043D\u0442(\u0456\u0432), \u044F\u043A\u0456 \u043F\u0440\u043E\u0445\u043E\u0434\u044F\u0442\u044C \u0446\u0456 \u043F\u0435\u0440\u0435\u0432\u0456\u0440\u043A\u0438: {1} +contains.min = \u043C\u0430\u0454 \u043C\u0456\u0441\u0442\u0438\u0442\u0438 \u043F\u0440\u0438\u043D\u0430\u0439\u043C\u043D\u0456 {0} \u0435\u043B\u0435\u043C\u0435\u043D\u0442(\u0456\u0432), \u044F\u043A\u0456 \u043F\u0440\u043E\u0445\u043E\u0434\u044F\u0442\u044C \u0446\u0456 \u043F\u0435\u0440\u0435\u0432\u0456\u0440\u043A\u0438: {1} +dependencies = \u043C\u0456\u0441\u0442\u0438\u0442\u044C \u043F\u043E\u043C\u0438\u043B\u043A\u0443 \u0456\u0437 \u0437\u0430\u043B\u0435\u0436\u043D\u043E\u0441\u0442\u044F\u043C\u0438 {0} +dependentRequired = \u043C\u0430\u0454 \u0432\u0456\u0434\u0441\u0443\u0442\u043D\u044E \u0432\u043B\u0430\u0441\u0442\u0438\u0432\u0456\u0441\u0442\u044C ''{0}'', \u044F\u043A\u0430 \u0454 \u0437\u0430\u043B\u0435\u0436\u043D\u043E\u044E, \u043E\u0441\u043A\u0456\u043B\u044C\u043A\u0438 \u043F\u0440\u0438\u0441\u0443\u0442\u043D\u044F ''{1}'' +dependentSchemas = \u0454 \u043F\u043E\u043C\u0438\u043B\u043A\u0430 \u0437 dependentSchemas {0} +enum = \u043D\u0435 \u043C\u0430\u0454 \u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F \u0432 \u043F\u0435\u0440\u0435\u043B\u0456\u043A\u0443 {0} +exclusiveMaximum = \u043C\u0430\u0454 \u043C\u0430\u0442\u0438 \u0432\u0438\u043D\u044F\u0442\u043A\u043E\u0432\u0435 \u043C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F {0} +exclusiveMinimum = \u043F\u043E\u0432\u0438\u043D\u043D\u043E \u043C\u0430\u0442\u0438 \u0432\u0438\u043D\u044F\u0442\u043A\u043E\u0432\u0435 \u043C\u0456\u043D\u0456\u043C\u0430\u043B\u044C\u043D\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F {0} +false = \u0441\u0445\u0435\u043C\u0430 \u0434\u043B\u044F ''{0}'' \u043D\u0435\u0432\u0456\u0440\u043D\u0430 +format = \u043D\u0435 \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u0430\u0454 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {0} +format.date = \u043D\u0435 \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u0430\u0454 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {0}, \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u043E\u044E \u043F\u043E\u0432\u043D\u043E\u044E \u0434\u0430\u0442\u043E\u044E RFC 3339 +format.date-time = \u043D\u0435 \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u0430\u0454 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {0} \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u043E\u044E \u0434\u0430\u0442\u043E\u044E-\u0447\u0430\u0441\u043E\u043C RFC 3339 +format.duration = \u043D\u0435 \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u0430\u0454 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {0}, \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u043E\u044E \u0442\u0440\u0438\u0432\u0430\u043B\u0456\u0441\u0442\u044E ISO 8601 +format.email = \u043D\u0435 \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u0430\u0454 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {0}, \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u043E\u044E \u043F\u043E\u0448\u0442\u043E\u0432\u043E\u044E \u0441\u043A\u0440\u0438\u043D\u044C\u043A\u043E\u044E RFC 5321 +format.ipv4 = \u043D\u0435 \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u0430\u0454 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {0} \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u043E\u044E IP-\u0430\u0434\u0440\u0435\u0441\u043E\u044E RFC 2673 +format.ipv6 = \u043D\u0435 \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u0430\u0454 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {0} \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u043E\u044E IP-\u0430\u0434\u0440\u0435\u0441\u043E\u044E RFC 4291 +format.idn-email = \u043D\u0435 \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u0430\u0454 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {0}, \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u043E\u044E \u043F\u043E\u0448\u0442\u043E\u0432\u043E\u044E \u0441\u043A\u0440\u0438\u043D\u044C\u043A\u043E\u044E RFC 6531 +format.idn-hostname = \u043D\u0435 \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u0430\u0454 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {0} \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u0438\u043C \u0456\u043D\u0442\u0435\u0440\u043D\u0430\u0446\u0456\u043E\u043D\u0430\u043B\u0456\u0437\u043E\u0432\u0430\u043D\u0438\u043C \u0456\u043C\u2019\u044F\u043C \u0445\u043E\u0441\u0442\u0430 RFC 5890 +format.iri = \u043D\u0435 \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u0430\u0454 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {0}, \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u0438\u043C RFC 3987 IRI +format.iri-reference = \u043D\u0435 \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u0430\u0454 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {0}, \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u0438\u043C \u043F\u043E\u0441\u0438\u043B\u0430\u043D\u043D\u044F\u043C IRI RFC 3987 +format.uri = \u043D\u0435 \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u0430\u0454 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {0}, \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u0438\u043C URI RFC 3986 +format.uri-reference = \u043D\u0435 \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u0430\u0454 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {0}, \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u0438\u043C \u043F\u043E\u0441\u0438\u043B\u0430\u043D\u043D\u044F\u043C URI RFC 3986 +format.uri-template = \u043D\u0435 \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u0430\u0454 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {0}, \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u0438\u043C \u0448\u0430\u0431\u043B\u043E\u043D\u043E\u043C URI RFC 6570 +format.uuid = \u043D\u0435 \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u0430\u0454 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {0}, \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u0438\u043C UUID RFC 4122 +format.regex = \u043D\u0435 \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u0430\u0454 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {0}, \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u0438\u043C \u0440\u0435\u0433\u0443\u043B\u044F\u0440\u043D\u0438\u043C \u0432\u0438\u0440\u0430\u0437\u043E\u043C ECMA-262 +format.time = \u043D\u0435 \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u0430\u0454 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {0}, \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u0438\u043C \u0447\u0430\u0441\u043E\u043C RFC 3339 +format.hostname = \u043D\u0435 \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u0430\u0454 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {0} \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u0438\u043C \u0456\u043C\u2019\u044F\u043C \u0445\u043E\u0441\u0442\u0430 RFC 1123 +format.json-pointer = \u043D\u0435 \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u0430\u0454 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {0}, \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u0438\u043C RFC 6901 JSON Pointer +format.relative-json-pointer = \u043D\u0435 \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u0430\u0454 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 {0}, \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u0438\u043C \u0432\u0456\u0434\u043D\u043E\u0441\u043D\u0438\u043C \u043F\u043E\u043A\u0430\u0436\u0447\u0438\u043A\u043E\u043C JSON IETF +format.unknown = \u043C\u0430\u0454 \u043D\u0435\u0432\u0456\u0434\u043E\u043C\u0438\u0439 \u0444\u043E\u0440\u043C\u0430\u0442 ''{0}'' +id = ''{0}'' \u043D\u0435\u0434\u0456\u0439\u0441\u043D\u0438\u0439 {1} +items = \u0456\u043D\u0434\u0435\u043A\u0441 ''{0}'' \u043D\u0435 \u0432\u0438\u0437\u043D\u0430\u0447\u0435\u043D\u043E \u0432 \u0441\u0445\u0435\u043C\u0456, \u0456 \u0441\u0445\u0435\u043C\u0430 \u043D\u0435 \u0434\u043E\u0437\u0432\u043E\u043B\u044F\u0454 \u0434\u043E\u0434\u0430\u0442\u043A\u043E\u0432\u0438\u0445 \u0435\u043B\u0435\u043C\u0435\u043D\u0442\u0456\u0432 +maxContains = \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u043D\u0435\u0432\u0456\u0434\u2019\u0454\u043C\u043D\u0438\u043C \u0446\u0456\u043B\u0438\u043C \u0447\u0438\u0441\u043B\u043E\u043C \u0443 {0} +maxItems = \u043C\u0430\u0454 \u043C\u0430\u0442\u0438 \u0449\u043E\u043D\u0430\u0439\u0431\u0456\u043B\u044C\u0448\u0435 {0} \u0435\u043B\u0435\u043C\u0435\u043D\u0442\u0456\u0432, \u0430\u043B\u0435 \u0437\u043D\u0430\u0439\u0434\u0435\u043D\u043E {1} +maxLength = \u043D\u0435 \u0431\u0456\u043B\u044C\u0448\u0435 \u043D\u0456\u0436 {0} \u0441\u0438\u043C\u0432\u043E\u043B\u0456\u0432 +maxProperties = \u043C\u0430\u0454 \u043C\u0430\u0442\u0438 \u0449\u043E\u043D\u0430\u0439\u0431\u0456\u043B\u044C\u0448\u0435 {0} \u0432\u043B\u0430\u0441\u0442\u0438\u0432\u043E\u0441\u0442\u0435\u0439 +maximum = \u043C\u0430\u0454 \u043C\u0430\u0442\u0438 \u043C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F {0} +minContains = \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u043D\u0435\u0432\u0456\u0434\u2019\u0454\u043C\u043D\u0438\u043C \u0446\u0456\u043B\u0438\u043C \u0447\u0438\u0441\u043B\u043E\u043C \u0443 {0} +minContainsVsMaxContains = minContains \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u043C\u0435\u043D\u0448\u0438\u043C \u0430\u0431\u043E \u0434\u043E\u0440\u0456\u0432\u043D\u044E\u0432\u0430\u0442\u0438 maxContains \u0443 {0} +minItems = \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u043F\u0440\u0438\u043D\u0430\u0439\u043C\u043D\u0456 {0} \u0435\u043B\u0435\u043C\u0435\u043D\u0442\u0456\u0432, \u0430\u043B\u0435 \u0437\u043D\u0430\u0439\u0434\u0435\u043D\u043E {1} +minLength = \u043C\u0430\u0454 \u043C\u0456\u0441\u0442\u0438\u0442\u0438 \u043F\u0440\u0438\u043D\u0430\u0439\u043C\u043D\u0456 {0} \u0441\u0438\u043C\u0432\u043E\u043B\u0456\u0432 +minProperties = \u043C\u0430\u0454 \u043C\u0430\u0442\u0438 \u043F\u0440\u0438\u043D\u0430\u0439\u043C\u043D\u0456 {0} \u0432\u043B\u0430\u0441\u0442\u0438\u0432\u043E\u0441\u0442\u0435\u0439 +minimum = \u043C\u0430\u0454 \u043C\u0430\u0442\u0438 \u043C\u0456\u043D\u0456\u043C\u0430\u043B\u044C\u043D\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044F {0} +multipleOf = \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u043A\u0440\u0430\u0442\u043D\u0438\u043C {0} +not = \u043D\u0435 \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u0438\u043C \u0434\u043B\u044F \u0441\u0445\u0435\u043C\u0438 {0} +notAllowed = \u0432\u043B\u0430\u0441\u0442\u0438\u0432\u0456\u0441\u0442\u044C ''{0}'' \u043D\u0435 \u0434\u043E\u0437\u0432\u043E\u043B\u0435\u043D\u0430, \u0430\u043B\u0435 \u0432\u043E\u043D\u0430 \u0454 \u0432 \u0434\u0430\u043D\u0438\u0445 +oneOf = \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u0438\u043C \u0434\u043B\u044F \u043E\u0434\u043D\u0456\u0454\u0457 \u0439 \u043B\u0438\u0448\u0435 \u043E\u0434\u043D\u0456\u0454\u0457 \u0441\u0445\u0435\u043C\u0438, \u0430\u043B\u0435 {0} \u0454 \u0434\u0456\u0439\u0441\u043D\u0438\u043C\u0438 +oneOf.indexes = \u043C\u0430\u0454 \u0431\u0443\u0442\u0438 \u0434\u0456\u0439\u0441\u043D\u0438\u043C \u0434\u043B\u044F \u043E\u0434\u043D\u0456\u0454\u0457 \u0439 \u043B\u0438\u0448\u0435 \u043E\u0434\u043D\u0456\u0454\u0457 \u0441\u0445\u0435\u043C\u0438, \u0430\u043B\u0435 {0} \u0454 \u0434\u0456\u0439\u0441\u043D\u0438\u043C\u0438 \u0437 \u0456\u043D\u0434\u0435\u043A\u0441\u0430\u043C\u0438 ''{1}'' +pattern = \u043D\u0435 \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u0430\u0454 \u0448\u0430\u0431\u043B\u043E\u043D\u0443 \u0440\u0435\u0433\u0443\u043B\u044F\u0440\u043D\u043E\u0433\u043E \u0432\u0438\u0440\u0430\u0437\u0443 {0} +patternProperties = \u0454 \u0434\u0435\u044F\u043A\u0430 \u043F\u043E\u043C\u0438\u043B\u043A\u0430 \u0437 ''\u0432\u043B\u0430\u0441\u0442\u0438\u0432\u043E\u0441\u0442\u0456 \u0448\u0430\u0431\u043B\u043E\u043D\u0443'' +prefixItems = \u0437\u0430 \u0446\u0438\u043C \u0456\u043D\u0434\u0435\u043A\u0441\u043E\u043C \u043D\u0435 \u0437\u043D\u0430\u0439\u0434\u0435\u043D\u043E \u0432\u0430\u043B\u0456\u0434\u0430\u0442\u043E\u0440\u0430 +properties = \u043C\u0456\u0441\u0442\u0438\u0442\u044C \u043F\u043E\u043C\u0438\u043B\u043A\u0443 \u0437 ''\u0432\u043B\u0430\u0441\u0442\u0438\u0432\u043E\u0441\u0442\u0456'' +propertyNames = \u043D\u0430\u0437\u0432\u0430 \u0432\u043B\u0430\u0441\u0442\u0438\u0432\u043E\u0441\u0442\u0456 ''{0}'' \u043D\u0435\u0434\u0456\u0439\u0441\u043D\u0430: {1} +readOnly = \u0446\u0435 \u043F\u043E\u043B\u0435 \u043B\u0438\u0448\u0435 \u0434\u043B\u044F \u0447\u0438\u0442\u0430\u043D\u043D\u044F, \u0439\u043E\u0433\u043E \u043D\u0435 \u043C\u043E\u0436\u043D\u0430 \u0437\u043C\u0456\u043D\u0438\u0442\u0438 +required = \u043D\u0435\u043E\u0431\u0445\u0456\u0434\u043D\u0430 \u0432\u043B\u0430\u0441\u0442\u0438\u0432\u0456\u0441\u0442\u044C ''{0}'' \u043D\u0435 \u0437\u043D\u0430\u0439\u0434\u0435\u043D\u0430 +type = \u0437\u043D\u0430\u0439\u0434\u0435\u043D\u043E {0}, \u043E\u0447\u0456\u043A\u0443\u0454\u0442\u044C\u0441\u044F {1} +unevaluatedItems = \u0456\u043D\u0434\u0435\u043A\u0441 ''{0}'' \u043D\u0435 \u043E\u0446\u0456\u043D\u044E\u0454\u0442\u044C\u0441\u044F, \u0456 \u0441\u0445\u0435\u043C\u0430 \u043D\u0435 \u0434\u043E\u0437\u0432\u043E\u043B\u044F\u0454 \u043D\u0435 \u043E\u0446\u0456\u043D\u0435\u043D\u0456 \u0435\u043B\u0435\u043C\u0435\u043D\u0442\u0438 +unevaluatedProperties = \u0432\u043B\u0430\u0441\u0442\u0438\u0432\u0456\u0441\u0442\u044C ''{0}'' \u043D\u0435 \u043E\u0446\u0456\u043D\u044E\u0454\u0442\u044C\u0441\u044F, \u0430 \u0441\u0445\u0435\u043C\u0430 \u043D\u0435 \u0434\u043E\u0437\u0432\u043E\u043B\u044F\u0454 \u0432\u043B\u0430\u0441\u0442\u0438\u0432\u043E\u0441\u0442\u0456 \u0431\u0435\u0437 \u043E\u0446\u0456\u043D\u043A\u0438 +unionType = \u0437\u043D\u0430\u0439\u0434\u0435\u043D\u043E {0}, \u043E\u0447\u0456\u043A\u0443\u0454\u0442\u044C\u0441\u044F {1} +uniqueItems = \u0443 \u043C\u0430\u0441\u0438\u0432\u0456 \u043F\u043E\u0432\u0438\u043D\u043D\u0456 \u0431\u0443\u0442\u0438 \u043B\u0438\u0448\u0435 \u0443\u043D\u0456\u043A\u0430\u043B\u044C\u043D\u0456 \u0435\u043B\u0435\u043C\u0435\u043D\u0442\u0438 +writeOnly = \u0446\u0435 \u043F\u043E\u043B\u0435 \u043B\u0438\u0448\u0435 \u0434\u043B\u044F \u0437\u0430\u043F\u0438\u0441\u0443, \u0432\u043E\u043D\u043E \u043D\u0435 \u043C\u043E\u0436\u0435 \u0432\u0456\u0434\u043E\u0431\u0440\u0430\u0436\u0430\u0442\u0438\u0441\u044F \u0432 \u0434\u0430\u043D\u0438\u0445 +contentEncoding = \u043D\u0435 \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u0430\u0454 \u043A\u043E\u0434\u0443\u0432\u0430\u043D\u043D\u044E \u0432\u043C\u0456\u0441\u0442\u0443 {0} +contentMediaType = \u043D\u0435 \u0454 \u0432\u043C\u0456\u0441\u0442\u043E\u043C me diff --git a/src/main/resources/jsv-messages_vi.properties b/src/main/resources/jsv-messages_vi.properties index 94797c3b6..7e7f33ec5 100644 --- a/src/main/resources/jsv-messages_vi.properties +++ b/src/main/resources/jsv-messages_vi.properties @@ -1,70 +1,70 @@ -$ref = {0}: có l\u1ED7i ''refs'' -additionalItems = {0}: ch\u1EC9 m\u1EE5c ''{1}'' không \u0111\u01B0\u1EE3c xác \u0111\u1ECBnh trong l\u01B0\u1EE3c \u0111\u1ED3 và l\u01B0\u1EE3c \u0111\u1ED3 không cho phép các m\u1EE5c b\u1ED5 sung -additionalProperties = {0}: thu\u1ED9c tính ''{1}'' không \u0111\u01B0\u1EE3c xác \u0111\u1ECBnh trong l\u01B0\u1EE3c \u0111\u1ED3 và l\u01B0\u1EE3c \u0111\u1ED3 không cho phép các thu\u1ED9c tính b\u1ED5 sung -allOf = {0}: ph\u1EA3i h\u1EE3p l\u1EC7 v\u1EDBi t\u1EA5t c\u1EA3 l\u01B0\u1EE3c \u0111\u1ED3 {1} -anyOf = {0}: ph\u1EA3i h\u1EE3p l\u1EC7 v\u1EDBi b\u1EA5t k\u1EF3 l\u01B0\u1EE3c \u0111\u1ED3 nào {1} -const = {0}: ph\u1EA3i là giá tr\u1ECB không \u0111\u1ED5i ''{1}'' -contains = {0}: không ch\u1EE9a ph\u1EA7n t\u1EED v\u01B0\u1EE3t qua các xác nh\u1EADn này: {2} -contains.max = {0}: ph\u1EA3i ch\u1EE9a t\u1ED1i \u0111a {1} ph\u1EA7n t\u1EED v\u01B0\u1EE3t qua các xác th\u1EF1c này: {2} -contains.min = {0}: ph\u1EA3i ch\u1EE9a ít nh\u1EA5t {1} ph\u1EA7n t\u1EED v\u01B0\u1EE3t qua các xác nh\u1EADn này: {2} -dependencies = {0}: có l\u1ED7i v\u1EDBi ph\u1EE5 thu\u1ED9c {1} -dependentRequired = {0}: thi\u1EBFu thu\u1ED9c tính ''{1}'' thu\u1ED9c tính ph\u1EE5 thu\u1ED9c b\u1EAFt bu\u1ED9c vì ''{2}'' hi\u1EC7n di\u1EC7n -dependentSchemas = {0}: có l\u1ED7i v\u1EDBi dependencySchemas {1} -enum = {0}: không có giá tr\u1ECB trong b\u1EA3ng li\u1EC7t kê {1} -exclusiveMaximum = {0}: ph\u1EA3i có giá tr\u1ECB t\u1ED1i \u0111a \u0111\u1ED9c quy\u1EC1n là {1} -exclusiveMinimum = {0}: ph\u1EA3i có giá tr\u1ECB t\u1ED1i thi\u1EC3u duy nh\u1EA5t là {1} -false = {0}: l\u01B0\u1EE3c \u0111\u1ED3 cho ''{1}'' là sai -format = {0}: không kh\u1EDBp v\u1EDBi m\u1EABu {1} {2} -format.date = {0}: không kh\u1EDBp v\u1EDBi m\u1EABu {1} ph\u1EA3i là ngày \u0111\u1EA7y \u0111\u1EE7 RFC 3339 h\u1EE3p l\u1EC7 -format.date-time = {0}: không kh\u1EDBp v\u1EDBi m\u1EABu {1} ph\u1EA3i là ngày gi\u1EDD h\u1EE3p l\u1EC7 RFC 3339 -format.duration = {0}: không kh\u1EDBp v\u1EDBi m\u1EABu {1} ph\u1EA3i có th\u1EDDi l\u01B0\u1EE3ng ISO 8601 h\u1EE3p l\u1EC7 -format.email = {0}: không kh\u1EDBp v\u1EDBi m\u1EABu {1} ph\u1EA3i là H\u1ED9p th\u01B0 RFC 5321 h\u1EE3p l\u1EC7 -format.ipv4 = {0}: không kh\u1EDBp v\u1EDBi m\u1EABu {1} ph\u1EA3i là \u0111\u1ECBa ch\u1EC9 IP RFC 2673 h\u1EE3p l\u1EC7 -format.ipv6 = {0}: không kh\u1EDBp v\u1EDBi m\u1EABu {1} ph\u1EA3i là \u0111\u1ECBa ch\u1EC9 IP RFC 4291 h\u1EE3p l\u1EC7 -format.idn-email = {0}: không kh\u1EDBp v\u1EDBi m\u1EABu {1} ph\u1EA3i là H\u1ED9p th\u01B0 RFC 6531 h\u1EE3p l\u1EC7 -format.idn-hostname = {0}: không kh\u1EDBp v\u1EDBi m\u1EABu {1} ph\u1EA3i là tên máy ch\u1EE7 \u0111\u01B0\u1EE3c qu\u1ED1c t\u1EBF hóa RFC 5890 h\u1EE3p l\u1EC7 -format.iri = {0}: không kh\u1EDBp v\u1EDBi m\u1EABu {1} ph\u1EA3i là RFC 3987 IRI h\u1EE3p l\u1EC7 -format.iri-reference = {0}: không kh\u1EDBp v\u1EDBi m\u1EABu {1} ph\u1EA3i là tham chi\u1EBFu IRI RFC 3987 h\u1EE3p l\u1EC7 -format.uri = {0}: không kh\u1EDBp v\u1EDBi m\u1EABu {1} ph\u1EA3i là URI RFC 3986 h\u1EE3p l\u1EC7 -format.uri-reference = {0}: không kh\u1EDBp v\u1EDBi m\u1EABu {1} ph\u1EA3i là tham chi\u1EBFu URI RFC 3986 h\u1EE3p l\u1EC7 -format.uri-template = {0}: không kh\u1EDBp v\u1EDBi m\u1EABu {1} ph\u1EA3i là M\u1EABu URI RFC 6570 h\u1EE3p l\u1EC7 -format.uuid = {0}: không kh\u1EDBp v\u1EDBi m\u1EABu {1} ph\u1EA3i là UUID RFC 4122 h\u1EE3p l\u1EC7 -format.regex = {0}: không kh\u1EDBp v\u1EDBi m\u1EABu {1} ph\u1EA3i là bi\u1EC3u th\u1EE9c chính quy ECMA-262 h\u1EE3p l\u1EC7 -format.time = {0}: không kh\u1EDBp v\u1EDBi m\u1EABu {1} ph\u1EA3i là th\u1EDDi gian RFC 3339 h\u1EE3p l\u1EC7 -format.hostname = {0}: không kh\u1EDBp v\u1EDBi m\u1EABu {1} ph\u1EA3i là tên máy ch\u1EE7 RFC 1123 h\u1EE3p l\u1EC7 -format.json-pointer = {0}: không kh\u1EDBp v\u1EDBi m\u1EABu {1} ph\u1EA3i là Con tr\u1ECF JSON RFC 6901 h\u1EE3p l\u1EC7 -format.relative-json-pointer = {0}: không kh\u1EDBp v\u1EDBi m\u1EABu {1} ph\u1EA3i là Con tr\u1ECF JSON t\u01B0\u01A1ng \u0111\u1ED1i c\u1EE7a IETF h\u1EE3p l\u1EC7 -format.unknown = {0}: có \u0111\u1ECBnh d\u1EA1ng không xác \u0111\u1ECBnh ''{1}'' -id = {0}: ''{1}'' không ph\u1EA3i là {2} h\u1EE3p l\u1EC7 -items = {0}: ch\u1EC9 m\u1EE5c ''{1}'' không \u0111\u01B0\u1EE3c xác \u0111\u1ECBnh trong l\u01B0\u1EE3c \u0111\u1ED3 và l\u01B0\u1EE3c \u0111\u1ED3 không cho phép các m\u1EE5c b\u1ED5 sung -maxContains = {0}: ph\u1EA3i là s\u1ED1 nguyên không âm trong {1} -maxItems = {0}: ph\u1EA3i có t\u1ED1i \u0111a {1} m\u1EE5c nh\u01B0ng \u0111ã tìm th\u1EA5y {2} -maxLength = {0}: ph\u1EA3i dài t\u1ED1i \u0111a {1} ký t\u1EF1 -maxProperties = {0}: ph\u1EA3i có t\u1ED1i \u0111a {1} thu\u1ED9c tính -maximum = {0}: ph\u1EA3i có giá tr\u1ECB t\u1ED1i \u0111a là {1} -minContains = {0}: ph\u1EA3i là s\u1ED1 nguyên không âm trong {1} -minContainsVsMaxContains = {0}: minContains ph\u1EA3i nh\u1ECF h\u01A1n ho\u1EB7c b\u1EB1ng maxContains trong {1} -minItems = {0}: ph\u1EA3i có ít nh\u1EA5t {1} m\u1EE5c nh\u01B0ng \u0111ã tìm th\u1EA5y {2} -minLength = {0}: ph\u1EA3i dài ít nh\u1EA5t {1} ký t\u1EF1 -minProperties = {0}: ph\u1EA3i có ít nh\u1EA5t {1} thu\u1ED9c tính -minimum = {0}: ph\u1EA3i có giá tr\u1ECB t\u1ED1i thi\u1EC3u là {1} -multipleOf = {0}: ph\u1EA3i là b\u1ED9i s\u1ED1 c\u1EE7a {1} -not = {0}: không \u0111\u01B0\u1EE3c h\u1EE3p l\u1EC7 \u0111\u1ED1i v\u1EDBi l\u01B0\u1EE3c \u0111\u1ED3 {1} -notAllowed = {0}: thu\u1ED9c tính ''{1}'' không \u0111\u01B0\u1EE3c phép nh\u01B0ng nó có trong d\u1EEF li\u1EC7u -oneOf = {0}: ph\u1EA3i h\u1EE3p l\u1EC7 v\u1EDBi m\u1ED9t và ch\u1EC9 m\u1ED9t l\u01B0\u1EE3c \u0111\u1ED3, nh\u01B0ng {1} h\u1EE3p l\u1EC7 -oneOf.indexes = {0}: ph\u1EA3i h\u1EE3p l\u1EC7 v\u1EDBi m\u1ED9t và ch\u1EC9 m\u1ED9t l\u01B0\u1EE3c \u0111\u1ED3, nh\u01B0ng {1} h\u1EE3p l\u1EC7 v\u1EDBi các ch\u1EC9 m\u1EE5c ''{2}'' -pattern = {0}: không kh\u1EDBp v\u1EDBi m\u1EABu bi\u1EC3u th\u1EE9c chính quy {1} -patternProperties = {0}: có m\u1ED9t s\u1ED1 l\u1ED7i v\u1EDBi ''thu\u1ED9c tính m\u1EABu'' -prefixItems = {0}: không tìm th\u1EA5y trình xác th\u1EF1c nào t\u1EA1i ch\u1EC9 m\u1EE5c này -properties = {0}: có l\u1ED7i ''thu\u1ED9c tính'' -propertyNames = {0}: tên thu\u1ED9c tính ''{1}'' không h\u1EE3p l\u1EC7: {2} -readOnly = {0}: là tr\u01B0\u1EDDng ch\u1EC9 \u0111\u1ECDc, không th\u1EC3 thay \u0111\u1ED5i -required = {0}: không tìm th\u1EA5y thu\u1ED9c tính b\u1EAFt bu\u1ED9c ''{1}'' -type = {0}: \u0111ã tìm th\u1EA5y {1}, mong \u0111\u1EE3i {2} -unevaluatedItems = {0}: ch\u1EC9 m\u1EE5c ''{1}'' không \u0111\u01B0\u1EE3c \u0111ánh giá và l\u01B0\u1EE3c \u0111\u1ED3 không cho phép các m\u1EE5c không \u0111\u01B0\u1EE3c \u0111ánh giá -unevaluatedProperties = {0}: thu\u1ED9c tính ''{1}'' không \u0111\u01B0\u1EE3c \u0111ánh giá và l\u01B0\u1EE3c \u0111\u1ED3 không cho phép các thu\u1ED9c tính không \u0111\u01B0\u1EE3c \u0111ánh giá -unionType = {0}: \u0111ã tìm th\u1EA5y {1}, mong \u0111\u1EE3i {2} -uniqueItems = {0}: ch\u1EC9 \u0111\u01B0\u1EE3c có các m\u1EE5c duy nh\u1EA5t trong m\u1EA3ng -writeOnly = {0}: là tr\u01B0\u1EDDng ch\u1EC9 ghi, không xu\u1EA5t hi\u1EC7n trong d\u1EEF li\u1EC7u -contentEncoding = {0}: không kh\u1EDBp v\u1EDBi mã hóa n\u1ED9i dung {1} -contentMediaType = {0}: không ph\u1EA3i là n\u1ED9i dung c\u1EE7a tôi +$ref = có l\u1ED7i ''refs'' +additionalItems = ch\u1EC9 m\u1EE5c ''{0}'' không \u0111\u01B0\u1EE3c xác \u0111\u1ECBnh trong l\u01B0\u1EE3c \u0111\u1ED3 và l\u01B0\u1EE3c \u0111\u1ED3 không cho phép các m\u1EE5c b\u1ED5 sung +additionalProperties = thu\u1ED9c tính ''{0}'' không \u0111\u01B0\u1EE3c xác \u0111\u1ECBnh trong l\u01B0\u1EE3c \u0111\u1ED3 và l\u01B0\u1EE3c \u0111\u1ED3 không cho phép các thu\u1ED9c tính b\u1ED5 sung +allOf = ph\u1EA3i h\u1EE3p l\u1EC7 v\u1EDBi t\u1EA5t c\u1EA3 l\u01B0\u1EE3c \u0111\u1ED3 {0} +anyOf = ph\u1EA3i h\u1EE3p l\u1EC7 v\u1EDBi b\u1EA5t k\u1EF3 l\u01B0\u1EE3c \u0111\u1ED3 nào {0} +const = ph\u1EA3i là giá tr\u1ECB không \u0111\u1ED5i ''{0}'' +contains = không ch\u1EE9a ph\u1EA7n t\u1EED v\u01B0\u1EE3t qua các xác nh\u1EADn này: {1} +contains.max = ph\u1EA3i ch\u1EE9a t\u1ED1i \u0111a {0} ph\u1EA7n t\u1EED v\u01B0\u1EE3t qua các xác th\u1EF1c này: {1} +contains.min = ph\u1EA3i ch\u1EE9a ít nh\u1EA5t {0} ph\u1EA7n t\u1EED v\u01B0\u1EE3t qua các xác nh\u1EADn này: {1} +dependencies = có l\u1ED7i v\u1EDBi ph\u1EE5 thu\u1ED9c {0} +dependentRequired = thi\u1EBFu thu\u1ED9c tính ''{0}'' thu\u1ED9c tính ph\u1EE5 thu\u1ED9c b\u1EAFt bu\u1ED9c vì ''{1}'' hi\u1EC7n di\u1EC7n +dependentSchemas = có l\u1ED7i v\u1EDBi dependencySchemas {0} +enum = không có giá tr\u1ECB trong b\u1EA3ng li\u1EC7t kê {0} +exclusiveMaximum = ph\u1EA3i có giá tr\u1ECB t\u1ED1i \u0111a \u0111\u1ED9c quy\u1EC1n là {0} +exclusiveMinimum = ph\u1EA3i có giá tr\u1ECB t\u1ED1i thi\u1EC3u duy nh\u1EA5t là {0} +false = l\u01B0\u1EE3c \u0111\u1ED3 cho ''{0}'' là sai +format = không kh\u1EDBp v\u1EDBi m\u1EABu {0} +format.date = không kh\u1EDBp v\u1EDBi m\u1EABu {0} ph\u1EA3i là ngày \u0111\u1EA7y \u0111\u1EE7 RFC 3339 h\u1EE3p l\u1EC7 +format.date-time = không kh\u1EDBp v\u1EDBi m\u1EABu {0} ph\u1EA3i là ngày gi\u1EDD h\u1EE3p l\u1EC7 RFC 3339 +format.duration = không kh\u1EDBp v\u1EDBi m\u1EABu {0} ph\u1EA3i có th\u1EDDi l\u01B0\u1EE3ng ISO 8601 h\u1EE3p l\u1EC7 +format.email = không kh\u1EDBp v\u1EDBi m\u1EABu {0} ph\u1EA3i là H\u1ED9p th\u01B0 RFC 5321 h\u1EE3p l\u1EC7 +format.ipv4 = không kh\u1EDBp v\u1EDBi m\u1EABu {0} ph\u1EA3i là \u0111\u1ECBa ch\u1EC9 IP RFC 2673 h\u1EE3p l\u1EC7 +format.ipv6 = không kh\u1EDBp v\u1EDBi m\u1EABu {0} ph\u1EA3i là \u0111\u1ECBa ch\u1EC9 IP RFC 4291 h\u1EE3p l\u1EC7 +format.idn-email = không kh\u1EDBp v\u1EDBi m\u1EABu {0} ph\u1EA3i là H\u1ED9p th\u01B0 RFC 6531 h\u1EE3p l\u1EC7 +format.idn-hostname = không kh\u1EDBp v\u1EDBi m\u1EABu {0} ph\u1EA3i là tên máy ch\u1EE7 \u0111\u01B0\u1EE3c qu\u1ED1c t\u1EBF hóa RFC 5890 h\u1EE3p l\u1EC7 +format.iri = không kh\u1EDBp v\u1EDBi m\u1EABu {0} ph\u1EA3i là RFC 3987 IRI h\u1EE3p l\u1EC7 +format.iri-reference = không kh\u1EDBp v\u1EDBi m\u1EABu {0} ph\u1EA3i là tham chi\u1EBFu IRI RFC 3987 h\u1EE3p l\u1EC7 +format.uri = không kh\u1EDBp v\u1EDBi m\u1EABu {0} ph\u1EA3i là URI RFC 3986 h\u1EE3p l\u1EC7 +format.uri-reference = không kh\u1EDBp v\u1EDBi m\u1EABu {0} ph\u1EA3i là tham chi\u1EBFu URI RFC 3986 h\u1EE3p l\u1EC7 +format.uri-template = không kh\u1EDBp v\u1EDBi m\u1EABu {0} ph\u1EA3i là M\u1EABu URI RFC 6570 h\u1EE3p l\u1EC7 +format.uuid = không kh\u1EDBp v\u1EDBi m\u1EABu {0} ph\u1EA3i là UUID RFC 4122 h\u1EE3p l\u1EC7 +format.regex = không kh\u1EDBp v\u1EDBi m\u1EABu {0} ph\u1EA3i là bi\u1EC3u th\u1EE9c chính quy ECMA-262 h\u1EE3p l\u1EC7 +format.time = không kh\u1EDBp v\u1EDBi m\u1EABu {0} ph\u1EA3i là th\u1EDDi gian RFC 3339 h\u1EE3p l\u1EC7 +format.hostname = không kh\u1EDBp v\u1EDBi m\u1EABu {0} ph\u1EA3i là tên máy ch\u1EE7 RFC 1123 h\u1EE3p l\u1EC7 +format.json-pointer = không kh\u1EDBp v\u1EDBi m\u1EABu {0} ph\u1EA3i là Con tr\u1ECF JSON RFC 6901 h\u1EE3p l\u1EC7 +format.relative-json-pointer = không kh\u1EDBp v\u1EDBi m\u1EABu {0} ph\u1EA3i là Con tr\u1ECF JSON t\u01B0\u01A1ng \u0111\u1ED1i c\u1EE7a IETF h\u1EE3p l\u1EC7 +format.unknown = có \u0111\u1ECBnh d\u1EA1ng không xác \u0111\u1ECBnh ''{0}'' +id = ''{0}'' không ph\u1EA3i là {1} h\u1EE3p l\u1EC7 +items = ch\u1EC9 m\u1EE5c ''{0}'' không \u0111\u01B0\u1EE3c xác \u0111\u1ECBnh trong l\u01B0\u1EE3c \u0111\u1ED3 và l\u01B0\u1EE3c \u0111\u1ED3 không cho phép các m\u1EE5c b\u1ED5 sung +maxContains = ph\u1EA3i là s\u1ED1 nguyên không âm trong {0} +maxItems = ph\u1EA3i có t\u1ED1i \u0111a {0} m\u1EE5c nh\u01B0ng \u0111ã tìm th\u1EA5y {1} +maxLength = ph\u1EA3i dài t\u1ED1i \u0111a {0} ký t\u1EF1 +maxProperties = ph\u1EA3i có t\u1ED1i \u0111a {0} thu\u1ED9c tính +maximum = ph\u1EA3i có giá tr\u1ECB t\u1ED1i \u0111a là {0} +minContains = ph\u1EA3i là s\u1ED1 nguyên không âm trong {0} +minContainsVsMaxContains = minContains ph\u1EA3i nh\u1ECF h\u01A1n ho\u1EB7c b\u1EB1ng maxContains trong {0} +minItems = ph\u1EA3i có ít nh\u1EA5t {0} m\u1EE5c nh\u01B0ng \u0111ã tìm th\u1EA5y {1} +minLength = ph\u1EA3i dài ít nh\u1EA5t {0} ký t\u1EF1 +minProperties = ph\u1EA3i có ít nh\u1EA5t {0} thu\u1ED9c tính +minimum = ph\u1EA3i có giá tr\u1ECB t\u1ED1i thi\u1EC3u là {0} +multipleOf = ph\u1EA3i là b\u1ED9i s\u1ED1 c\u1EE7a {0} +not = không \u0111\u01B0\u1EE3c h\u1EE3p l\u1EC7 \u0111\u1ED1i v\u1EDBi l\u01B0\u1EE3c \u0111\u1ED3 {0} +notAllowed = thu\u1ED9c tính ''{0}'' không \u0111\u01B0\u1EE3c phép nh\u01B0ng nó có trong d\u1EEF li\u1EC7u +oneOf = ph\u1EA3i h\u1EE3p l\u1EC7 v\u1EDBi m\u1ED9t và ch\u1EC9 m\u1ED9t l\u01B0\u1EE3c \u0111\u1ED3, nh\u01B0ng {0} h\u1EE3p l\u1EC7 +oneOf.indexes = ph\u1EA3i h\u1EE3p l\u1EC7 v\u1EDBi m\u1ED9t và ch\u1EC9 m\u1ED9t l\u01B0\u1EE3c \u0111\u1ED3, nh\u01B0ng {0} h\u1EE3p l\u1EC7 v\u1EDBi các ch\u1EC9 m\u1EE5c ''{1}'' +pattern = không kh\u1EDBp v\u1EDBi m\u1EABu bi\u1EC3u th\u1EE9c chính quy {0} +patternProperties = có m\u1ED9t s\u1ED1 l\u1ED7i v\u1EDBi ''thu\u1ED9c tính m\u1EABu'' +prefixItems = không tìm th\u1EA5y trình xác th\u1EF1c nào t\u1EA1i ch\u1EC9 m\u1EE5c này +properties = có l\u1ED7i ''thu\u1ED9c tính'' +propertyNames = tên thu\u1ED9c tính ''{0}'' không h\u1EE3p l\u1EC7: {1} +readOnly = là tr\u01B0\u1EDDng ch\u1EC9 \u0111\u1ECDc, không th\u1EC3 thay \u0111\u1ED5i +required = không tìm th\u1EA5y thu\u1ED9c tính b\u1EAFt bu\u1ED9c ''{0}'' +type = \u0111ã tìm th\u1EA5y {0}, mong \u0111\u1EE3i {1} +unevaluatedItems = ch\u1EC9 m\u1EE5c ''{0}'' không \u0111\u01B0\u1EE3c \u0111ánh giá và l\u01B0\u1EE3c \u0111\u1ED3 không cho phép các m\u1EE5c không \u0111\u01B0\u1EE3c \u0111ánh giá +unevaluatedProperties = thu\u1ED9c tính ''{0}'' không \u0111\u01B0\u1EE3c \u0111ánh giá và l\u01B0\u1EE3c \u0111\u1ED3 không cho phép các thu\u1ED9c tính không \u0111\u01B0\u1EE3c \u0111ánh giá +unionType = \u0111ã tìm th\u1EA5y {0}, mong \u0111\u1EE3i {1} +uniqueItems = ch\u1EC9 \u0111\u01B0\u1EE3c có các m\u1EE5c duy nh\u1EA5t trong m\u1EA3ng +writeOnly = là tr\u01B0\u1EDDng ch\u1EC9 ghi, không xu\u1EA5t hi\u1EC7n trong d\u1EEF li\u1EC7u +contentEncoding = không kh\u1EDBp v\u1EDBi mã hóa n\u1ED9i dung {0} +contentMediaType = không ph\u1EA3i là n\u1ED9i dung c\u1EE7a tôi diff --git a/src/main/resources/jsv-messages_zh_CN.properties b/src/main/resources/jsv-messages_zh_CN.properties index d5d7d45be..be6defbbe 100644 --- a/src/main/resources/jsv-messages_zh_CN.properties +++ b/src/main/resources/jsv-messages_zh_CN.properties @@ -1,70 +1,70 @@ -$ref = {0}: \u201Crefs\u201D\u6709\u9519\u8BEF -additionalItems = {0}: \u7D22\u5F15\u201C{1}\u201D\u672A\u5728\u67B6\u6784\u4E2D\u5B9A\u4E49\uFF0C\u5E76\u4E14\u8BE5\u67B6\u6784\u4E0D\u5141\u8BB8\u9644\u52A0\u9879\u76EE -additionalProperties = {0}: \u67B6\u6784\u4E2D\u672A\u5B9A\u4E49\u5C5E\u6027\u201C{1}\u201D\uFF0C\u5E76\u4E14\u67B6\u6784\u4E0D\u5141\u8BB8\u9644\u52A0\u5C5E\u6027 -allOf = {0}: \u5FC5\u987B\u5BF9\u6240\u6709\u67B6\u6784 {1} \u6709\u6548 -anyOf = {0}: \u5FC5\u987B\u5BF9\u4EFB\u4F55\u67B6\u6784 {1} \u6709\u6548 -const = {0}: \u5FC5\u987B\u662F\u5E38\u91CF\u503C\u201C{1}\u201D -contains = {0}: \u4E0D\u5305\u542B\u901A\u8FC7\u8FD9\u4E9B\u9A8C\u8BC1\u7684\u5143\u7D20: {2} -contains.max = {0}: \u5FC5\u987B\u5305\u542B\u6700\u591A {1} \u4E2A\u901A\u8FC7\u4EE5\u4E0B\u9A8C\u8BC1\u7684\u5143\u7D20: {2} -contains.min = {0}: \u5FC5\u987B\u5305\u542B\u81F3\u5C11 {1} \u4E2A\u901A\u8FC7\u8FD9\u4E9B\u9A8C\u8BC1\u7684\u5143\u7D20: {2} -dependencies = {0}: \u4F9D\u8D56\u9879 {1} \u5B58\u5728\u9519\u8BEF -dependentRequired = {0}: \u7F3A\u5C11\u5C5E\u6027\u201C{1}\u201D\uFF0C\u8BE5\u5C5E\u6027\u662F\u4F9D\u8D56\u5FC5\u9700\u7684\uFF0C\u56E0\u4E3A\u5B58\u5728\u201C{2}\u201D -dependentSchemas = {0}: dependentSchemas {1} \u5B58\u5728\u9519\u8BEF -enum = {0}: \u679A\u4E3E {1} \u4E2D\u6CA1\u6709\u503C -exclusiveMaximum = {0}: \u5FC5\u987B\u5177\u6709\u72EC\u5360\u6700\u5927\u503C {1} -exclusiveMinimum = {0}: \u5FC5\u987B\u5177\u6709\u72EC\u5360\u6700\u5C0F\u503C {1} -false = {0}: \u201C{1}\u201D\u7684\u67B6\u6784\u4E3A false -format = {0}: \u4E0E {1} \u6A21\u5F0F {2} \u4E0D\u5339\u914D -format.date = {0}: \u4E0E {1} \u6A21\u5F0F\u4E0D\u5339\u914D\uFF0C\u5FC5\u987B\u662F\u6709\u6548\u7684 RFC 3339 \u5B8C\u6574\u65E5\u671F -format.date-time = {0}: \u4E0E {1} \u6A21\u5F0F\u4E0D\u5339\u914D\u5FC5\u987B\u662F\u6709\u6548\u7684 RFC 3339 \u65E5\u671F\u65F6\u95F4 -format.duration = {0}: \u4E0E {1} \u6A21\u5F0F\u4E0D\u5339\u914D\u5FC5\u987B\u662F\u6709\u6548\u7684 ISO 8601 \u6301\u7EED\u65F6\u95F4 -format.email = {0}: \u4E0E {1} \u6A21\u5F0F\u4E0D\u5339\u914D\u5FC5\u987B\u662F\u6709\u6548\u7684 RFC 5321 \u90AE\u7BB1 -format.ipv4 = {0}: \u4E0E {1} \u6A21\u5F0F\u4E0D\u5339\u914D\u5FC5\u987B\u662F\u6709\u6548\u7684 RFC 2673 IP \u5730\u5740 -format.ipv6 = {0}: \u4E0E {1} \u6A21\u5F0F\u4E0D\u5339\u914D\u5FC5\u987B\u662F\u6709\u6548\u7684 RFC 4291 IP \u5730\u5740 -format.idn-email = {0}: \u4E0E {1} \u6A21\u5F0F\u4E0D\u5339\u914D\u5FC5\u987B\u662F\u6709\u6548\u7684 RFC 6531 \u90AE\u7BB1 -format.idn-hostname = {0}: \u4E0E {1} \u6A21\u5F0F\u4E0D\u5339\u914D\u5FC5\u987B\u662F\u6709\u6548\u7684 RFC 5890 \u56FD\u9645\u5316\u4E3B\u673A\u540D -format.iri = {0}: \u4E0E {1} \u6A21\u5F0F\u4E0D\u5339\u914D\u5FC5\u987B\u662F\u6709\u6548\u7684 RFC 3987 IRI -format.iri-reference = {0}: \u4E0E {1} \u6A21\u5F0F\u4E0D\u5339\u914D\u5FC5\u987B\u662F\u6709\u6548\u7684 RFC 3987 IRI-reference -format.uri = {0}: \u4E0E {1} \u6A21\u5F0F\u4E0D\u5339\u914D\u5FC5\u987B\u662F\u6709\u6548\u7684 RFC 3986 URI -format.uri-reference = {0}: \u4E0E {1} \u6A21\u5F0F\u4E0D\u5339\u914D\u5FC5\u987B\u662F\u6709\u6548\u7684 RFC 3986 URI \u5F15\u7528 -format.uri-template = {0}: \u4E0E {1} \u6A21\u5F0F\u4E0D\u5339\u914D\u5FC5\u987B\u662F\u6709\u6548\u7684 RFC 6570 URI \u6A21\u677F -format.uuid = {0}: \u4E0E {1} \u6A21\u5F0F\u4E0D\u5339\u914D\u5FC5\u987B\u662F\u6709\u6548\u7684 RFC 4122 UUID -format.regex = {0}: \u4E0D\u5339\u914D {1} \u6A21\u5F0F\u5FC5\u987B\u662F\u6709\u6548\u7684 ECMA-262 \u6B63\u5219\u8868\u8FBE\u5F0F -format.time = {0}: \u4E0E {1} \u6A21\u5F0F\u4E0D\u5339\u914D\uFF0C\u5FC5\u987B\u662F\u6709\u6548\u7684 RFC 3339 \u65F6\u95F4 -format.hostname = {0}: \u4E0E {1} \u6A21\u5F0F\u4E0D\u5339\u914D\uFF0C\u5FC5\u987B\u662F\u6709\u6548\u7684 RFC 1123 \u4E3B\u673A\u540D -format.json-pointer = {0}: \u4E0E {1} \u6A21\u5F0F\u4E0D\u5339\u914D\u5FC5\u987B\u662F\u6709\u6548\u7684 RFC 6901 JSON \u6307\u9488 -format.relative-json-pointer = {0}: \u4E0E {1} \u6A21\u5F0F\u4E0D\u5339\u914D\u5FC5\u987B\u662F\u6709\u6548\u7684 IETF \u76F8\u5BF9 JSON \u6307\u9488 -format.unknown = {0}: \u683C\u5F0F\u672A\u77E5\u201C{1}\u201D -id = {0}: \u201C{1}\u201D\u4E0D\u662F\u6709\u6548\u7684 {2} -items = {0}: \u7D22\u5F15\u201C{1}\u201D\u672A\u5728\u67B6\u6784\u4E2D\u5B9A\u4E49\uFF0C\u5E76\u4E14\u8BE5\u67B6\u6784\u4E0D\u5141\u8BB8\u6DFB\u52A0\u5176\u4ED6\u9879\u76EE -maxContains = {0}: \u5FC5\u987B\u662F {1} \u4E2D\u7684\u975E\u8D1F\u6574\u6570 -maxItems = {0}: \u6700\u591A\u5FC5\u987B\u6709 {1} \u4E2A\u9879\u76EE\uFF0C\u4F46\u627E\u5230\u4E86 {2} \u4E2A -maxLength = {0}: \u957F\u5EA6\u4E0D\u5F97\u8D85\u8FC7 {1} \u4E2A\u5B57\u7B26 -maxProperties = {0}: \u6700\u591A\u5FC5\u987B\u6709 {1} \u4E2A\u5C5E\u6027 -maximum = {0}: \u6700\u5927\u503C\u5FC5\u987B\u4E3A {1} -minContains = {0}: \u5FC5\u987B\u662F {1} \u4E2D\u7684\u975E\u8D1F\u6574\u6570 -minContainsVsMaxContains = {0}: minContains \u5FC5\u987B\u5C0F\u4E8E\u6216\u7B49\u4E8E {1} \u4E2D\u7684 maxContains -minItems = {0}: \u5FC5\u987B\u81F3\u5C11\u6709 {1} \u4E2A\u9879\u76EE\uFF0C\u4F46\u5DF2\u627E\u5230 {2} \u4E2A -minLength = {0}: \u957F\u5EA6\u5FC5\u987B\u81F3\u5C11\u4E3A {1} \u4E2A\u5B57\u7B26 -minProperties = {0}: \u5FC5\u987B\u81F3\u5C11\u5177\u6709 {1} \u4E2A\u5C5E\u6027 -minimum = {0}: \u6700\u5C0F\u503C\u5FC5\u987B\u4E3A {1} -multipleOf = {0}: \u5FC5\u987B\u662F {1} \u7684\u500D\u6570 -not = {0}: \u5BF9\u4E8E\u67B6\u6784 {1} \u5FC5\u987B\u65E0\u6548 -notAllowed = {0}: \u4E0D\u5141\u8BB8\u4F7F\u7528\u5C5E\u6027\u201C{1}\u201D\uFF0C\u4F46\u5B83\u5B58\u5728\u4E8E\u6570\u636E\u4E2D -oneOf = {0}: \u5FC5\u987B\u5BF9\u4E00\u4E2A\u4E14\u4EC5\u4E00\u4E2A\u67B6\u6784\u6709\u6548\uFF0C\u4F46 {1} \u6709\u6548 -oneOf.indexes = {0}: \u5FC5\u987B\u5BF9\u4E00\u4E2A\u4E14\u4EC5\u4E00\u4E2A\u67B6\u6784\u6709\u6548\uFF0C\u4F46 {1} \u5BF9\u7D22\u5F15\u201C{2}\u201D\u6709\u6548 -pattern = {0}: \u4E0E\u6B63\u5219\u8868\u8FBE\u5F0F\u6A21\u5F0F {1} \u4E0D\u5339\u914D -patternProperties = {0}: \u201C\u6A21\u5F0F\u5C5E\u6027\u201D\u6709\u4E00\u4E9B\u9519\u8BEF -prefixItems = {0}: \u5728\u6B64\u7D22\u5F15\u5904\u627E\u4E0D\u5230\u9A8C\u8BC1\u5668 -properties = {0}: \u201C\u5C5E\u6027\u201D\u6709\u9519\u8BEF -propertyNames = {0}: \u5C5E\u6027\u201C{1}\u201D\u540D\u79F0\u65E0\u6548: {2} -readOnly = {0}: \u662F\u53EA\u8BFB\u5B57\u6BB5\uFF0C\u65E0\u6CD5\u66F4\u6539 -required = {0}: \u672A\u627E\u5230\u6240\u9700\u5C5E\u6027\u201C{1}\u201D -type = {0}: \u5DF2\u627E\u5230 {1}\uFF0C\u5FC5\u987B\u662F {2} -unevaluatedItems = {0}: \u672A\u8BC4\u4F30\u7D22\u5F15\u201C{1}\u201D\uFF0C\u67B6\u6784\u4E0D\u5141\u8BB8\u672A\u8BC4\u4F30\u7684\u9879\u76EE -unevaluatedProperties = {0}: \u672A\u8BC4\u4F30\u5C5E\u6027\u201C{1}\u201D\uFF0C\u5E76\u4E14\u67B6\u6784\u4E0D\u5141\u8BB8\u672A\u8BC4\u4F30\u7684\u5C5E\u6027 -unionType = {0}: \u5DF2\u627E\u5230 {1}\uFF0C\u5FC5\u987B\u662F {2} -uniqueItems = {0}: \u6570\u7EC4\u4E2D\u5FC5\u987B\u4EC5\u5305\u542B\u552F\u4E00\u9879 -writeOnly = {0}: \u662F\u53EA\u5199\u5B57\u6BB5\uFF0C\u4E0D\u80FD\u51FA\u73B0\u5728\u6570\u636E\u4E2D -contentEncoding = {0}: \u4E0E\u5185\u5BB9\u7F16\u7801 {1} \u4E0D\u5339\u914D -contentMediaType = {0}: \u4E0D\u662F\u5185\u5BB9\u6211 +$ref = \u201Crefs\u201D\u6709\u9519\u8BEF +additionalItems = \u7D22\u5F15\u201C{0}\u201D\u672A\u5728\u67B6\u6784\u4E2D\u5B9A\u4E49\uFF0C\u5E76\u4E14\u8BE5\u67B6\u6784\u4E0D\u5141\u8BB8\u9644\u52A0\u9879\u76EE +additionalProperties = \u67B6\u6784\u4E2D\u672A\u5B9A\u4E49\u5C5E\u6027\u201C{0}\u201D\uFF0C\u5E76\u4E14\u67B6\u6784\u4E0D\u5141\u8BB8\u9644\u52A0\u5C5E\u6027 +allOf = \u5FC5\u987B\u5BF9\u6240\u6709\u67B6\u6784 {0} \u6709\u6548 +anyOf = \u5FC5\u987B\u5BF9\u4EFB\u4F55\u67B6\u6784 {0} \u6709\u6548 +const = \u5FC5\u987B\u662F\u5E38\u91CF\u503C\u201C{0}\u201D +contains = \u4E0D\u5305\u542B\u901A\u8FC7\u8FD9\u4E9B\u9A8C\u8BC1\u7684\u5143\u7D20: {1} +contains.max = \u5FC5\u987B\u5305\u542B\u6700\u591A {0} \u4E2A\u901A\u8FC7\u4EE5\u4E0B\u9A8C\u8BC1\u7684\u5143\u7D20: {1} +contains.min = \u5FC5\u987B\u5305\u542B\u81F3\u5C11 {0} \u4E2A\u901A\u8FC7\u8FD9\u4E9B\u9A8C\u8BC1\u7684\u5143\u7D20: {1} +dependencies = \u4F9D\u8D56\u9879 {0} \u5B58\u5728\u9519\u8BEF +dependentRequired = \u7F3A\u5C11\u5C5E\u6027\u201C{0}\u201D\uFF0C\u8BE5\u5C5E\u6027\u662F\u4F9D\u8D56\u5FC5\u9700\u7684\uFF0C\u56E0\u4E3A\u5B58\u5728\u201C{1}\u201D +dependentSchemas = dependentSchemas {0} \u5B58\u5728\u9519\u8BEF +enum = \u679A\u4E3E {0} \u4E2D\u6CA1\u6709\u503C +exclusiveMaximum = \u5FC5\u987B\u5177\u6709\u72EC\u5360\u6700\u5927\u503C {0} +exclusiveMinimum = \u5FC5\u987B\u5177\u6709\u72EC\u5360\u6700\u5C0F\u503C {0} +false = \u201C{0}\u201D\u7684\u67B6\u6784\u4E3A false +format = \u4E0E {0} \u6A21\u5F0F \u4E0D\u5339\u914D +format.date = \u4E0E {0} \u6A21\u5F0F\u4E0D\u5339\u914D\uFF0C\u5FC5\u987B\u662F\u6709\u6548\u7684 RFC 3339 \u5B8C\u6574\u65E5\u671F +format.date-time = \u4E0E {0} \u6A21\u5F0F\u4E0D\u5339\u914D\u5FC5\u987B\u662F\u6709\u6548\u7684 RFC 3339 \u65E5\u671F\u65F6\u95F4 +format.duration = \u4E0E {0} \u6A21\u5F0F\u4E0D\u5339\u914D\u5FC5\u987B\u662F\u6709\u6548\u7684 ISO 8601 \u6301\u7EED\u65F6\u95F4 +format.email = \u4E0E {0} \u6A21\u5F0F\u4E0D\u5339\u914D\u5FC5\u987B\u662F\u6709\u6548\u7684 RFC 5321 \u90AE\u7BB1 +format.ipv4 = \u4E0E {0} \u6A21\u5F0F\u4E0D\u5339\u914D\u5FC5\u987B\u662F\u6709\u6548\u7684 RFC 2673 IP \u5730\u5740 +format.ipv6 = \u4E0E {0} \u6A21\u5F0F\u4E0D\u5339\u914D\u5FC5\u987B\u662F\u6709\u6548\u7684 RFC 4291 IP \u5730\u5740 +format.idn-email = \u4E0E {0} \u6A21\u5F0F\u4E0D\u5339\u914D\u5FC5\u987B\u662F\u6709\u6548\u7684 RFC 6531 \u90AE\u7BB1 +format.idn-hostname = \u4E0E {0} \u6A21\u5F0F\u4E0D\u5339\u914D\u5FC5\u987B\u662F\u6709\u6548\u7684 RFC 5890 \u56FD\u9645\u5316\u4E3B\u673A\u540D +format.iri = \u4E0E {0} \u6A21\u5F0F\u4E0D\u5339\u914D\u5FC5\u987B\u662F\u6709\u6548\u7684 RFC 3987 IRI +format.iri-reference = \u4E0E {0} \u6A21\u5F0F\u4E0D\u5339\u914D\u5FC5\u987B\u662F\u6709\u6548\u7684 RFC 3987 IRI-reference +format.uri = \u4E0E {0} \u6A21\u5F0F\u4E0D\u5339\u914D\u5FC5\u987B\u662F\u6709\u6548\u7684 RFC 3986 URI +format.uri-reference = \u4E0E {0} \u6A21\u5F0F\u4E0D\u5339\u914D\u5FC5\u987B\u662F\u6709\u6548\u7684 RFC 3986 URI \u5F15\u7528 +format.uri-template = \u4E0E {0} \u6A21\u5F0F\u4E0D\u5339\u914D\u5FC5\u987B\u662F\u6709\u6548\u7684 RFC 6570 URI \u6A21\u677F +format.uuid = \u4E0E {0} \u6A21\u5F0F\u4E0D\u5339\u914D\u5FC5\u987B\u662F\u6709\u6548\u7684 RFC 4122 UUID +format.regex = \u4E0D\u5339\u914D {0} \u6A21\u5F0F\u5FC5\u987B\u662F\u6709\u6548\u7684 ECMA-262 \u6B63\u5219\u8868\u8FBE\u5F0F +format.time = \u4E0E {0} \u6A21\u5F0F\u4E0D\u5339\u914D\uFF0C\u5FC5\u987B\u662F\u6709\u6548\u7684 RFC 3339 \u65F6\u95F4 +format.hostname = \u4E0E {0} \u6A21\u5F0F\u4E0D\u5339\u914D\uFF0C\u5FC5\u987B\u662F\u6709\u6548\u7684 RFC 1123 \u4E3B\u673A\u540D +format.json-pointer = \u4E0E {0} \u6A21\u5F0F\u4E0D\u5339\u914D\u5FC5\u987B\u662F\u6709\u6548\u7684 RFC 6901 JSON \u6307\u9488 +format.relative-json-pointer = \u4E0E {0} \u6A21\u5F0F\u4E0D\u5339\u914D\u5FC5\u987B\u662F\u6709\u6548\u7684 IETF \u76F8\u5BF9 JSON \u6307\u9488 +format.unknown = \u683C\u5F0F\u672A\u77E5\u201C{0}\u201D +id = \u201C{0}\u201D\u4E0D\u662F\u6709\u6548\u7684 {1} +items = \u7D22\u5F15\u201C{0}\u201D\u672A\u5728\u67B6\u6784\u4E2D\u5B9A\u4E49\uFF0C\u5E76\u4E14\u8BE5\u67B6\u6784\u4E0D\u5141\u8BB8\u6DFB\u52A0\u5176\u4ED6\u9879\u76EE +maxContains = \u5FC5\u987B\u662F {0} \u4E2D\u7684\u975E\u8D1F\u6574\u6570 +maxItems = \u6700\u591A\u5FC5\u987B\u6709 {0} \u4E2A\u9879\u76EE\uFF0C\u4F46\u627E\u5230\u4E86 {1} \u4E2A +maxLength = \u957F\u5EA6\u4E0D\u5F97\u8D85\u8FC7 {0} \u4E2A\u5B57\u7B26 +maxProperties = \u6700\u591A\u5FC5\u987B\u6709 {0} \u4E2A\u5C5E\u6027 +maximum = \u6700\u5927\u503C\u5FC5\u987B\u4E3A {0} +minContains = \u5FC5\u987B\u662F {0} \u4E2D\u7684\u975E\u8D1F\u6574\u6570 +minContainsVsMaxContains = minContains \u5FC5\u987B\u5C0F\u4E8E\u6216\u7B49\u4E8E {0} \u4E2D\u7684 maxContains +minItems = \u5FC5\u987B\u81F3\u5C11\u6709 {0} \u4E2A\u9879\u76EE\uFF0C\u4F46\u5DF2\u627E\u5230 {1} \u4E2A +minLength = \u957F\u5EA6\u5FC5\u987B\u81F3\u5C11\u4E3A {0} \u4E2A\u5B57\u7B26 +minProperties = \u5FC5\u987B\u81F3\u5C11\u5177\u6709 {0} \u4E2A\u5C5E\u6027 +minimum = \u6700\u5C0F\u503C\u5FC5\u987B\u4E3A {0} +multipleOf = \u5FC5\u987B\u662F {0} \u7684\u500D\u6570 +not = \u5BF9\u4E8E\u67B6\u6784 {0} \u5FC5\u987B\u65E0\u6548 +notAllowed = \u4E0D\u5141\u8BB8\u4F7F\u7528\u5C5E\u6027\u201C{0}\u201D\uFF0C\u4F46\u5B83\u5B58\u5728\u4E8E\u6570\u636E\u4E2D +oneOf = \u5FC5\u987B\u5BF9\u4E00\u4E2A\u4E14\u4EC5\u4E00\u4E2A\u67B6\u6784\u6709\u6548\uFF0C\u4F46 {0} \u6709\u6548 +oneOf.indexes = \u5FC5\u987B\u5BF9\u4E00\u4E2A\u4E14\u4EC5\u4E00\u4E2A\u67B6\u6784\u6709\u6548\uFF0C\u4F46 {0} \u5BF9\u7D22\u5F15\u201C{1}\u201D\u6709\u6548 +pattern = \u4E0E\u6B63\u5219\u8868\u8FBE\u5F0F\u6A21\u5F0F {0} \u4E0D\u5339\u914D +patternProperties = \u201C\u6A21\u5F0F\u5C5E\u6027\u201D\u6709\u4E00\u4E9B\u9519\u8BEF +prefixItems = \u5728\u6B64\u7D22\u5F15\u5904\u627E\u4E0D\u5230\u9A8C\u8BC1\u5668 +properties = \u201C\u5C5E\u6027\u201D\u6709\u9519\u8BEF +propertyNames = \u5C5E\u6027\u201C{0}\u201D\u540D\u79F0\u65E0\u6548: {1} +readOnly = \u662F\u53EA\u8BFB\u5B57\u6BB5\uFF0C\u65E0\u6CD5\u66F4\u6539 +required = \u672A\u627E\u5230\u6240\u9700\u5C5E\u6027\u201C{0}\u201D +type = \u5DF2\u627E\u5230 {0}\uFF0C\u5FC5\u987B\u662F {1} +unevaluatedItems = \u672A\u8BC4\u4F30\u7D22\u5F15\u201C{0}\u201D\uFF0C\u67B6\u6784\u4E0D\u5141\u8BB8\u672A\u8BC4\u4F30\u7684\u9879\u76EE +unevaluatedProperties = \u672A\u8BC4\u4F30\u5C5E\u6027\u201C{0}\u201D\uFF0C\u5E76\u4E14\u67B6\u6784\u4E0D\u5141\u8BB8\u672A\u8BC4\u4F30\u7684\u5C5E\u6027 +unionType = \u5DF2\u627E\u5230 {0}\uFF0C\u5FC5\u987B\u662F {1} +uniqueItems = \u6570\u7EC4\u4E2D\u5FC5\u987B\u4EC5\u5305\u542B\u552F\u4E00\u9879 +writeOnly = \u662F\u53EA\u5199\u5B57\u6BB5\uFF0C\u4E0D\u80FD\u51FA\u73B0\u5728\u6570\u636E\u4E2D +contentEncoding = \u4E0E\u5185\u5BB9\u7F16\u7801 {0} \u4E0D\u5339\u914D +contentMediaType = \u4E0D\u662F\u5185\u5BB9\u6211 diff --git a/src/main/resources/jsv-messages_zh_TW.properties b/src/main/resources/jsv-messages_zh_TW.properties index c69f2670b..122306ed3 100644 --- a/src/main/resources/jsv-messages_zh_TW.properties +++ b/src/main/resources/jsv-messages_zh_TW.properties @@ -1,70 +1,70 @@ -$ref = {0}: \u300Crefs\u300D\u6709\u932F\u8AA4 -additionalItems = {0}: \u7D22\u5F15\u300C{1}\u300D\u672A\u5728\u67B6\u69CB\u4E2D\u5B9A\u7FA9\uFF0C\u4E14\u8A72\u67B6\u69CB\u4E0D\u5141\u8A31\u9644\u52A0\u9805\u76EE -additionalProperties = {0}: \u67B6\u69CB\u4E2D\u672A\u5B9A\u7FA9\u5C6C\u6027\u201C{1}\u201D\uFF0C\u4E14\u67B6\u69CB\u4E0D\u5141\u8A31\u9644\u52A0\u5C6C\u6027 -allOf = {0}: \u5FC5\u9808\u5C0D\u6240\u6709\u67B6\u69CB {1} \u6709\u6548 -anyOf = {0}: \u5FC5\u9808\u5C0D\u4EFB\u4F55\u67B6\u69CB {1} \u6709\u6548 -const = {0}: \u5FC5\u9808\u662F\u5E38\u6578\u503C\u201C{1}\u201D -contains = {0}: \u4E0D\u5305\u542B\u901A\u904E\u9019\u4E9B\u9A57\u8B49\u7684\u5143\u7D20: {2} -contains.max = {0}: \u5FC5\u9808\u5305\u542B\u6700\u591A {1} \u500B\u901A\u904E\u4EE5\u4E0B\u9A57\u8B49\u7684\u5143\u7D20: {2} -contains.min = {0}: \u5FC5\u9808\u5305\u542B\u81F3\u5C11 {1} \u500B\u901A\u904E\u9019\u4E9B\u9A57\u8B49\u7684\u5143\u7D20: {2} -dependencies = {0}: \u4F9D\u8CF4\u9805 {1} \u5B58\u5728\u932F\u8AA4 -dependentRequired = {0}: \u7F3A\u5C11\u5C6C\u6027\u201C{1}\u201D\uFF0C\u8A72\u5C6C\u6027\u662F\u4F9D\u8CF4\u5FC5\u9700\u7684\uFF0C\u56E0\u70BA\u5B58\u5728\u201C{2}\u201D -dependentSchemas = {0}: dependentSchemas {1} \u5B58\u5728\u932F\u8AA4 -enum = {0}: \u679A\u8209 {1} \u4E2D\u6C92\u6709\u503C -exclusiveMaximum = {0}: \u5FC5\u9808\u5177\u6709\u7368\u4F54\u6700\u5927\u503C {1} -exclusiveMinimum = {0}: \u5FC5\u9808\u5177\u6709\u7368\u4F54\u6700\u5C0F\u503C {1} -false = {0}: \u300C{1}\u300D\u7684\u67B6\u69CB\u70BA false -format = {0}: \u8207 {1} \u6A21\u5F0F {2} \u4E0D\u5339\u914D -format.date = {0}: \u8207 {1} \u6A21\u5F0F\u4E0D\u5339\u914D\uFF0C\u5FC5\u9808\u662F\u6709\u6548\u7684 RFC 3339 \u5B8C\u6574\u65E5\u671F -format.date-time = {0}: \u8207 {1} \u6A21\u5F0F\u4E0D\u7B26\u5FC5\u9808\u662F\u6709\u6548\u7684 RFC 3339 \u65E5\u671F\u6642\u9593 -format.duration = {0}: \u8207 {1} \u6A21\u5F0F\u4E0D\u7B26\u5FC5\u9808\u662F\u6709\u6548\u7684 ISO 8601 \u6301\u7E8C\u6642\u9593 -format.email = {0}: \u8207 {1} \u6A21\u5F0F\u4E0D\u7B26\u5FC5\u9808\u662F\u6709\u6548\u7684 RFC 5321 \u90F5\u7BB1 -format.ipv4 = {0}: \u8207 {1} \u6A21\u5F0F\u4E0D\u7B26\u5FC5\u9808\u662F\u6709\u6548\u7684 RFC 2673 IP \u4F4D\u5740 -format.ipv6 = {0}: \u8207 {1} \u6A21\u5F0F\u4E0D\u7B26\u5FC5\u9808\u662F\u6709\u6548\u7684 RFC 4291 IP \u4F4D\u5740 -format.idn-email = {0}: \u8207 {1} \u6A21\u5F0F\u4E0D\u7B26\u5FC5\u9808\u662F\u6709\u6548\u7684 RFC 6531 \u90F5\u7BB1 -format.idn-hostname = {0}: \u8207 {1} \u6A21\u5F0F\u4E0D\u7B26\u5FC5\u9808\u662F\u6709\u6548\u7684 RFC 5890 \u570B\u969B\u5316\u4E3B\u6A5F\u540D -format.iri = {0}: \u8207 {1} \u6A21\u5F0F\u4E0D\u7B26\u5FC5\u9808\u662F\u6709\u6548\u7684 RFC 3987 IRI -format.iri-reference = {0}: \u8207 {1} \u6A21\u5F0F\u4E0D\u7B26\u5FC5\u9808\u662F\u6709\u6548\u7684 RFC 3987 IRI-reference -format.uri = {0}: \u8207 {1} \u6A21\u5F0F\u4E0D\u7B26\u5FC5\u9808\u662F\u6709\u6548\u7684 RFC 3986 URI -format.uri-reference = {0}: \u8207 {1} \u6A21\u5F0F\u4E0D\u7B26\u5FC5\u9808\u662F\u6709\u6548\u7684 RFC 3986 URI \u5F15\u7528 -format.uri-template = {0}: \u8207 {1} \u6A21\u5F0F\u4E0D\u7B26\u5FC5\u9808\u662F\u6709\u6548\u7684 RFC 6570 URI \u6A21\u677F -format.uuid = {0}: \u8207 {1} \u6A21\u5F0F\u4E0D\u7B26\u5FC5\u9808\u662F\u6709\u6548\u7684 RFC 4122 UUID -format.regex = {0}: \u4E0D\u7B26\u5408 {1} \u6A21\u5F0F\u5FC5\u9808\u662F\u6709\u6548\u7684 ECMA-262 \u6B63\u898F\u8868\u793A\u5F0F -format.time = {0}: \u8207 {1} \u6A21\u5F0F\u4E0D\u5339\u914D\uFF0C\u5FC5\u9808\u662F\u6709\u6548\u7684 RFC 3339 \u6642\u9593 -format.hostname = {0}: \u8207 {1} \u6A21\u5F0F\u4E0D\u5339\u914D\uFF0C\u5FC5\u9808\u662F\u6709\u6548\u7684 RFC 1123 \u4E3B\u6A5F\u540D -format.json-pointer = {0}: \u8207 {1} \u6A21\u5F0F\u4E0D\u7B26\u5FC5\u9808\u662F\u6709\u6548\u7684 RFC 6901 JSON \u6307\u91DD -format.relative-json-pointer = {0}: \u8207 {1} \u6A21\u5F0F\u4E0D\u5339\u914D\u5FC5\u9808\u662F\u6709\u6548\u7684 IETF \u76F8\u5C0D JSON \u6307\u91DD -format.unknown = {0}: \u683C\u5F0F\u672A\u77E5\u201C{1}\u201D -id = {0}: \u300C{1}\u300D\u4E0D\u662F\u6709\u6548\u7684 {2} -items = {0}: \u7D22\u5F15\u300C{1}\u300D\u672A\u5728\u67B6\u69CB\u4E2D\u5B9A\u7FA9\uFF0C\u4E14\u8A72\u67B6\u69CB\u4E0D\u5141\u8A31\u65B0\u589E\u5176\u4ED6\u9805\u76EE -maxContains = {0}: \u5FC5\u9808\u662F {1} \u4E2D\u7684\u975E\u8CA0\u6574\u6578 -maxItems = {0}: \u6700\u591A\u5FC5\u9808\u6709 {1} \u500B\u9805\u76EE\uFF0C\u4F46\u627E\u5230\u4E86 {2} \u500B -maxLength = {0}: \u9577\u5EA6\u4E0D\u5F97\u8D85\u904E {1} \u500B\u5B57\u5143 -maxProperties = {0}: \u6700\u591A\u5FC5\u9808\u6709 {1} \u500B\u5C6C\u6027 -maximum = {0}: \u6700\u5927\u503C\u5FC5\u9808\u70BA {1} -minContains = {0}: \u5FC5\u9808\u662F {1} \u4E2D\u7684\u975E\u8CA0\u6574\u6578 -minContainsVsMaxContains = {0}: minContains \u5FC5\u9808\u5C0F\u65BC\u6216\u7B49\u65BC {1} \u4E2D\u7684 maxContains -minItems = {0}: \u5FC5\u9808\u81F3\u5C11\u6709 {1} \u500B\u9805\u76EE\uFF0C\u4F46\u5DF2\u627E\u5230 {2} \u500B -minLength = {0}: \u9577\u5EA6\u5FC5\u9808\u81F3\u5C11\u70BA {1} \u500B\u5B57\u5143 -minProperties = {0}: \u5FC5\u9808\u81F3\u5C11\u5177\u6709 {1} \u500B\u5C6C\u6027 -minimum = {0}: \u6700\u5C0F\u503C\u5FC5\u9808\u70BA {1} -multipleOf = {0}: \u5FC5\u9808\u662F {1} \u7684\u500D\u6578 -not = {0}: \u5C0D\u65BC\u67B6\u69CB {1} \u5FC5\u9808\u7121\u6548 -notAllowed = {0}: \u4E0D\u5141\u8A31\u4F7F\u7528\u5C6C\u6027\u201C{1}\u201D\uFF0C\u4F46\u5B83\u5B58\u5728\u65BC\u8CC7\u6599\u4E2D -oneOf = {0}: \u5FC5\u9808\u5C0D\u4E00\u500B\u4E14\u50C5\u4E00\u500B\u67B6\u69CB\u6709\u6548\uFF0C\u4F46 {1} \u6709\u6548 -oneOf.indexes = {0}: \u5FC5\u9808\u5C0D\u4E00\u500B\u4E14\u50C5\u4E00\u500B\u67B6\u69CB\u6709\u6548\uFF0C\u4F46 {1} \u5C0D\u7D22\u5F15\u300C{2}\u300D\u6709\u6548 -pattern = {0}: \u8207\u6B63\u898F\u8868\u793A\u5F0F\u6A21\u5F0F {1} \u4E0D\u5339\u914D -patternProperties = {0}: \u300C\u6A21\u5F0F\u5C6C\u6027\u300D\u6709\u4E00\u4E9B\u932F\u8AA4 -prefixItems = {0}: \u5728\u6B64\u7D22\u5F15\u8655\u627E\u4E0D\u5230\u9A57\u8B49\u5668 -properties = {0}: \u300C\u5C6C\u6027\u300D\u6709\u932F\u8AA4 -propertyNames = {0}: \u5C6C\u6027\u300C{1}\u300D\u540D\u7A31\u7121\u6548: {2} -readOnly = {0}: \u662F\u552F\u8B80\u5B57\u6BB5\uFF0C\u7121\u6CD5\u66F4\u6539 -required = {0}: \u672A\u627E\u5230\u6240\u9700\u5C6C\u6027\u201C{1}\u201D -type = {0}: \u5DF2\u627E\u5230 {1}\uFF0C\u5FC5\u9808\u662F {2} -unevaluatedItems = {0}: \u672A\u8A55\u4F30\u7D22\u5F15\u201C{1}\u201D\uFF0C\u67B6\u69CB\u4E0D\u5141\u8A31\u672A\u8A55\u4F30\u7684\u9805\u76EE -unevaluatedProperties = {0}: \u672A\u8A55\u4F30\u5C6C\u6027\u201C{1}\u201D\uFF0C\u4E14\u67B6\u69CB\u4E0D\u5141\u8A31\u672A\u8A55\u4F30\u7684\u5C6C\u6027 -unionType = {0}: \u5DF2\u627E\u5230 {1}\uFF0C\u5FC5\u9808\u662F {2} -uniqueItems = {0}: \u6578\u7D44\u4E2D\u5FC5\u9808\u53EA\u5305\u542B\u552F\u4E00\u9805 -writeOnly = {0}: \u662F\u53EA\u5BEB\u5B57\u6BB5\uFF0C\u4E0D\u80FD\u51FA\u73FE\u5728\u8CC7\u6599\u4E2D -contentEncoding = {0}: \u8207\u5167\u5BB9\u7DE8\u78BC {1} \u4E0D\u7B26 -contentMediaType = {0}: \u4E0D\u662F\u5167\u5BB9\u6211 +$ref = \u300Crefs\u300D\u6709\u932F\u8AA4 +additionalItems = \u7D22\u5F15\u300C{0}\u300D\u672A\u5728\u67B6\u69CB\u4E2D\u5B9A\u7FA9\uFF0C\u4E14\u8A72\u67B6\u69CB\u4E0D\u5141\u8A31\u9644\u52A0\u9805\u76EE +additionalProperties = \u67B6\u69CB\u4E2D\u672A\u5B9A\u7FA9\u5C6C\u6027\u201C{0}\u201D\uFF0C\u4E14\u67B6\u69CB\u4E0D\u5141\u8A31\u9644\u52A0\u5C6C\u6027 +allOf = \u5FC5\u9808\u5C0D\u6240\u6709\u67B6\u69CB {0} \u6709\u6548 +anyOf = \u5FC5\u9808\u5C0D\u4EFB\u4F55\u67B6\u69CB {0} \u6709\u6548 +const = \u5FC5\u9808\u662F\u5E38\u6578\u503C\u201C{0}\u201D +contains = \u4E0D\u5305\u542B\u901A\u904E\u9019\u4E9B\u9A57\u8B49\u7684\u5143\u7D20: {1} +contains.max = \u5FC5\u9808\u5305\u542B\u6700\u591A {0} \u500B\u901A\u904E\u4EE5\u4E0B\u9A57\u8B49\u7684\u5143\u7D20: {1} +contains.min = \u5FC5\u9808\u5305\u542B\u81F3\u5C11 {0} \u500B\u901A\u904E\u9019\u4E9B\u9A57\u8B49\u7684\u5143\u7D20: {1} +dependencies = \u4F9D\u8CF4\u9805 {0} \u5B58\u5728\u932F\u8AA4 +dependentRequired = \u7F3A\u5C11\u5C6C\u6027\u201C{0}\u201D\uFF0C\u8A72\u5C6C\u6027\u662F\u4F9D\u8CF4\u5FC5\u9700\u7684\uFF0C\u56E0\u70BA\u5B58\u5728\u201C{1}\u201D +dependentSchemas = dependentSchemas {0} \u5B58\u5728\u932F\u8AA4 +enum = \u679A\u8209 {0} \u4E2D\u6C92\u6709\u503C +exclusiveMaximum = \u5FC5\u9808\u5177\u6709\u7368\u4F54\u6700\u5927\u503C {0} +exclusiveMinimum = \u5FC5\u9808\u5177\u6709\u7368\u4F54\u6700\u5C0F\u503C {0} +false = \u300C{0}\u300D\u7684\u67B6\u69CB\u70BA false +format = \u8207 {0} \u6A21\u5F0F \u4E0D\u5339\u914D +format.date = \u8207 {0} \u6A21\u5F0F\u4E0D\u5339\u914D\uFF0C\u5FC5\u9808\u662F\u6709\u6548\u7684 RFC 3339 \u5B8C\u6574\u65E5\u671F +format.date-time = \u8207 {0} \u6A21\u5F0F\u4E0D\u7B26\u5FC5\u9808\u662F\u6709\u6548\u7684 RFC 3339 \u65E5\u671F\u6642\u9593 +format.duration = \u8207 {0} \u6A21\u5F0F\u4E0D\u7B26\u5FC5\u9808\u662F\u6709\u6548\u7684 ISO 8601 \u6301\u7E8C\u6642\u9593 +format.email = \u8207 {0} \u6A21\u5F0F\u4E0D\u7B26\u5FC5\u9808\u662F\u6709\u6548\u7684 RFC 5321 \u90F5\u7BB1 +format.ipv4 = \u8207 {0} \u6A21\u5F0F\u4E0D\u7B26\u5FC5\u9808\u662F\u6709\u6548\u7684 RFC 2673 IP \u4F4D\u5740 +format.ipv6 = \u8207 {0} \u6A21\u5F0F\u4E0D\u7B26\u5FC5\u9808\u662F\u6709\u6548\u7684 RFC 4291 IP \u4F4D\u5740 +format.idn-email = \u8207 {0} \u6A21\u5F0F\u4E0D\u7B26\u5FC5\u9808\u662F\u6709\u6548\u7684 RFC 6531 \u90F5\u7BB1 +format.idn-hostname = \u8207 {0} \u6A21\u5F0F\u4E0D\u7B26\u5FC5\u9808\u662F\u6709\u6548\u7684 RFC 5890 \u570B\u969B\u5316\u4E3B\u6A5F\u540D +format.iri = \u8207 {0} \u6A21\u5F0F\u4E0D\u7B26\u5FC5\u9808\u662F\u6709\u6548\u7684 RFC 3987 IRI +format.iri-reference = \u8207 {0} \u6A21\u5F0F\u4E0D\u7B26\u5FC5\u9808\u662F\u6709\u6548\u7684 RFC 3987 IRI-reference +format.uri = \u8207 {0} \u6A21\u5F0F\u4E0D\u7B26\u5FC5\u9808\u662F\u6709\u6548\u7684 RFC 3986 URI +format.uri-reference = \u8207 {0} \u6A21\u5F0F\u4E0D\u7B26\u5FC5\u9808\u662F\u6709\u6548\u7684 RFC 3986 URI \u5F15\u7528 +format.uri-template = \u8207 {0} \u6A21\u5F0F\u4E0D\u7B26\u5FC5\u9808\u662F\u6709\u6548\u7684 RFC 6570 URI \u6A21\u677F +format.uuid = \u8207 {0} \u6A21\u5F0F\u4E0D\u7B26\u5FC5\u9808\u662F\u6709\u6548\u7684 RFC 4122 UUID +format.regex = \u4E0D\u7B26\u5408 {0} \u6A21\u5F0F\u5FC5\u9808\u662F\u6709\u6548\u7684 ECMA-262 \u6B63\u898F\u8868\u793A\u5F0F +format.time = \u8207 {0} \u6A21\u5F0F\u4E0D\u5339\u914D\uFF0C\u5FC5\u9808\u662F\u6709\u6548\u7684 RFC 3339 \u6642\u9593 +format.hostname = \u8207 {0} \u6A21\u5F0F\u4E0D\u5339\u914D\uFF0C\u5FC5\u9808\u662F\u6709\u6548\u7684 RFC 1123 \u4E3B\u6A5F\u540D +format.json-pointer = \u8207 {0} \u6A21\u5F0F\u4E0D\u7B26\u5FC5\u9808\u662F\u6709\u6548\u7684 RFC 6901 JSON \u6307\u91DD +format.relative-json-pointer = \u8207 {0} \u6A21\u5F0F\u4E0D\u5339\u914D\u5FC5\u9808\u662F\u6709\u6548\u7684 IETF \u76F8\u5C0D JSON \u6307\u91DD +format.unknown = \u683C\u5F0F\u672A\u77E5\u201C{0}\u201D +id = \u300C{0}\u300D\u4E0D\u662F\u6709\u6548\u7684 {1} +items = \u7D22\u5F15\u300C{0}\u300D\u672A\u5728\u67B6\u69CB\u4E2D\u5B9A\u7FA9\uFF0C\u4E14\u8A72\u67B6\u69CB\u4E0D\u5141\u8A31\u65B0\u589E\u5176\u4ED6\u9805\u76EE +maxContains = \u5FC5\u9808\u662F {0} \u4E2D\u7684\u975E\u8CA0\u6574\u6578 +maxItems = \u6700\u591A\u5FC5\u9808\u6709 {0} \u500B\u9805\u76EE\uFF0C\u4F46\u627E\u5230\u4E86 {1} \u500B +maxLength = \u9577\u5EA6\u4E0D\u5F97\u8D85\u904E {0} \u500B\u5B57\u5143 +maxProperties = \u6700\u591A\u5FC5\u9808\u6709 {0} \u500B\u5C6C\u6027 +maximum = \u6700\u5927\u503C\u5FC5\u9808\u70BA {0} +minContains = \u5FC5\u9808\u662F {0} \u4E2D\u7684\u975E\u8CA0\u6574\u6578 +minContainsVsMaxContains = minContains \u5FC5\u9808\u5C0F\u65BC\u6216\u7B49\u65BC {0} \u4E2D\u7684 maxContains +minItems = \u5FC5\u9808\u81F3\u5C11\u6709 {0} \u500B\u9805\u76EE\uFF0C\u4F46\u5DF2\u627E\u5230 {1} \u500B +minLength = \u9577\u5EA6\u5FC5\u9808\u81F3\u5C11\u70BA {0} \u500B\u5B57\u5143 +minProperties = \u5FC5\u9808\u81F3\u5C11\u5177\u6709 {0} \u500B\u5C6C\u6027 +minimum = \u6700\u5C0F\u503C\u5FC5\u9808\u70BA {0} +multipleOf = \u5FC5\u9808\u662F {0} \u7684\u500D\u6578 +not = \u5C0D\u65BC\u67B6\u69CB {0} \u5FC5\u9808\u7121\u6548 +notAllowed = \u4E0D\u5141\u8A31\u4F7F\u7528\u5C6C\u6027\u201C{0}\u201D\uFF0C\u4F46\u5B83\u5B58\u5728\u65BC\u8CC7\u6599\u4E2D +oneOf = \u5FC5\u9808\u5C0D\u4E00\u500B\u4E14\u50C5\u4E00\u500B\u67B6\u69CB\u6709\u6548\uFF0C\u4F46 {0} \u6709\u6548 +oneOf.indexes = \u5FC5\u9808\u5C0D\u4E00\u500B\u4E14\u50C5\u4E00\u500B\u67B6\u69CB\u6709\u6548\uFF0C\u4F46 {0} \u5C0D\u7D22\u5F15\u300C{1}\u300D\u6709\u6548 +pattern = \u8207\u6B63\u898F\u8868\u793A\u5F0F\u6A21\u5F0F {0} \u4E0D\u5339\u914D +patternProperties = \u300C\u6A21\u5F0F\u5C6C\u6027\u300D\u6709\u4E00\u4E9B\u932F\u8AA4 +prefixItems = \u5728\u6B64\u7D22\u5F15\u8655\u627E\u4E0D\u5230\u9A57\u8B49\u5668 +properties = \u300C\u5C6C\u6027\u300D\u6709\u932F\u8AA4 +propertyNames = \u5C6C\u6027\u300C{0}\u300D\u540D\u7A31\u7121\u6548: {1} +readOnly = \u662F\u552F\u8B80\u5B57\u6BB5\uFF0C\u7121\u6CD5\u66F4\u6539 +required = \u672A\u627E\u5230\u6240\u9700\u5C6C\u6027\u201C{0}\u201D +type = \u5DF2\u627E\u5230 {0}\uFF0C\u5FC5\u9808\u662F {1} +unevaluatedItems = \u672A\u8A55\u4F30\u7D22\u5F15\u201C{0}\u201D\uFF0C\u67B6\u69CB\u4E0D\u5141\u8A31\u672A\u8A55\u4F30\u7684\u9805\u76EE +unevaluatedProperties = \u672A\u8A55\u4F30\u5C6C\u6027\u201C{0}\u201D\uFF0C\u4E14\u67B6\u69CB\u4E0D\u5141\u8A31\u672A\u8A55\u4F30\u7684\u5C6C\u6027 +unionType = \u5DF2\u627E\u5230 {0}\uFF0C\u5FC5\u9808\u662F {1} +uniqueItems = \u6578\u7D44\u4E2D\u5FC5\u9808\u53EA\u5305\u542B\u552F\u4E00\u9805 +writeOnly = \u662F\u53EA\u5BEB\u5B57\u6BB5\uFF0C\u4E0D\u80FD\u51FA\u73FE\u5728\u8CC7\u6599\u4E2D +contentEncoding = \u8207\u5167\u5BB9\u7DE8\u78BC {0} \u4E0D\u7B26 +contentMediaType = \u4E0D\u662F\u5167\u5BB9\u6211 diff --git a/src/test/java/com/networknt/schema/AbstractJsonSchemaTest.java b/src/test/java/com/networknt/schema/AbstractJsonSchemaTest.java index aab62c27c..2c1a92e96 100644 --- a/src/test/java/com/networknt/schema/AbstractJsonSchemaTest.java +++ b/src/test/java/com/networknt/schema/AbstractJsonSchemaTest.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import com.networknt.schema.keyword.KeywordType; import com.networknt.schema.serialization.JsonMapperFactory; import java.io.IOException; @@ -21,29 +22,25 @@ abstract class AbstractJsonSchemaTest { private static final String SCHEMA = "$schema"; - private static final SpecVersion.VersionFlag DEFAULT_VERSION_FLAG = SpecVersion.VersionFlag.V202012; - private static final String ASSERT_MSG_ERROR_CODE = "Validation result should contain {0} error code"; - private static final String ASSERT_MSG_TYPE = "Validation result should contain {0} type"; + private static final SpecificationVersion DEFAULT_VERSION_FLAG = SpecificationVersion.DRAFT_2020_12; + private static final String ASSERT_MSG_KEYWORD = "Validation result should contain {0} keyword"; - protected List validate(String dataPath) { + protected List validate(String dataPath) { JsonNode dataNode = getJsonNodeFromPath(dataPath); return getJsonSchemaFromDataNode(dataNode).validate(dataNode); } - protected void assertValidatorType(String filename, ValidatorTypeCode validatorTypeCode) { - List validationMessages = validate(getDataTestFolder() + filename); + protected void assertValidatorType(String filename, KeywordType validatorTypeCode) { + List errors = validate(getDataTestFolder() + filename); assertTrue( - validationMessages.stream().anyMatch(vm -> validatorTypeCode.getErrorCode().equals(vm.getCode())), - () -> MessageFormat.format(ASSERT_MSG_ERROR_CODE, validatorTypeCode.getErrorCode())); - assertTrue( - validationMessages.stream().anyMatch(vm -> validatorTypeCode.getValue().equals(vm.getType())), - () -> MessageFormat.format(ASSERT_MSG_TYPE, validatorTypeCode.getValue())); + errors.stream().anyMatch(vm -> validatorTypeCode.getValue().equals(vm.getKeyword())), + () -> MessageFormat.format(ASSERT_MSG_KEYWORD, validatorTypeCode.getValue())); } protected abstract String getDataTestFolder(); - private JsonSchema getJsonSchemaFromDataNode(JsonNode dataNode) { + private Schema getJsonSchemaFromDataNode(JsonNode dataNode) { return Optional.ofNullable(dataNode.get(SCHEMA)) .map(JsonNode::textValue) .map(this::getJsonNodeFromPath) @@ -61,9 +58,9 @@ private JsonNode getJsonNodeFromPath(String dataPath) { } } - private JsonSchema getJsonSchema(JsonNode schemaNode) { - return JsonSchemaFactory - .getInstance(SpecVersionDetector.detectOptionalVersion(schemaNode, false).orElse(DEFAULT_VERSION_FLAG)) + private Schema getJsonSchema(JsonNode schemaNode) { + return SchemaRegistry + .withDefaultDialect(SpecificationVersionDetector.detectOptionalVersion(schemaNode, false).orElse(DEFAULT_VERSION_FLAG)) .getSchema(schemaNode); } diff --git a/src/test/java/com/networknt/schema/AbstractJsonSchemaTestSuite.java b/src/test/java/com/networknt/schema/AbstractJsonSchemaTestSuite.java index 7b98ef3d1..9bb76ed27 100644 --- a/src/test/java/com/networknt/schema/AbstractJsonSchemaTestSuite.java +++ b/src/test/java/com/networknt/schema/AbstractJsonSchemaTestSuite.java @@ -16,11 +16,10 @@ package com.networknt.schema; -import com.networknt.schema.SpecVersion.VersionFlag; import com.networknt.schema.regex.JDKRegularExpressionFactory; import com.networknt.schema.regex.JoniRegularExpressionFactory; import com.networknt.schema.resource.InputStreamSource; -import com.networknt.schema.resource.SchemaLoader; +import com.networknt.schema.resource.ResourceLoader; import com.networknt.schema.suite.TestCase; import com.networknt.schema.suite.TestSource; import com.networknt.schema.suite.TestSpec; @@ -43,7 +42,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import static com.networknt.schema.SpecVersionDetector.detectVersion; +import static com.networknt.schema.SpecificationVersionDetector.detectVersion; import static org.junit.jupiter.api.Assumptions.abort; import static org.junit.jupiter.api.DynamicContainer.dynamicContainer; import static org.junit.jupiter.api.DynamicTest.dynamicTest; @@ -54,11 +53,21 @@ private static String toForwardSlashPath(Path file) { return file.toString().replace('\\', '/'); } - private static void executeTest(JsonSchema schema, TestSpec testSpec) { - List errors = schema.validate(testSpec.getData(), OutputFormat.DEFAULT, (executionContext, validationContext) -> { - if (testSpec.getTestCase().getSource().getPath().getParent().toString().endsWith("format")) { - executionContext.getExecutionConfig().setFormatAssertionsEnabled(true); - } + private static void executeTest(Schema schema, TestSpec testSpec) { + List errors = schema.validate(testSpec.getData(), OutputFormat.DEFAULT, (executionContext, schemaContext) -> { + executionContext.executionConfig(executionConfig -> { + if (testSpec.getConfig() != null) { + if (testSpec.getConfig().containsKey("readOnly")) { + executionConfig.readOnly((Boolean) testSpec.getConfig().get("readOnly")); + } + if (testSpec.getConfig().containsKey("writeOnly")) { + executionConfig.writeOnly((Boolean) testSpec.getConfig().get("writeOnly")); + } + } + if (testSpec.getTestCase().getSource().getPath().getParent().toString().endsWith("format")) { + executionConfig.formatAssertionsEnabled(true); + } + }); }); if (testSpec.isValid()) { @@ -74,7 +83,7 @@ private static void executeTest(JsonSchema schema, TestSpec testSpec) { AssertionFailedError t = AssertionFailureBuilder.assertionFailure() .message(msg) - .reason(errors.stream().map(ValidationMessage::getMessage).collect(Collectors.joining("\n ", "\n errors:\n ", ""))) + .reason(errors.stream().map(Error::getMessage).collect(Collectors.joining("\n ", "\n errors:\n ", ""))) .build(); t.setStackTrace(new StackTraceElement[0]); throw t; @@ -100,8 +109,10 @@ private static void executeTest(JsonSchema schema, TestSpec testSpec) { // Expected Validation Messages need not be exactly same as actual errors. // This code checks if expected validation message is subset of actual errors - Set actual = errors.stream().map(ValidationMessage::getMessage).collect(Collectors.toSet()); - Set expected = testSpec.getValidationMessages(); + Set actual = errors.stream() + .map(error -> error.getInstanceLocation().toString() + ": " + error.getMessage()) + .collect(Collectors.toSet()); + Set expected = testSpec.getErrors(); expected.removeAll(actual); if (!expected.isEmpty()) { String msg = new StringBuilder("Expected Validation Messages") @@ -137,7 +148,7 @@ private static Iterable unsupportedMetaSchema(TestCase te ); } - protected Stream createTests(VersionFlag defaultVersion, String basePath) { + protected Stream createTests(SpecificationVersion defaultVersion, String basePath) { return findTestCases(basePath) .stream() .peek(System.out::println) @@ -152,7 +163,7 @@ protected Optional reason(@SuppressWarnings("unused") Path path) { return Optional.empty(); } - private Stream buildContainers(VersionFlag defaultVersion, Path path) { + private Stream buildContainers(SpecificationVersion defaultVersion, Path path) { boolean disabled = !enabled(path); String reason = reason(path).orElse("Unknown"); return TestSource.loadFrom(path, disabled, reason) @@ -160,18 +171,35 @@ private Stream buildContainers(VersionFlag defaultVersion, Path pat .orElse(Stream.empty()); } - private Stream buildContainer(VersionFlag defaultVersion, TestSource testSource) { + private Stream buildContainer(SpecificationVersion defaultVersion, TestSource testSource) { return testSource.getTestCases().stream().map(testCase -> buildContainer(defaultVersion, testCase)); } - private DynamicNode buildContainer(VersionFlag defaultVersion, TestCase testCase) { + private DynamicNode buildContainer(SpecificationVersion defaultVersion, TestCase testCase) { try { - JsonSchemaFactory validatorFactory = buildValidatorFactory(defaultVersion, testCase); - return dynamicContainer(testCase.getDisplayName(), testCase.getTests().stream().map(testSpec -> { - return buildTest(validatorFactory, testSpec); + // Configure the schemaValidator to set typeLoose's value based on the test file, + // if test file do not contains typeLoose flag, use default value: false. + @SuppressWarnings("deprecation") boolean typeLoose = testSpec.isTypeLoose(); + + SchemaRegistryConfig.Builder configBuilder = SchemaRegistryConfig.builder(); + configBuilder.strict("type", false); + configBuilder.typeLoose(typeLoose); + configBuilder.regularExpressionFactory( + TestSpec.RegexKind.JDK == testSpec.getRegex() ? JDKRegularExpressionFactory.getInstance() + : JoniRegularExpressionFactory.getInstance()); + testSpec.getStrictness().forEach(configBuilder::strict); + + if (testSpec.getConfig() != null) { + if (testSpec.getConfig().containsKey("isCustomMessageSupported")) { + configBuilder.errorMessageKeyword( + (Boolean) testSpec.getConfig().get("isCustomMessageSupported") ? "message" : null); + } + } + SchemaRegistry schemaRegistry = buildSchemaRegistry(defaultVersion, testCase, configBuilder.build()); + return buildTest(schemaRegistry, testSpec); })); - } catch (JsonSchemaException e) { + } catch (SchemaException e) { String msg = e.getMessage(); if (msg.endsWith("' is unrecognizable schema")) { return dynamicContainer(testCase.getDisplayName(), unsupportedMetaSchema(testCase)); @@ -180,11 +208,11 @@ private DynamicNode buildContainer(VersionFlag defaultVersion, TestCase testCase } } - private JsonSchemaFactory buildValidatorFactory(VersionFlag defaultVersion, TestCase testCase) { + private SchemaRegistry buildSchemaRegistry(SpecificationVersion defaultVersion, TestCase testCase, SchemaRegistryConfig schemaRegistryConfig) { if (testCase.isDisabled()) return null; - SchemaLoader schemaLoader = new SchemaLoader() { + ResourceLoader schemaLoader = new ResourceLoader() { @Override - public InputStreamSource getSchema(AbsoluteIri absoluteIri) { + public InputStreamSource getResource(AbsoluteIri absoluteIri) { String iri = absoluteIri.toString(); if (iri.startsWith("http://localhost:1234")) { return () -> { @@ -199,47 +227,25 @@ public InputStreamSource getSchema(AbsoluteIri absoluteIri) { return null; } }; - VersionFlag specVersion = detectVersion(testCase.getSchema(), testCase.getSpecification(), defaultVersion, false); - JsonSchemaFactory base = JsonSchemaFactory.getInstance(specVersion); - return JsonSchemaFactory + SpecificationVersion specVersion = detectVersion(testCase.getSchema(), testCase.getSpecification(), defaultVersion, false); + SchemaRegistry base = SchemaRegistry.withDefaultDialect(specVersion); + return SchemaRegistry .builder(base) - .schemaMappers(schemaMappers -> schemaMappers + .schemaIdResolvers(schemaIdResolvers -> schemaIdResolvers .mapPrefix("https://", "http://") .mapPrefix("http://json-schema.org", "resource:")) - .schemaLoaders(schemaLoaders -> schemaLoaders.add(schemaLoader)) + .resourceLoaders(resourceLoaders -> resourceLoaders.add(schemaLoader)) + .schemaRegistryConfig(schemaRegistryConfig) .build(); } - private DynamicNode buildTest(JsonSchemaFactory validatorFactory, TestSpec testSpec) { + private DynamicNode buildTest(SchemaRegistry validatorFactory, TestSpec testSpec) { if (testSpec.isDisabled()) { return dynamicTest(testSpec.getDescription(), () -> abortAndReset(testSpec.getReason())); } - // Configure the schemaValidator to set typeLoose's value based on the test file, - // if test file do not contains typeLoose flag, use default value: false. - @SuppressWarnings("deprecation") boolean typeLoose = testSpec.isTypeLoose(); - - SchemaValidatorsConfig.Builder configBuilder = SchemaValidatorsConfig.builder(); - configBuilder.typeLoose(typeLoose); - configBuilder.regularExpressionFactory( - TestSpec.RegexKind.JDK == testSpec.getRegex() ? JDKRegularExpressionFactory.getInstance() - : JoniRegularExpressionFactory.getInstance()); - testSpec.getStrictness().forEach(configBuilder::strict); - - if (testSpec.getConfig() != null) { - if (testSpec.getConfig().containsKey("isCustomMessageSupported")) { - configBuilder.errorMessageKeyword( - (Boolean) testSpec.getConfig().get("isCustomMessageSupported") ? "message" : null); - } - if (testSpec.getConfig().containsKey("readOnly")) { - configBuilder.readOnly((Boolean) testSpec.getConfig().get("readOnly")); - } - if (testSpec.getConfig().containsKey("writeOnly")) { - configBuilder.writeOnly((Boolean) testSpec.getConfig().get("writeOnly")); - } - } SchemaLocation testCaseFileUri = SchemaLocation.of("classpath:" + toForwardSlashPath(testSpec.getTestCase().getSpecification())); - JsonSchema schema = validatorFactory.getSchema(testCaseFileUri, testSpec.getTestCase().getSchema(), configBuilder.build()); + Schema schema = validatorFactory.getSchema(testCaseFileUri, testSpec.getTestCase().getSchema()); return dynamicTest(testSpec.getDescription(), () -> executeAndReset(schema, testSpec)); } @@ -252,7 +258,7 @@ private void abortAndReset(String reason) { } } - private void executeAndReset(JsonSchema schema, TestSpec testSpec) { + private void executeAndReset(Schema schema, TestSpec testSpec) { try { executeTest(schema, testSpec); } finally { diff --git a/src/test/java/com/networknt/schema/AdditionalPropertiesValidatorTest.java b/src/test/java/com/networknt/schema/AdditionalPropertiesValidatorTest.java index af20d956a..64dc4330c 100644 --- a/src/test/java/com/networknt/schema/AdditionalPropertiesValidatorTest.java +++ b/src/test/java/com/networknt/schema/AdditionalPropertiesValidatorTest.java @@ -23,8 +23,6 @@ import org.junit.jupiter.api.Test; -import com.networknt.schema.SpecVersion.VersionFlag; - /** * AdditionalPropertiesValidatorTest. */ @@ -45,22 +43,21 @@ void messageFalse() { + " },\r\n" + " \"additionalProperties\": false\r\n" + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema schema = factory.getSchema(schemaData, config); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12); + Schema schema = factory.getSchema(schemaData); String inputData = "{\r\n" + " \"foo\":\"hello\",\r\n" + " \"bar\":\"world\"\r\n" + "}"; - List messages = schema.validate(inputData, InputFormat.JSON); + List messages = schema.validate(inputData, InputFormat.JSON); assertFalse(messages.isEmpty()); - ValidationMessage message = messages.iterator().next(); + Error message = messages.iterator().next(); assertEquals("/additionalProperties", message.getEvaluationPath().toString()); assertEquals("https://www.example.org/schema#/additionalProperties", message.getSchemaLocation().toString()); assertEquals("", message.getInstanceLocation().toString()); assertEquals("false", message.getSchemaNode().toString()); assertEquals("{\"foo\":\"hello\",\"bar\":\"world\"}", message.getInstanceNode().toString()); - assertEquals(": property 'bar' is not defined in the schema and the schema does not allow additional properties", message.getMessage()); + assertEquals(": property 'bar' is not defined in the schema and the schema does not allow additional properties", message.toString()); assertEquals("bar", message.getProperty()); } @@ -80,22 +77,21 @@ void messageSchema() { + " },\r\n" + " \"additionalProperties\": { \"type\": \"number\" }\r\n" + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema schema = factory.getSchema(schemaData, config); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12); + Schema schema = factory.getSchema(schemaData); String inputData = "{\r\n" + " \"foo\":\"hello\",\r\n" + " \"bar\":\"world\"\r\n" + "}"; - List messages = schema.validate(inputData, InputFormat.JSON); + List messages = schema.validate(inputData, InputFormat.JSON); assertFalse(messages.isEmpty()); - ValidationMessage message = messages.iterator().next(); + Error message = messages.iterator().next(); assertEquals("/additionalProperties/type", message.getEvaluationPath().toString()); assertEquals("https://www.example.org/schema#/additionalProperties/type", message.getSchemaLocation().toString()); assertEquals("/bar", message.getInstanceLocation().toString()); assertEquals("\"number\"", message.getSchemaNode().toString()); assertEquals("\"world\"", message.getInstanceNode().toString()); - assertEquals("/bar: string found, number expected", message.getMessage()); + assertEquals("/bar: string found, number expected", message.toString()); assertNull(message.getProperty()); } diff --git a/src/test/java/com/networknt/schema/AllOfValidatorTest.java b/src/test/java/com/networknt/schema/AllOfValidatorTest.java index 3db78312b..9559e1ff7 100644 --- a/src/test/java/com/networknt/schema/AllOfValidatorTest.java +++ b/src/test/java/com/networknt/schema/AllOfValidatorTest.java @@ -20,11 +20,9 @@ import org.junit.jupiter.api.Test; -import com.networknt.schema.SpecVersion.VersionFlag; - class AllOfValidatorTest { @Test - void invalidTypeShouldThrowJsonSchemaException() { + void invalidTypeShouldThrowSchemaException() { String schemaData = "{\r\n" + " \"$defs\": {\r\n" + " \"User\": true\r\n" @@ -33,8 +31,8 @@ void invalidTypeShouldThrowJsonSchemaException() { + " \"$ref\": \"#/defs/User\"\r\n" + " }\r\n" + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - JsonSchemaException ex = assertThrows(JsonSchemaException.class, () -> factory.getSchema(schemaData)); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12); + SchemaException ex = assertThrows(SchemaException.class, () -> factory.getSchema(schemaData)); assertEquals("type", ex.getError().getMessageKey()); } @@ -59,9 +57,9 @@ void walkValidationWithNullNodeShouldNotValidate() { String jsonContents = "{}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7); - JsonSchema schema = factory.getSchema(schemaContents); - ValidationResult result = schema.walk(jsonContents, InputFormat.JSON, true); - assertEquals(true, result.getValidationMessages().isEmpty()); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7); + Schema schema = factory.getSchema(schemaContents); + Result result = schema.walk(jsonContents, InputFormat.JSON, true); + assertEquals(true, result.getErrors().isEmpty()); } } diff --git a/src/test/java/com/networknt/schema/JsonNodeAnnotationsTest.java b/src/test/java/com/networknt/schema/AnnotationsTest.java similarity index 65% rename from src/test/java/com/networknt/schema/JsonNodeAnnotationsTest.java rename to src/test/java/com/networknt/schema/AnnotationsTest.java index 596393985..e147ef12a 100644 --- a/src/test/java/com/networknt/schema/JsonNodeAnnotationsTest.java +++ b/src/test/java/com/networknt/schema/AnnotationsTest.java @@ -19,18 +19,20 @@ import org.junit.jupiter.api.Test; -import com.networknt.schema.annotation.JsonNodeAnnotation; -import com.networknt.schema.annotation.JsonNodeAnnotations; +import com.networknt.schema.annotation.Annotation; +import com.networknt.schema.annotation.Annotations; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.path.PathType; /** - * JsonNodeAnnotationsTest. + * AnnotationsTest. */ -class JsonNodeAnnotationsTest { +class AnnotationsTest { @Test void put() { - JsonNodeAnnotations annotations = new JsonNodeAnnotations(); - JsonNodeAnnotation annotation = new JsonNodeAnnotation("unevaluatedProperties", - new JsonNodePath(PathType.JSON_POINTER), SchemaLocation.of(""), new JsonNodePath(PathType.JSON_POINTER), + Annotations annotations = new Annotations(); + Annotation annotation = new Annotation("unevaluatedProperties", + new NodePath(PathType.JSON_POINTER), SchemaLocation.of(""), new NodePath(PathType.JSON_POINTER), "test"); annotations.put(annotation); assertTrue(annotations.asMap().get(annotation.getInstanceLocation()).contains(annotation)); diff --git a/src/test/java/com/networknt/schema/AnyOfValidatorTest.java b/src/test/java/com/networknt/schema/AnyOfValidatorTest.java index f230b2d7b..b7b89e78b 100644 --- a/src/test/java/com/networknt/schema/AnyOfValidatorTest.java +++ b/src/test/java/com/networknt/schema/AnyOfValidatorTest.java @@ -20,8 +20,6 @@ import org.junit.jupiter.api.Test; -import com.networknt.schema.SpecVersion.VersionFlag; - class AnyOfValidatorTest { @Test void invalidTypeShouldThrowJsonSchemaException() { @@ -33,8 +31,8 @@ void invalidTypeShouldThrowJsonSchemaException() { + " \"$ref\": \"#/defs/User\"\r\n" + " }\r\n" + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - JsonSchemaException ex = assertThrows(JsonSchemaException.class, () -> factory.getSchema(schemaData)); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12); + SchemaException ex = assertThrows(SchemaException.class, () -> factory.getSchema(schemaData)); assertEquals("type", ex.getError().getMessageKey()); } @@ -59,9 +57,9 @@ void walkValidationWithNullNodeShouldNotValidate() { String jsonContents = "{}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7); - JsonSchema schema = factory.getSchema(schemaContents); - ValidationResult result = schema.walk(jsonContents, InputFormat.JSON, true); - assertEquals(true, result.getValidationMessages().isEmpty()); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7); + Schema schema = factory.getSchema(schemaContents); + Result result = schema.walk(jsonContents, InputFormat.JSON, true); + assertEquals(true, result.getErrors().isEmpty()); } } diff --git a/src/test/java/com/networknt/schema/BaseJsonSchemaValidatorTest.java b/src/test/java/com/networknt/schema/BaseJsonSchemaValidatorTest.java index 5650cd43d..d02924de5 100644 --- a/src/test/java/com/networknt/schema/BaseJsonSchemaValidatorTest.java +++ b/src/test/java/com/networknt/schema/BaseJsonSchemaValidatorTest.java @@ -46,42 +46,39 @@ public static JsonNode getJsonNodeFromUrl(String url) throws IOException { return mapper.readTree(new URL(url)); } - public static JsonSchema getJsonSchemaFromClasspath(String name) { - return getJsonSchemaFromClasspath(name, SpecVersion.VersionFlag.V4, null); + public static Schema getJsonSchemaFromClasspath(String name) { + return getJsonSchemaFromClasspath(name, SpecificationVersion.DRAFT_4, null); } - public static JsonSchema getJsonSchemaFromClasspath(String name, SpecVersion.VersionFlag schemaVersion) { + public static Schema getJsonSchemaFromClasspath(String name, SpecificationVersion schemaVersion) { return getJsonSchemaFromClasspath(name, schemaVersion, null); } - public static JsonSchema getJsonSchemaFromClasspath(String name, SpecVersion.VersionFlag schemaVersion, SchemaValidatorsConfig config) { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(schemaVersion); + public static Schema getJsonSchemaFromClasspath(String name, SpecificationVersion schemaVersion, SchemaRegistryConfig config) { + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(schemaVersion, builder -> builder.schemaRegistryConfig(config)); InputStream is = Thread.currentThread().getContextClassLoader() .getResourceAsStream(name); - if (config == null) { - return factory.getSchema(is); - } - return factory.getSchema(is, config); + return factory.getSchema(is); } - public static JsonSchema getJsonSchemaFromStringContent(String schemaContent) { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V4); + public static Schema getJsonSchemaFromStringContent(String schemaContent) { + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_4); return factory.getSchema(schemaContent); } - public static JsonSchema getJsonSchemaFromUrl(String uri) throws URISyntaxException { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V4); + public static Schema getJsonSchemaFromUrl(String uri) throws URISyntaxException { + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_4); return factory.getSchema(SchemaLocation.of(uri)); } - public static JsonSchema getJsonSchemaFromJsonNode(JsonNode jsonNode) { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V4); + public static Schema getJsonSchemaFromJsonNode(JsonNode jsonNode) { + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_4); return factory.getSchema(jsonNode); } // Automatically detect version for given JsonNode - public static JsonSchema getJsonSchemaFromJsonNodeAutomaticVersion(JsonNode jsonNode) { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersionDetector.detect(jsonNode)); + public static Schema getJsonSchemaFromJsonNodeAutomaticVersion(JsonNode jsonNode) { + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersionDetector.detect(jsonNode)); return factory.getSchema(jsonNode); } diff --git a/src/test/java/com/networknt/schema/CollectorContextTest.java b/src/test/java/com/networknt/schema/CollectorContextTest.java index a39e8d42f..f2ecfc7e7 100644 --- a/src/test/java/com/networknt/schema/CollectorContextTest.java +++ b/src/test/java/com/networknt/schema/CollectorContextTest.java @@ -19,7 +19,13 @@ import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.networknt.schema.SpecVersion.VersionFlag; +import com.networknt.schema.dialect.Dialect; +import com.networknt.schema.dialect.Dialects; +import com.networknt.schema.format.Format; +import com.networknt.schema.keyword.AbstractKeywordValidator; +import com.networknt.schema.keyword.Keyword; +import com.networknt.schema.keyword.KeywordValidator; +import com.networknt.schema.path.NodePath; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; @@ -34,36 +40,39 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.BiConsumer; +import java.util.function.BinaryOperator; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collector; class CollectorContextTest { + enum Data { + SAMPLE_COLLECTOR, + SAMPLE_COLLECTOR_OTHER + } - private static final String SAMPLE_COLLECTOR = "sampleCollector"; - - private static final String SAMPLE_COLLECTOR_OTHER = "sampleCollectorOther"; - - private JsonSchema jsonSchema; + private Schema jsonSchema; - private JsonSchema jsonSchemaForCombine; + private Schema jsonSchemaForCombine; @BeforeEach void setup() throws Exception { setupSchema(); } - @SuppressWarnings("unchecked") @Test void testCollectorContextWithKeyword() throws Exception { - ValidationResult validationResult = validate("{\"test-property1\":\"sample1\",\"test-property2\":\"sample2\"}"); - Assertions.assertEquals(0, validationResult.getValidationMessages().size()); - List contextValues = (List) validationResult.getCollectorContext().get(SAMPLE_COLLECTOR); + Result validationResult = validate("{\"test-property1\":\"sample1\",\"test-property2\":\"sample2\"}"); + Assertions.assertEquals(0, validationResult.getErrors().size()); + List contextValues = validationResult.getCollectorContext().get(Data.SAMPLE_COLLECTOR); contextValues.sort(null); - Assertions.assertEquals(0, validationResult.getValidationMessages().size()); + Assertions.assertEquals(0, validationResult.getErrors().size()); Assertions.assertEquals(2, contextValues.size()); Assertions.assertEquals(contextValues.get(0), "actual_value_added_to_context1"); Assertions.assertEquals(contextValues.get(1), "actual_value_added_to_context2"); } - @SuppressWarnings("unchecked") @Test void testCollectorContextWithMultipleThreads() throws Exception { @@ -86,77 +95,64 @@ void testCollectorContextWithMultipleThreads() throws Exception { thread2.join(); thread3.join(); - ValidationResult validationResult1 = validationRunnable1.getValidationResult(); - ValidationResult validationResult2 = validationRunnable2.getValidationResult(); - ValidationResult validationResult3 = validationRunnable3.getValidationResult(); + Result validationResult1 = validationRunnable1.getValidationResult(); + Result validationResult2 = validationRunnable2.getValidationResult(); + Result validationResult3 = validationRunnable3.getValidationResult(); - Assertions.assertEquals(0, validationResult1.getValidationMessages().size()); - Assertions.assertEquals(0, validationResult2.getValidationMessages().size()); - Assertions.assertEquals(0, validationResult3.getValidationMessages().size()); + Assertions.assertEquals(0, validationResult1.getErrors().size()); + Assertions.assertEquals(0, validationResult2.getErrors().size()); + Assertions.assertEquals(0, validationResult3.getErrors().size()); - List contextValue1 = (List) validationResult1.getCollectorContext().get(SAMPLE_COLLECTOR); - List contextValue2 = (List) validationResult2.getCollectorContext().get(SAMPLE_COLLECTOR); - List contextValue3 = (List) validationResult3.getCollectorContext().get(SAMPLE_COLLECTOR); + List contextValue1 = validationResult1.getCollectorContext().get(Data.SAMPLE_COLLECTOR); + List contextValue2 = validationResult2.getCollectorContext().get(Data.SAMPLE_COLLECTOR); + List contextValue3 = validationResult3.getCollectorContext().get(Data.SAMPLE_COLLECTOR); Assertions.assertEquals(contextValue1.get(0), "actual_value_added_to_context1"); Assertions.assertEquals(contextValue2.get(0), "actual_value_added_to_context2"); Assertions.assertEquals(contextValue3.get(0), "actual_value_added_to_context3"); } - @SuppressWarnings("unchecked") @Test void testCollectorGetAll() throws IOException { ObjectMapper objectMapper = new ObjectMapper(); ExecutionContext executionContext = jsonSchemaForCombine.createExecutionContext(); - executionContext.getExecutionConfig().setFormatAssertionsEnabled(true); + executionContext.executionConfig(executionConfig -> executionConfig.formatAssertionsEnabled(true)); jsonSchemaForCombine.validate(executionContext, objectMapper .readTree("{\"property1\":\"sample1\",\"property2\":\"sample2\",\"property3\":\"sample3\" }")); - ValidationResult validationResult = new ValidationResult(executionContext); + Result validationResult = new Result(executionContext); CollectorContext collectorContext = validationResult.getCollectorContext(); - collectorContext.loadCollectors(); - Assertions.assertEquals(((List) collectorContext.get(SAMPLE_COLLECTOR)).size(), 1); - Assertions.assertEquals(((List) collectorContext.get(SAMPLE_COLLECTOR_OTHER)).size(), 3); + List sampleCollector = collectorContext.get(Data.SAMPLE_COLLECTOR); + List sampleCollectorOther = collectorContext.get(Data.SAMPLE_COLLECTOR_OTHER); + Assertions.assertEquals(sampleCollector.size(), 1); + Assertions.assertEquals(sampleCollectorOther.size(), 3); } - - private JsonMetaSchema getJsonMetaSchema(String uri) throws Exception { - JsonMetaSchema jsonMetaSchema = JsonMetaSchema.builder(uri, JsonMetaSchema.getV201909()) - .keyword(new CustomKeyword()).keyword(new CustomKeyword1()).format(new Format() { - @SuppressWarnings("unchecked") - @Override - public boolean matches(ExecutionContext executionContext, String value) { - CollectorContext collectorContext = executionContext.getCollectorContext(); - if (collectorContext.get(SAMPLE_COLLECTOR) == null) { - collectorContext.add(SAMPLE_COLLECTOR, new ArrayList()); - } - List returnList = (List) collectorContext.get(SAMPLE_COLLECTOR); - returnList.add(value); - return true; - } + private Dialect getDialect(String uri) throws Exception { + Dialect dialect = Dialect.builder(uri, Dialects.getDraft201909()) + .keyword(new CustomKeyword()).keyword(new CustomKeyword1()).format(new Format() { + @Override + public boolean matches(ExecutionContext executionContext, String value) { + CollectorContext collectorContext = executionContext.getCollectorContext(); + List returnList = collectorContext.computeIfAbsent(Data.SAMPLE_COLLECTOR, + key -> new ArrayList()); + returnList.add(value); + return true; + } @Override public String getName() { return "sample-format"; } - - // Return null. As are just testing collection context. - @Override - public String getErrorMessageDescription() { - return null; - } }).build(); - return jsonMetaSchema; + return dialect; } private void setupSchema() throws Exception { - final JsonMetaSchema metaSchema = getJsonMetaSchema( + final Dialect dialect = getDialect( "https://github.com/networknt/json-schema-validator/tests/schemas/example01"); - final JsonSchemaFactory schemaFactory = JsonSchemaFactory - .builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V201909)).metaSchema(metaSchema) - .build(); - SchemaValidatorsConfig schemaValidatorsConfig = SchemaValidatorsConfig.builder().build(); - this.jsonSchema = schemaFactory.getSchema(getSchemaString(), schemaValidatorsConfig); - this.jsonSchemaForCombine = schemaFactory.getSchema(getSchemaStringMultipleProperties(), schemaValidatorsConfig); + final SchemaRegistry schemaFactory = SchemaRegistry.withDialect(dialect); + this.jsonSchema = schemaFactory.getSchema(getSchemaString()); + this.jsonSchemaForCombine = schemaFactory.getSchema(getSchemaStringMultipleProperties()); } private String getSchemaString() { @@ -222,7 +218,7 @@ private class ValidationThread implements Runnable { private final String name; - private ValidationResult validationResult; + private Result validationResult; ValidationThread(String data, String name) { this.name = name; @@ -242,7 +238,7 @@ public void run() { } } - ValidationResult getValidationResult() { + Result getValidationResult() { return this.validationResult; } @@ -264,8 +260,8 @@ public String getValue() { } @Override - public JsonValidator newValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, - JsonSchema parentSchema, ValidationContext validationContext) throws JsonSchemaException, Exception { + public KeywordValidator newValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, + Schema parentSchema, SchemaContext schemaContext) throws SchemaException, Exception { if (schemaNode != null && schemaNode.isArray()) { return new CustomValidator(schemaLocation, evaluationPath, schemaNode); } @@ -279,48 +275,68 @@ public JsonValidator newValidator(SchemaLocation schemaLocation, JsonNodePath ev * This will be helpful in cases where we don't want to revisit the entire JSON * document again just for gathering this kind of information. */ - private class CustomValidator extends AbstractJsonValidator { - public CustomValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode) { - super(schemaLocation, evaluationPath, new CustomKeyword(), schemaNode); + private class CustomValidator extends AbstractKeywordValidator { + private final CustomCollector customCollector = new CustomCollector(); + public CustomValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode) { + super(new CustomKeyword(), schemaNode, schemaLocation, evaluationPath); } - @Override - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, - JsonNodePath instanceLocation) { - CollectorContext collectorContext = executionContext.getCollectorContext(); - CustomCollector customCollector = (CustomCollector) collectorContext.getCollectorMap().computeIfAbsent(SAMPLE_COLLECTOR, - key -> new CustomCollector()); - customCollector.combine(node.textValue()); - } + @Override + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, + NodePath instanceLocation) { + CollectorContext collectorContext = executionContext.getCollectorContext(); + List result = collectorContext.computeIfAbsent(Data.SAMPLE_COLLECTOR, + key -> customCollector.supplier().get()); + customCollector.accumulator().accept(result, node); + } @Override - public void walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation, boolean shouldValidateSchema) { + public void walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation, boolean shouldValidateSchema) { // Ignore this method for testing. } } - - private class CustomCollector extends AbstractCollector> { - - List returnList = new ArrayList(); - + private class CustomCollector implements Collector, List> { private Map referenceMap = null; public CustomCollector() { - referenceMap = getDatasourceMap(); - } - - @Override - public List collect() { - return returnList; + this(getDatasourceMap()); } - - @Override - public void combine(Object object) { - synchronized (returnList) { - returnList.add(referenceMap.get((String) object)); - } + + public CustomCollector(Map referenceMap) { + this.referenceMap = referenceMap; } + @Override + public Supplier> supplier() { + return ArrayList::new; + } + + @Override + public BiConsumer, JsonNode> accumulator() { + return (returnList, instanceNode) -> { + synchronized (returnList) { + returnList.add(referenceMap.get(instanceNode.textValue())); + } + }; + } + + @Override + public BinaryOperator> combiner() { + return (left, right) -> { + left.addAll(right); + return left; + }; + } + + @Override + public Function, List> finisher() { + return Function.identity(); + } + + @Override + public Set characteristics() { + return Collections.unmodifiableSet(EnumSet.of(Characteristics.IDENTITY_FINISH)); + } } /** @@ -334,8 +350,8 @@ public String getValue() { } @Override - public JsonValidator newValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, - JsonSchema parentSchema, ValidationContext validationContext) throws JsonSchemaException, Exception { + public KeywordValidator newValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, + Schema parentSchema, SchemaContext schemaContext) throws SchemaException, Exception { if (schemaNode != null && schemaNode.isArray()) { return new CustomValidator1(schemaLocation, evaluationPath, schemaNode); } @@ -351,39 +367,38 @@ public JsonValidator newValidator(SchemaLocation schemaLocation, JsonNodePath ev * we expect this validator to be called multiple times as the associated * keyword has been used multiple times in JSON Schema. */ - private class CustomValidator1 extends AbstractJsonValidator { - public CustomValidator1(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode) { - super(schemaLocation, evaluationPath,new CustomKeyword(), schemaNode); + private class CustomValidator1 extends AbstractKeywordValidator { + public CustomValidator1(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode) { + super(new CustomKeyword(), schemaNode,schemaLocation, evaluationPath); } - @SuppressWarnings("unchecked") @Override - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) { + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, + NodePath instanceLocation) { // Get an instance of collector context. CollectorContext collectorContext = executionContext.getCollectorContext(); // If collector type is not added to context add one. - List returnList = (List) collectorContext.getCollectorMap() - .computeIfAbsent(SAMPLE_COLLECTOR_OTHER, key -> new ArrayList()); - synchronized(returnList) { + List returnList = collectorContext.computeIfAbsent(Data.SAMPLE_COLLECTOR_OTHER, + key -> new ArrayList()); + synchronized (returnList) { returnList.add(node.textValue()); } } @Override - public void walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation, boolean shouldValidateSchema) { + public void walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation, boolean shouldValidateSchema) { // Ignore this method for testing. } } - private ValidationResult validate(String jsonData) throws Exception { + private Result validate(String jsonData) throws Exception { ObjectMapper objectMapper = new ObjectMapper(); ExecutionContext executionContext = this.jsonSchema.createExecutionContext(); this.jsonSchema.validate(executionContext, objectMapper.readTree(jsonData)); - executionContext.getCollectorContext().loadCollectors(); - return new ValidationResult(executionContext); + return new Result(executionContext); } - private Map getDatasourceMap() { + protected static Map getDatasourceMap() { Map map = new HashMap(); map.put("sample1", "actual_value_added_to_context1"); map.put("sample2", "actual_value_added_to_context2"); @@ -394,16 +409,14 @@ private Map getDatasourceMap() { @Test void constructor() { CollectorContext context = new CollectorContext(); - assertTrue(context.getCollectorMap().isEmpty()); - assertTrue(context.getAll().isEmpty()); + assertTrue(context.getData().isEmpty()); } @Test void constructorWithMap() { - ConcurrentHashMap collectorMap = new ConcurrentHashMap<>(); - ConcurrentHashMap collectorLoadMap = new ConcurrentHashMap<>(); - CollectorContext context = new CollectorContext(collectorMap, collectorLoadMap); - assertSame(collectorMap, context.getCollectorMap()); + ConcurrentHashMap data = new ConcurrentHashMap<>(); + CollectorContext context = new CollectorContext(data); + assertSame(data, context.getData()); } private class CollectKeyword implements Keyword { @@ -413,8 +426,8 @@ public String getValue() { } @Override - public JsonValidator newValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, - JsonSchema parentSchema, ValidationContext validationContext) throws JsonSchemaException, Exception { + public KeywordValidator newValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, + Schema parentSchema, SchemaContext schemaContext) throws SchemaException, Exception { if (schemaNode != null && schemaNode.isBoolean()) { return new CollectValidator(schemaLocation, evaluationPath, schemaNode); } @@ -422,26 +435,26 @@ public JsonValidator newValidator(SchemaLocation schemaLocation, JsonNodePath ev } } - private class CollectValidator extends AbstractJsonValidator { - CollectValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode) { - super(schemaLocation, evaluationPath, new CollectKeyword(), schemaNode); + private class CollectValidator extends AbstractKeywordValidator { + CollectValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode) { + super(new CollectKeyword(), schemaNode, schemaLocation, evaluationPath); } @Override - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) { + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation) { // Get an instance of collector context. CollectorContext collectorContext = executionContext.getCollectorContext(); - AtomicInteger count = (AtomicInteger) collectorContext.getCollectorMap().computeIfAbsent("collect", + AtomicInteger count = collectorContext.computeIfAbsent("collect", (key) -> new AtomicInteger(0)); count.incrementAndGet(); } @Override public void walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, - JsonNodePath instanceLocation, boolean shouldValidateSchema) { + NodePath instanceLocation, boolean shouldValidateSchema) { if (!shouldValidateSchema) { CollectorContext collectorContext = executionContext.getCollectorContext(); - AtomicInteger count = (AtomicInteger) collectorContext.getCollectorMap().computeIfAbsent("collect", + AtomicInteger count = (AtomicInteger) collectorContext.getData().computeIfAbsent("collect", (key) -> new AtomicInteger(0)); count.incrementAndGet(); } @@ -451,10 +464,10 @@ public void walk(ExecutionContext executionContext, JsonNode node, JsonNode root @Test void concurrency() throws Exception { - CollectorContext collectorContext = new CollectorContext(new ConcurrentHashMap<>(), new ConcurrentHashMap<>()); - JsonMetaSchema metaSchema = JsonMetaSchema.builder(JsonMetaSchema.getV202012()).keyword(new CollectKeyword()).build(); - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012, builder -> builder.metaSchema(metaSchema)); - JsonSchema schema = factory.getSchema("{\n" + CollectorContext collectorContext = new CollectorContext(new ConcurrentHashMap<>()); + Dialect dialect = Dialect.builder(Dialects.getDraft202012()).keyword(new CollectKeyword()).build(); + SchemaRegistry factory = SchemaRegistry.withDialect(dialect); + Schema schema = factory.getSchema("{\n" + " \"collect\": true\n" + "}"); Exception[] instance = new Exception[1]; @@ -492,17 +505,16 @@ public void run() { if (instance[0] != null) { throw instance[0]; } - collectorContext.loadCollectors(); - AtomicInteger result = (AtomicInteger) collectorContext.get("collect"); + AtomicInteger result = collectorContext.get("collect"); assertEquals(50, result.get()); } @Test void iterate() { - CollectorContext collectorContext = new CollectorContext(new ConcurrentHashMap<>(), new ConcurrentHashMap<>()); - JsonMetaSchema metaSchema = JsonMetaSchema.builder(JsonMetaSchema.getV202012()).keyword(new CollectKeyword()).build(); - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012, builder -> builder.metaSchema(metaSchema)); - JsonSchema schema = factory.getSchema("{\n" + CollectorContext collectorContext = new CollectorContext(new ConcurrentHashMap<>()); + Dialect dialect = Dialect.builder(Dialects.getDraft202012()).keyword(new CollectKeyword()).build(); + SchemaRegistry factory = SchemaRegistry.withDialect(dialect); + Schema schema = factory.getSchema("{\n" + " \"collect\": true\n" + "}"); for (int i = 0; i < 50; ++i) { @@ -510,17 +522,16 @@ void iterate() { executionContext.setCollectorContext(collectorContext); }); } - collectorContext.loadCollectors(); - AtomicInteger result = (AtomicInteger) collectorContext.get("collect"); + AtomicInteger result = collectorContext.get("collect"); assertEquals(50, result.get()); } @Test void iterateWalk() { - CollectorContext collectorContext = new CollectorContext(new ConcurrentHashMap<>(), new ConcurrentHashMap<>()); - JsonMetaSchema metaSchema = JsonMetaSchema.builder(JsonMetaSchema.getV202012()).keyword(new CollectKeyword()).build(); - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012, builder -> builder.metaSchema(metaSchema)); - JsonSchema schema = factory.getSchema("{\n" + CollectorContext collectorContext = new CollectorContext(new ConcurrentHashMap<>()); + Dialect dialect = Dialect.builder(Dialects.getDraft202012()).keyword(new CollectKeyword()).build(); + SchemaRegistry factory = SchemaRegistry.withDialect(dialect); + Schema schema = factory.getSchema("{\n" + " \"collect\": true\n" + "}"); for (int i = 0; i < 50; ++i) { @@ -528,17 +539,16 @@ void iterateWalk() { executionContext.setCollectorContext(collectorContext); }); } - collectorContext.loadCollectors(); - AtomicInteger result = (AtomicInteger) collectorContext.get("collect"); + AtomicInteger result = collectorContext.get("collect"); assertEquals(50, result.get()); } @Test void iterateWalkValidate() { - CollectorContext collectorContext = new CollectorContext(new ConcurrentHashMap<>(), new ConcurrentHashMap<>()); - JsonMetaSchema metaSchema = JsonMetaSchema.builder(JsonMetaSchema.getV202012()).keyword(new CollectKeyword()).build(); - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012, builder -> builder.metaSchema(metaSchema)); - JsonSchema schema = factory.getSchema("{\n" + CollectorContext collectorContext = new CollectorContext(new ConcurrentHashMap<>()); + Dialect dialect = Dialect.builder(Dialects.getDraft202012()).keyword(new CollectKeyword()).build(); + SchemaRegistry factory = SchemaRegistry.withDialect(dialect); + Schema schema = factory.getSchema("{\n" + " \"collect\": true\n" + "}"); for (int i = 0; i < 50; ++i) { @@ -546,8 +556,7 @@ void iterateWalkValidate() { executionContext.setCollectorContext(collectorContext); }); } - collectorContext.loadCollectors(); - AtomicInteger result = (AtomicInteger) collectorContext.get("collect"); + AtomicInteger result = collectorContext.get("collect"); assertEquals(50, result.get()); } diff --git a/src/test/java/com/networknt/schema/ConstValidatorTest.java b/src/test/java/com/networknt/schema/ConstValidatorTest.java index 94794f6b5..585c0552a 100644 --- a/src/test/java/com/networknt/schema/ConstValidatorTest.java +++ b/src/test/java/com/networknt/schema/ConstValidatorTest.java @@ -23,7 +23,6 @@ import org.junit.jupiter.api.Test; -import com.networknt.schema.SpecVersion.VersionFlag; import com.networknt.schema.i18n.ResourceBundleMessageSource; /** @@ -36,13 +35,13 @@ void localeMessageOthers() { String schemaData = "{\r\n" + " \"const\": \"aa\"\r\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder() + SchemaRegistryConfig config = SchemaRegistryConfig.builder() .messageSource(new ResourceBundleMessageSource("const-messages-override", "jsv-messages")) .build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, config); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12, builder -> builder.schemaRegistryConfig(config)).getSchema(schemaData); String inputData = "\"bb\""; - List messages = schema.validate(inputData, InputFormat.JSON); - assertEquals(": must be the constant value 'aa' but is 'bb'", messages.iterator().next().getMessage()); + List messages = schema.validate(inputData, InputFormat.JSON); + assertEquals(": must be the constant value 'aa' but is 'bb'", messages.iterator().next().toString()); } @Test @@ -50,13 +49,13 @@ void localeMessageNumber() { String schemaData = "{\r\n" + " \"const\": 1\r\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder() + SchemaRegistryConfig config = SchemaRegistryConfig.builder() .messageSource(new ResourceBundleMessageSource("const-messages-override", "jsv-messages")) .build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, config); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12, builder -> builder.schemaRegistryConfig(config)).getSchema(schemaData); String inputData = "2"; - List messages = schema.validate(inputData, InputFormat.JSON); - assertEquals(": must be the constant value '1' but is '2'", messages.iterator().next().getMessage()); + List messages = schema.validate(inputData, InputFormat.JSON); + assertEquals(": must be the constant value '1' but is '2'", messages.iterator().next().toString()); } @Test @@ -64,10 +63,10 @@ void validOthers() { String schemaData = "{\r\n" + " \"const\": \"aa\"\r\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, config); + SchemaRegistryConfig config = SchemaRegistryConfig.builder().build(); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12, builder -> builder.schemaRegistryConfig(config)).getSchema(schemaData); String inputData = "\"aa\""; - List messages = schema.validate(inputData, InputFormat.JSON); + List messages = schema.validate(inputData, InputFormat.JSON); assertTrue(messages.isEmpty()); } @@ -76,10 +75,9 @@ void validNumber() { String schemaData = "{\r\n" + " \"const\": 1234.56789\r\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, config); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12).getSchema(schemaData); String inputData = "1234.56789"; - List messages = schema.validate(inputData, InputFormat.JSON); + List messages = schema.validate(inputData, InputFormat.JSON); assertTrue(messages.isEmpty()); } @@ -88,10 +86,9 @@ void invalidNumber() { String schemaData = "{\r\n" + " \"const\": 1234.56789\r\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, config); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12).getSchema(schemaData); String inputData = "\"1234.56789\""; - List messages = schema.validate(inputData, InputFormat.JSON); + List messages = schema.validate(inputData, InputFormat.JSON); assertFalse(messages.isEmpty()); } diff --git a/src/test/java/com/networknt/schema/ContentSchemaValidatorTest.java b/src/test/java/com/networknt/schema/ContentSchemaValidatorTest.java index fa41fc703..929c0cd1a 100644 --- a/src/test/java/com/networknt/schema/ContentSchemaValidatorTest.java +++ b/src/test/java/com/networknt/schema/ContentSchemaValidatorTest.java @@ -20,7 +20,6 @@ import org.junit.jupiter.api.Test; import com.fasterxml.jackson.core.JsonProcessingException; -import com.networknt.schema.SpecVersion.VersionFlag; import com.networknt.schema.output.OutputUnit; import com.networknt.schema.serialization.JsonMapperFactory; @@ -54,15 +53,14 @@ void annotationCollection() throws JsonProcessingException { + " ]\r\n" + " }\r\n" + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema schema = factory.getSchema(schemaData, config); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12); + Schema schema = factory.getSchema(schemaData); String inputData = "\"helloworld\""; OutputUnit outputUnit = schema.validate(inputData, InputFormat.JSON, OutputFormat.LIST, executionConfiguration -> { - executionConfiguration.getExecutionConfig().setAnnotationCollectionEnabled(true); - executionConfiguration.getExecutionConfig().setAnnotationCollectionFilter(keyword -> true); + executionConfiguration.executionConfig(executionConfig -> executionConfig + .annotationCollectionEnabled(true).annotationCollectionFilter(keyword -> true)); }); String output = JsonMapperFactory.getInstance().writeValueAsString(outputUnit); String expected = "{\"valid\":true,\"details\":[{\"valid\":true,\"evaluationPath\":\"\",\"schemaLocation\":\"#\",\"instanceLocation\":\"\",\"annotations\":{\"contentMediaType\":\"application/jwt\",\"contentSchema\":{\"type\":\"array\",\"minItems\":2,\"prefixItems\":[{\"const\":{\"typ\":\"JWT\",\"alg\":\"HS256\"}},{\"type\":\"object\",\"required\":[\"iss\",\"exp\"],\"properties\":{\"iss\":{\"type\":\"string\"},\"exp\":{\"type\":\"integer\"}}}]}}}]}"; diff --git a/src/test/java/com/networknt/schema/CustomMessageTest.java b/src/test/java/com/networknt/schema/CustomMessageTest.java index 79f41b473..cf0064bd0 100644 --- a/src/test/java/com/networknt/schema/CustomMessageTest.java +++ b/src/test/java/com/networknt/schema/CustomMessageTest.java @@ -1,7 +1,5 @@ package com.networknt.schema; -import com.networknt.schema.SpecVersion.VersionFlag; - import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.DynamicNode; import org.junit.jupiter.api.TestFactory; @@ -14,13 +12,13 @@ class CustomMessageTest extends AbstractJsonSchemaTestSuite { @TestFactory @DisplayName("Draft 2019-09 - Custom Messages Enabled") Stream draft201909__customMessagesEnabled() { - return createTests(VersionFlag.V201909, "src/test/resources/schema/customMessageTests/custom-message-tests.json"); + return createTests(SpecificationVersion.DRAFT_2019_09, "src/test/resources/schema/customMessageTests/custom-message-tests.json"); } @TestFactory @DisplayName("Draft 2019-09 - Custom Messages Disabled") Stream draft201909__customMessagesDisabled() { - return createTests(VersionFlag.V201909, "src/test/resources/schema/customMessageTests/custom-message-disabled-tests.json"); + return createTests(SpecificationVersion.DRAFT_2019_09, "src/test/resources/schema/customMessageTests/custom-message-disabled-tests.json"); } } diff --git a/src/test/java/com/networknt/schema/CustomMetaSchemaTest.java b/src/test/java/com/networknt/schema/CustomMetaSchemaTest.java index 6e616893b..7f7c06c00 100644 --- a/src/test/java/com/networknt/schema/CustomMetaSchemaTest.java +++ b/src/test/java/com/networknt/schema/CustomMetaSchemaTest.java @@ -18,6 +18,13 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import com.networknt.schema.dialect.Dialect; +import com.networknt.schema.dialect.Dialects; +import com.networknt.schema.keyword.AbstractKeyword; +import com.networknt.schema.keyword.AbstractKeywordValidator; +import com.networknt.schema.keyword.KeywordValidator; +import com.networknt.schema.path.NodePath; + import org.junit.jupiter.api.Test; import java.io.IOException; @@ -40,14 +47,14 @@ class CustomMetaSchemaTest { */ static class EnumNamesKeyword extends AbstractKeyword { - private static final class Validator extends AbstractJsonValidator { + private static final class Validator extends AbstractKeywordValidator { private final List enumValues; private final List enumNames; private final String keyword; - private Validator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, String keyword, + private Validator(SchemaLocation schemaLocation, NodePath evaluationPath, String keyword, List enumValues, List enumNames, JsonNode schemaNode) { - super(schemaLocation, evaluationPath, new EnumNamesKeyword(), schemaNode); + super(new EnumNamesKeyword(), schemaNode, schemaLocation, evaluationPath); if (enumNames.size() != enumValues.size()) { throw new IllegalArgumentException("enum and enumNames need to be of same length"); } @@ -57,19 +64,19 @@ private Validator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, St } @Override - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) { + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation) { String value = node.asText(); int idx = enumValues.indexOf(value); if (idx < 0) { throw new IllegalArgumentException("value not found in enum. value: " + value + " enum: " + enumValues); } String valueName = enumNames.get(idx); - ValidationMessage validationMessage = ValidationMessage.builder().type(keyword) + Error error = Error.builder().keyword(keyword) .schemaNode(node) .instanceNode(node) - .code("tests.example.enumNames").message("{0}: enumName is {1}").instanceLocation(instanceLocation) + .messageKey("tests.example.enumNames").message("enumName is {0}").instanceLocation(instanceLocation) .arguments(valueName).build(); - executionContext.addError(validationMessage); + executionContext.addError(error); } } @@ -79,17 +86,17 @@ public void validate(ExecutionContext executionContext, JsonNode node, JsonNode } @Override - public JsonValidator newValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, - JsonSchema parentSchema, ValidationContext validationContext) throws JsonSchemaException, Exception { + public KeywordValidator newValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, + Schema parentSchema, SchemaContext schemaContext) throws SchemaException, Exception { /* * You can access the schema node here to read data from your keyword */ if (!schemaNode.isArray()) { - throw new JsonSchemaException("Keyword enumNames needs to receive an array"); + throw new SchemaException("Keyword enumNames needs to receive an array"); } JsonNode parentSchemaNode = parentSchema.getSchemaNode(); if (!parentSchemaNode.has("enum")) { - throw new JsonSchemaException("Keyword enumNames needs to have a sibling enum keyword"); + throw new SchemaException("Keyword enumNames needs to have a sibling enum keyword"); } JsonNode enumSchemaNode = parentSchemaNode.get("enum"); @@ -99,7 +106,7 @@ public JsonValidator newValidator(SchemaLocation schemaLocation, JsonNodePath ev private List readStringList(JsonNode node) { if (!node.isArray()) { - throw new JsonSchemaException("Keyword enum needs to receive an array"); + throw new SchemaException("Keyword enum needs to receive an array"); } ArrayList result = new ArrayList(node.size()); for (JsonNode child : node) { @@ -112,24 +119,24 @@ private List readStringList(JsonNode node) { @Test void customMetaSchemaWithIgnoredKeyword() throws IOException { ObjectMapper objectMapper = new ObjectMapper(); - final JsonMetaSchema metaSchema = JsonMetaSchema - .builder("https://github.com/networknt/json-schema-validator/tests/schemas/example01", JsonMetaSchema.getV4()) + final Dialect dialect = Dialect + .builder("https://github.com/networknt/json-schema-validator/tests/schemas/example01", Dialects.getDraft4()) // Generated UI uses enumNames to render Labels for enum values .keyword(new EnumNamesKeyword()) .build(); - final JsonSchemaFactory validatorFactory = JsonSchemaFactory.builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V4)).metaSchema(metaSchema).build(); - final JsonSchema schema = validatorFactory.getSchema("{\n" + + final SchemaRegistry validatorFactory = SchemaRegistry.withDialect(dialect); + final Schema schema = validatorFactory.getSchema("{\n" + " \"$schema\":\n" + " \"https://github.com/networknt/json-schema-validator/tests/schemas/example01\",\n" + " \"enum\": [\"foo\", \"bar\"],\n" + " \"enumNames\": [\"Foo !\", \"Bar !\"]\n" + "}"); - List messages = schema.validate(objectMapper.readTree("\"foo\"")); + List messages = schema.validate(objectMapper.readTree("\"foo\"")); assertEquals(1, messages.size()); - ValidationMessage message = messages.iterator().next(); - assertEquals("$: enumName is Foo !", message.getMessage()); + Error message = messages.iterator().next(); + assertEquals(": enumName is Foo !", message.toString()); } } diff --git a/src/test/java/com/networknt/schema/CustomUriTest.java b/src/test/java/com/networknt/schema/CustomUriTest.java index bfd613469..c5790c077 100644 --- a/src/test/java/com/networknt/schema/CustomUriTest.java +++ b/src/test/java/com/networknt/schema/CustomUriTest.java @@ -2,7 +2,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.networknt.schema.resource.InputStreamSource; -import com.networknt.schema.resource.SchemaLoader; +import com.networknt.schema.resource.ResourceLoader; import org.junit.jupiter.api.Test; @@ -17,29 +17,29 @@ class CustomUriTest { @Test void customUri() throws Exception { /* Given */ - final JsonSchemaFactory factory = buildJsonSchemaFactory(); - final JsonSchema schema = factory.getSchema( + final SchemaRegistry factory = buildJsonSchemaFactory(); + final Schema schema = factory.getSchema( "{\"$schema\": \"https://json-schema.org/draft/2019-09/schema\",\"type\": \"object\",\"additionalProperties\": false,\"properties\": {\"customAnyOf\": {\"anyOf\": [{\"type\": \"null\"},{\"$ref\": \"custom:date\"}]},\"customOneOf\": {\"oneOf\": [{\"type\": \"null\"},{\"$ref\": \"custom:date\"}]}}}"); final ObjectMapper mapper = new ObjectMapper(); final JsonNode value = mapper.readTree("{\"customAnyOf\": null,\"customOneOf\": null}"); /* When */ - final List errors = schema.validate(value); + final List errors = schema.validate(value); /* Then */ assertThat(errors.isEmpty(), is(true)); } - private JsonSchemaFactory buildJsonSchemaFactory() { - return JsonSchemaFactory.builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V201909)) - .schemaLoaders(schemaLoaders -> schemaLoaders.add(new CustomUriFetcher())).build(); + private SchemaRegistry buildJsonSchemaFactory() { + return SchemaRegistry.builder(SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2019_09)) + .resourceLoaders(resourceLoaders -> resourceLoaders.add(new CustomUriFetcher())).build(); } - private static class CustomUriFetcher implements SchemaLoader { + private static class CustomUriFetcher implements ResourceLoader { private static final String SCHEMA = "{\"$schema\": \"https://json-schema.org/draft/2019-09/schema\",\"$id\":\"custom:date\",\"type\":\"string\",\"format\":\"date\"}"; @Override - public InputStreamSource getSchema(AbsoluteIri absoluteIri) { + public InputStreamSource getResource(AbsoluteIri absoluteIri) { return () -> new ByteArrayInputStream(SCHEMA.getBytes(StandardCharsets.UTF_8)); } } diff --git a/src/test/java/com/networknt/schema/CyclicDependencyTest.java b/src/test/java/com/networknt/schema/CyclicDependencyTest.java index c6bb016fa..3ac6a8910 100644 --- a/src/test/java/com/networknt/schema/CyclicDependencyTest.java +++ b/src/test/java/com/networknt/schema/CyclicDependencyTest.java @@ -10,8 +10,8 @@ class CyclicDependencyTest { @Test void whenDependencyBetweenSchemaThenValidationSuccessful() throws Exception { - JsonSchemaFactory schemaFactory = JsonSchemaFactory - .builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V4)) + SchemaRegistry schemaFactory = SchemaRegistry + .builder(SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_4)) .build(); String jsonObject = "{\n" + " \"element\": {\n" + @@ -32,8 +32,7 @@ void whenDependencyBetweenSchemaThenValidationSuccessful() throws Exception { " ]\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema schema = schemaFactory.getSchema(SchemaLocation.of("resource:/draft4/issue258/Master.json"), config); + Schema schema = schemaFactory.getSchema(SchemaLocation.of("resource:/draft4/issue258/Master.json")); assertEquals(0, schema.validate(new ObjectMapper().readTree(jsonObject)).size()); } diff --git a/src/test/java/com/networknt/schema/DateTimeDSTTest.java b/src/test/java/com/networknt/schema/DateTimeDSTTest.java index ea182bf83..f98ed0ffb 100644 --- a/src/test/java/com/networknt/schema/DateTimeDSTTest.java +++ b/src/test/java/com/networknt/schema/DateTimeDSTTest.java @@ -9,8 +9,8 @@ import java.util.List; class DateTimeDSTTest { - protected JsonSchema getJsonSchemaFromStreamContentV7(InputStream schemaContent) { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7); + protected Schema getJsonSchemaFromStreamContentV7(InputStream schemaContent) { + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7); return factory.getSchema(schemaContent); } @@ -25,10 +25,10 @@ void shouldWorkV7() throws Exception { String schemaPath = "/schema/dateTimeArray.json"; String dataPath = "/data/dstTimes.json"; // Contains 2020 DST changes for various countries InputStream schemaInputStream = getClass().getResourceAsStream(schemaPath); - JsonSchema schema = getJsonSchemaFromStreamContentV7(schemaInputStream); + Schema schema = getJsonSchemaFromStreamContentV7(schemaInputStream); InputStream dataInputStream = getClass().getResourceAsStream(dataPath); JsonNode node = getJsonNodeFromStreamContent(dataInputStream); - List errors = schema.validate(node); + List errors = schema.validate(node); Assertions.assertEquals(0, errors.size()); } } diff --git a/src/test/java/com/networknt/schema/DefaultJsonSchemaIdValidatorTest.java b/src/test/java/com/networknt/schema/DefaultJsonSchemaIdValidatorTest.java index e2326132f..4c52bd6e8 100644 --- a/src/test/java/com/networknt/schema/DefaultJsonSchemaIdValidatorTest.java +++ b/src/test/java/com/networknt/schema/DefaultJsonSchemaIdValidatorTest.java @@ -21,8 +21,6 @@ import org.junit.jupiter.api.Test; -import com.networknt.schema.SpecVersion.VersionFlag; - /** * Tests for the non-standard DefaultJsonSchemaIdValidator. */ @@ -31,15 +29,15 @@ class DefaultJsonSchemaIdValidatorTest { void givenRelativeIdShouldThrowInvalidSchemaException() { String schema = "{\r\n" + " \"$id\": \"0\",\r\n" + " \"$schema\": \"https://json-schema.org/draft/2020-12/schema\"\r\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder() - .schemaIdValidator(JsonSchemaIdValidator.DEFAULT) + SchemaRegistryConfig config = SchemaRegistryConfig.builder() + .schemaIdValidator(SchemaIdValidator.DEFAULT) .build(); assertThrowsExactly(InvalidSchemaException.class, - () -> JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schema, config)); + () -> SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12, builder -> builder.schemaRegistryConfig(config)).getSchema(schema)); try { - JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schema, config); + SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12, builder -> builder.schemaRegistryConfig(config)).getSchema(schema); } catch (InvalidSchemaException e) { - assertEquals("/$id: '0' is not a valid $id", e.getMessage()); + assertEquals("/$id: '0' is not a valid $id", e.getError().toString()); } } @@ -47,28 +45,28 @@ void givenRelativeIdShouldThrowInvalidSchemaException() { void givenFragmentWithNoContextShouldNotThrowInvalidSchemaException() { String schema = "{\r\n" + " \"$id\": \"#0\",\r\n" + " \"$schema\": \"https://json-schema.org/draft/2020-12/schema\"\r\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder() - .schemaIdValidator(JsonSchemaIdValidator.DEFAULT) + SchemaRegistryConfig config = SchemaRegistryConfig.builder() + .schemaIdValidator(SchemaIdValidator.DEFAULT) .build(); - assertDoesNotThrow(() -> JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schema, config)); + assertDoesNotThrow(() -> SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12, builder -> builder.schemaRegistryConfig(config)).getSchema(schema)); } @Test void givenSlashWithNoContextShouldNotThrowInvalidSchemaException() { String schema = "{\r\n" + " \"$id\": \"/base\",\r\n" + " \"$schema\": \"https://json-schema.org/draft/2020-12/schema\"\r\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder() - .schemaIdValidator(JsonSchemaIdValidator.DEFAULT) + SchemaRegistryConfig config = SchemaRegistryConfig.builder() + .schemaIdValidator(SchemaIdValidator.DEFAULT) .build(); - assertDoesNotThrow(() -> JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schema, config)); + assertDoesNotThrow(() -> SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12, builder -> builder.schemaRegistryConfig(config)).getSchema(schema)); } @Test void givenRelativeIdWithClasspathBaseShouldNotThrowInvalidSchemaException() { - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder() - .schemaIdValidator(JsonSchemaIdValidator.DEFAULT) + SchemaRegistryConfig config = SchemaRegistryConfig.builder() + .schemaIdValidator(SchemaIdValidator.DEFAULT) .build(); - assertDoesNotThrow(() -> JsonSchemaFactory.getInstance(VersionFlag.V202012) - .getSchema(SchemaLocation.of("classpath:schema/id-relative.json"), config)); + assertDoesNotThrow(() -> SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12, builder -> builder.schemaRegistryConfig(config)) + .getSchema(SchemaLocation.of("classpath:schema/id-relative.json"))); } } diff --git a/src/test/java/com/networknt/schema/DependentRequiredTest.java b/src/test/java/com/networknt/schema/DependentRequiredTest.java index 3455d8cf9..4a5e327a6 100644 --- a/src/test/java/com/networknt/schema/DependentRequiredTest.java +++ b/src/test/java/com/networknt/schema/DependentRequiredTest.java @@ -28,14 +28,14 @@ class DependentRequiredTest { " }" + "}"; - private static final JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V201909); - private static final JsonSchema schema = factory.getSchema(SCHEMA); + private static final SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2019_09); + private static final Schema schema = factory.getSchema(SCHEMA); private static final ObjectMapper mapper = new ObjectMapper(); @Test void shouldReturnNoErrorMessagesForObjectWithoutOptionalField() throws IOException { - List messages = whenValidate("{}"); + List messages = whenValidate("{}"); assertThat(messages, empty()); } @@ -43,23 +43,23 @@ void shouldReturnNoErrorMessagesForObjectWithoutOptionalField() throws IOExcepti @Test void shouldReturnErrorMessageForObjectWithoutDependentRequiredField() throws IOException { - List messages = whenValidate("{ \"optional\": \"present\" }"); + List messages = whenValidate("{ \"optional\": \"present\" }"); assertThat( - messages.stream().map(ValidationMessage::getMessage).collect(Collectors.toList()), - contains("$: has a missing property 'requiredWhenOptionalPresent' which is dependent required because 'optional' is present")); + messages.stream().map(Error::toString).collect(Collectors.toList()), + contains(": has a missing property 'requiredWhenOptionalPresent' which is dependent required because 'optional' is present")); } @Test void shouldReturnNoErrorMessagesForObjectWithOptionalAndDependentRequiredFieldSet() throws JsonProcessingException { - List messages = + List messages = whenValidate("{ \"optional\": \"present\", \"requiredWhenOptionalPresent\": \"present\" }"); assertThat(messages, empty()); } - private static List whenValidate(String content) throws JsonProcessingException { + private static List whenValidate(String content) throws JsonProcessingException { return schema.validate(mapper.readTree(content)); } diff --git a/src/test/java/com/networknt/schema/DisallowUnknownJsonMetaSchemaFactoryTest.java b/src/test/java/com/networknt/schema/DisallowUnknownJsonMetaSchemaFactoryTest.java deleted file mode 100644 index 8560c2bab..000000000 --- a/src/test/java/com/networknt/schema/DisallowUnknownJsonMetaSchemaFactoryTest.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.networknt.schema; - -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; -import static org.junit.jupiter.api.Assertions.assertThrows; - -import org.junit.jupiter.api.Test; - -import com.networknt.schema.SpecVersion.VersionFlag; - -/** - * Tests for DisallowUnknownJsonMetaSchemaFactory. - */ -class DisallowUnknownJsonMetaSchemaFactoryTest { - private static final String DRAFT_202012_SCHEMA = "{\r\n" - + " \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\r\n" - + " \"type\": \"object\"\r\n" - + "}"; - - private static final String DRAFT_7_SCHEMA = "{\r\n" - + " \"$schema\": \"http://json-schema.org/draft-07/schema#\",\r\n" - + " \"type\": \"object\"\r\n" - + "}"; - @Test - void defaultHandling() { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - assertDoesNotThrow(() -> factory.getSchema(DRAFT_202012_SCHEMA)); - assertDoesNotThrow(() -> factory.getSchema(DRAFT_7_SCHEMA)); - } - - @Test - void draft202012() { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012, - builder -> builder.metaSchemaFactory(DisallowUnknownJsonMetaSchemaFactory.getInstance())); - assertDoesNotThrow(() -> factory.getSchema(DRAFT_202012_SCHEMA)); - assertThrows(InvalidSchemaException.class, () -> factory.getSchema(DRAFT_7_SCHEMA)); - } - - @Test - void draft7() { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V7, - builder -> builder.metaSchemaFactory(DisallowUnknownJsonMetaSchemaFactory.getInstance())); - assertDoesNotThrow(() -> factory.getSchema(DRAFT_7_SCHEMA)); - assertThrows(InvalidSchemaException.class, () -> factory.getSchema(DRAFT_202012_SCHEMA)); - } -} diff --git a/src/test/java/com/networknt/schema/DisallowUnknownKeywordFactoryTest.java b/src/test/java/com/networknt/schema/DisallowUnknownKeywordFactoryTest.java index f2b397af9..7169a9586 100644 --- a/src/test/java/com/networknt/schema/DisallowUnknownKeywordFactoryTest.java +++ b/src/test/java/com/networknt/schema/DisallowUnknownKeywordFactoryTest.java @@ -19,7 +19,9 @@ import org.junit.jupiter.api.Test; -import com.networknt.schema.SpecVersion.VersionFlag; +import com.networknt.schema.dialect.Dialect; +import com.networknt.schema.dialect.Dialects; +import com.networknt.schema.keyword.DisallowUnknownKeywordFactory; class DisallowUnknownKeywordFactoryTest { @Test @@ -30,10 +32,9 @@ void shouldThrowForUnknownKeywords() { @Test void getSchemaShouldThrowForUnknownKeywords() { - JsonMetaSchema metaSchema = JsonMetaSchema.builder(JsonMetaSchema.getV202012()) + Dialect dialect = Dialect.builder(Dialects.getDraft202012()) .unknownKeywordFactory(DisallowUnknownKeywordFactory.getInstance()).build(); - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012, - builder -> builder.metaSchema(metaSchema)); + SchemaRegistry factory = SchemaRegistry.withDialect(dialect); String schemaData = "{\r\n" + " \"equals\": \"world\"\r\n" + "}"; diff --git a/src/test/java/com/networknt/schema/DiscriminatorValidatorTest.java b/src/test/java/com/networknt/schema/DiscriminatorValidatorTest.java index 0133260b8..1c4857c08 100644 --- a/src/test/java/com/networknt/schema/DiscriminatorValidatorTest.java +++ b/src/test/java/com/networknt/schema/DiscriminatorValidatorTest.java @@ -23,7 +23,7 @@ import org.junit.jupiter.api.Test; -import com.networknt.schema.SpecVersion.VersionFlag; +import com.networknt.schema.dialect.Dialects; /** * Test for discriminator. @@ -115,10 +115,9 @@ void discriminatorInArray() { + " }\r\n" + "]"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().discriminatorKeywordEnabled(true).build(); - JsonSchema schema = factory.getSchema(schemaData, config); - List messages = schema.validate(inputData, InputFormat.JSON); + SchemaRegistry factory = SchemaRegistry.withDialect(Dialects.getOpenApi31()); + Schema schema = factory.getSchema(schemaData); + List messages = schema.validate(inputData, InputFormat.JSON); assertTrue(messages.isEmpty()); } @@ -147,10 +146,9 @@ void anyOfWithConfigEnabledButNoDiscriminator() { + " \"intOrStringType\": 4\r\n" + " }"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().discriminatorKeywordEnabled(true).build(); - JsonSchema schema = factory.getSchema(schemaData, config); - List messages = schema.validate(inputData, InputFormat.JSON); + SchemaRegistry factory = SchemaRegistry.withDialect(Dialects.getOpenApi31()); + Schema schema = factory.getSchema(schemaData); + List messages = schema.validate(inputData, InputFormat.JSON); assertTrue(messages.isEmpty()); } @@ -240,11 +238,10 @@ void discriminatorInArrayInvalidDiscriminatorPropertyAnyOf() { + " }\r\n" + "]"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().discriminatorKeywordEnabled(true).build(); - JsonSchema schema = factory.getSchema(schemaData, config); - List messages = schema.validate(inputData, InputFormat.JSON); - assertEquals(1, messages.size()); + SchemaRegistry factory = SchemaRegistry.withDialect(Dialects.getOpenApi31()); + Schema schema = factory.getSchema(schemaData); + List messages = schema.validate(inputData, InputFormat.JSON); + assertEquals(1, messages.size()); // RECHECK THIS } /** @@ -333,10 +330,9 @@ void discriminatorInArrayInvalidDiscriminatorPropertyOneOf() { + " }\r\n" + "]"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().discriminatorKeywordEnabled(true).build(); - JsonSchema schema = factory.getSchema(schemaData, config); - List messages = schema.validate(inputData, InputFormat.JSON); + SchemaRegistry factory = SchemaRegistry.withDialect(Dialects.getOpenApi31()); + Schema schema = factory.getSchema(schemaData); + List messages = schema.validate(inputData, InputFormat.JSON); assertEquals(1, messages.size()); } @@ -423,16 +419,15 @@ void discriminatorInArrayOneOfShouldOnlyReportErrorsInMatchingDiscriminator() { + " }\r\n" + "]"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().discriminatorKeywordEnabled(true).build(); - JsonSchema schema = factory.getSchema(schemaData, config); - List messages = schema.validate(inputData, InputFormat.JSON); + SchemaRegistry factory = SchemaRegistry.withDialect(Dialects.getOpenApi31()); + Schema schema = factory.getSchema(schemaData); + List messages = schema.validate(inputData, InputFormat.JSON); // Only the oneOf and the error in the BedRoom discriminator is reported // the mismatch in Kitchen is not reported assertEquals(2, messages.size()); - List list = messages.stream().collect(Collectors.toList()); - assertEquals("oneOf", list.get(0).getType()); - assertEquals("required", list.get(1).getType()); + List list = messages.stream().collect(Collectors.toList()); + assertEquals("oneOf", list.get(0).getKeyword()); + assertEquals("required", list.get(1).getKeyword()); assertEquals("numberOfBeds", list.get(1).getProperty()); } @@ -519,16 +514,15 @@ void discriminatorInOneOfShouldOnlyReportErrorsInMatchingDiscriminator() { + " }\r\n" + "]"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().discriminatorKeywordEnabled(true).build(); - JsonSchema schema = factory.getSchema(schemaData, config); - List messages = schema.validate(inputData, InputFormat.JSON); + SchemaRegistry factory = SchemaRegistry.withDialect(Dialects.getOpenApi31()); + Schema schema = factory.getSchema(schemaData); + List messages = schema.validate(inputData, InputFormat.JSON); // Only the oneOf and the error in the BedRoom discriminator is reported // the mismatch in Kitchen is not reported assertEquals(2, messages.size()); - List list = messages.stream().collect(Collectors.toList()); - assertEquals("oneOf", list.get(0).getType()); - assertEquals("required", list.get(1).getType()); + List list = messages.stream().collect(Collectors.toList()); + assertEquals("oneOf", list.get(0).getKeyword()); + assertEquals("required", list.get(1).getKeyword()); assertEquals("numberOfBeds", list.get(1).getProperty()); } @@ -619,16 +613,15 @@ void discriminatorMappingInOneOfShouldOnlyReportErrorsInMatchingDiscriminator() + " }\r\n" + "]"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().discriminatorKeywordEnabled(true).build(); - JsonSchema schema = factory.getSchema(schemaData, config); - List messages = schema.validate(inputData, InputFormat.JSON); + SchemaRegistry factory = SchemaRegistry.withDialect(Dialects.getOpenApi31()); + Schema schema = factory.getSchema(schemaData); + List messages = schema.validate(inputData, InputFormat.JSON); // Only the oneOf and the error in the BedRoom discriminator is reported // the mismatch in Kitchen is not reported assertEquals(2, messages.size()); - List list = messages.stream().collect(Collectors.toList()); - assertEquals("oneOf", list.get(0).getType()); - assertEquals("required", list.get(1).getType()); + List list = messages.stream().collect(Collectors.toList()); + assertEquals("oneOf", list.get(0).getKeyword()); + assertEquals("required", list.get(1).getKeyword()); assertEquals("numberOfBeds", list.get(1).getProperty()); } @@ -674,15 +667,14 @@ void oneOfMissingDiscriminatorValue() { String inputData = "{}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().discriminatorKeywordEnabled(true).build(); - JsonSchema schema = factory.getSchema(schemaData, config); - List messages = schema.validate(inputData, InputFormat.JSON); + SchemaRegistry factory = SchemaRegistry.withDialect(Dialects.getOpenApi31()); + Schema schema = factory.getSchema(schemaData); + List messages = schema.validate(inputData, InputFormat.JSON); assertEquals(3, messages.size()); - List list = messages.stream().collect(Collectors.toList()); - assertEquals("oneOf", list.get(0).getType()); - assertEquals("required", list.get(1).getType()); - assertEquals("required", list.get(2).getType()); + List list = messages.stream().collect(Collectors.toList()); + assertEquals("oneOf", list.get(0).getKeyword()); + assertEquals("required", list.get(1).getKeyword()); + assertEquals("required", list.get(2).getKeyword()); } /** @@ -770,11 +762,223 @@ void anyOfMissingDiscriminatorValue() { + " }\r\n" + "]"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().discriminatorKeywordEnabled(true).build(); - JsonSchema schema = factory.getSchema(schemaData, config); - List messages = schema.validate(inputData, InputFormat.JSON); - List list = messages.stream().collect(Collectors.toList()); - assertEquals("required", list.get(0).getType()); + SchemaRegistry factory = SchemaRegistry.withDialect(Dialects.getOpenApi31()); + Schema schema = factory.getSchema(schemaData); + List messages = schema.validate(inputData, InputFormat.JSON); + List list = messages.stream().collect(Collectors.toList()); + assertEquals("required", list.get(0).getKeyword()); + } + + /** + * Mapped to Bedroom with missing number of beds, however the discriminator is + * not supposed to change the result of anyOf and the data passes for "/anyOf/0" + * : {"$ref":"#/components/schemas/Room"}. + * + * This case is an example of the actual implementation for undefined behavior + * eg. multiple discriminators for an instance location. + */ + @Test + void anyOfRedefinedDiscriminatorAndDiscriminatorWithMissingPropertyName() { + String schemaData = "{\r\n" + + " \"anyOf\": [\r\n" + + " {\r\n" + + " \"$ref\": \"#/components/schemas/Room\"\r\n" + + " },\r\n" + + " {\r\n" + + " \"$ref\": \"#/components/schemas/BedRoom\"\r\n" + + " },\r\n" + + " {\r\n" + + " \"$ref\": \"#/components/schemas/KidsBedRoom\"\r\n" + + " },\r\n" + + " {\r\n" + + " \"$ref\": \"#/components/schemas/Kitchen\"\r\n" + + " },\r\n" + + " {\r\n" + + " \"$ref\": \"#/components/schemas/GuestRoom\"\r\n" + + " }\r\n" + + " ],\r\n" + + " \"components\": {\r\n" + + " \"schemas\": {\r\n" + + " \"Room\": {\r\n" + + " \"type\": \"object\",\r\n" + + " \"properties\": {\r\n" + + " \"@type\": {\r\n" + + " \"type\": \"string\"\r\n" + + " },\r\n" + + " \"floor\": {\r\n" + + " \"type\": \"integer\"\r\n" + + " }\r\n" + + " },\r\n" + + " \"required\": [\r\n" + + " \"@type\"\r\n" + + " ],\r\n" + + " \"discriminator\": {\r\n" + + " \"propertyName\": \"@type\",\r\n" + + " \"mapping\": {\r\n" + + " \"bed\": \"#/components/schemas/BedRoom\",\r\n" + + " \"guest\": \"#/components/schemas/GuestRoom\"\r\n" + + " }\r\n" + + " }\r\n" + + " },\r\n" + + " \"BedRoom\": {\r\n" + + " \"type\": \"object\",\r\n" + + " \"allOf\": [\r\n" + + " {\r\n" + + " \"$ref\": \"#/components/schemas/Room\"\r\n" + + " },\r\n" + + " {\r\n" + + " \"type\": \"object\",\r\n" + + " \"properties\": {\r\n" + + " \"numberOfBeds\": {\r\n" + + " \"type\": \"integer\"\r\n" + + " }\r\n" + + " },\r\n" + + " \"required\": [\r\n" + + " \"numberOfBeds\"\r\n" + + " ]\r\n" + + " }\r\n" + + " ],\r\n" + + " \"discriminator\": {\r\n" + + " \"mapping\": {\r\n" + + " \"guest\": \"#/components/schemas/GuestRoom\"\r\n" + + " }\r\n" + + " }\r\n" + + " },\r\n" + + " \"KidsBedRoom\": {\r\n" + + " \"type\": \"object\",\r\n" + + " \"allOf\": [\r\n" + + " {\r\n" + + " \"$ref\": \"#/components/schemas/BedRoom\"\r\n" + + " },\r\n" + + " {\r\n" + + " \"type\": \"object\",\r\n" + + " \"properties\": {\r\n" + + " \"isTidy\": {\r\n" + + " \"type\": \"boolean\"\r\n" + + " }\r\n" + + " },\r\n" + + " \"required\": [\r\n" + + " \"isTidy\"\r\n" + + " ]\r\n" + + " }\r\n" + + " ]\r\n" + + " },\r\n" + + " \"GuestRoom\": {\r\n" + + " \"type\": \"object\",\r\n" + + " \"allOf\": [\r\n" + + " {\r\n" + + " \"$ref\": \"#/components/schemas/BedRoom\"\r\n" + + " },\r\n" + + " {\r\n" + + " \"type\": \"object\",\r\n" + + " \"properties\": {\r\n" + + " \"guest\": {\r\n" + + " \"type\": \"string\"\r\n" + + " }\r\n" + + " },\r\n" + + " \"required\": [\r\n" + + " \"guest\"\r\n" + + " ]\r\n" + + " }\r\n" + + " ]\r\n" + + " },\r\n" + + " \"Kitchen\": {\r\n" + + " \"type\": \"object\",\r\n" + + " \"allOf\": [\r\n" + + " {\r\n" + + " \"$ref\": \"#/components/schemas/Room\"\r\n" + + " },\r\n" + + " {\r\n" + + " \"type\": \"object\",\r\n" + + " \"properties\": {\r\n" + + " \"hasMicrowaveOven\": {\r\n" + + " \"type\": \"boolean\"\r\n" + + " },\r\n" + + " \"equipment\": {\r\n" + + " \"type\": \"array\",\r\n" + + " \"items\": {\r\n" + + " \"anyOf\": [\r\n" + + " {\r\n" + + " \"$ref\": \"#/components/schemas/Pot\"\r\n" + + " },\r\n" + + " {\r\n" + + " \"$ref\": \"#/components/schemas/Blender\"\r\n" + + " }\r\n" + + " ]\r\n" + + " }\r\n" + + " }\r\n" + + " },\r\n" + + " \"required\": [\r\n" + + " \"hasMicrowaveOven\"\r\n" + + " ]\r\n" + + " }\r\n" + + " ]\r\n" + + " },\r\n" + + " \"KitchenEquipment\": {\r\n" + + " \"type\": \"object\",\r\n" + + " \"properties\": {\r\n" + + " \"@type\": {\r\n" + + " \"type\": \"string\"\r\n" + + " }\r\n" + + " },\r\n" + + " \"required\": [\r\n" + + " \"@type\"\r\n" + + " ],\r\n" + + " \"discriminator\": {\r\n" + + " \"propertyName\": \"@type\"\r\n" + + " }\r\n" + + " },\r\n" + + " \"Pot\": {\r\n" + + " \"allOf\": [\r\n" + + " {\r\n" + + " \"$ref\": \"#/components/schemas/KitchenEquipment\"\r\n" + + " },\r\n" + + " {\r\n" + + " \"type\": \"object\",\r\n" + + " \"properties\": {\r\n" + + " \"capacity\": {\r\n" + + " \"type\": \"integer\"\r\n" + + " }\r\n" + + " },\r\n" + + " \"required\": [\r\n" + + " \"capacity\"\r\n" + + " ]\r\n" + + " }\r\n" + + " ]\r\n" + + " },\r\n" + + " \"Blender\": {\r\n" + + " \"allOf\": [\r\n" + + " {\r\n" + + " \"$ref\": \"#/components/schemas/KitchenEquipment\"\r\n" + + " },\r\n" + + " {\r\n" + + " \"type\": \"object\",\r\n" + + " \"properties\": {\r\n" + + " \"maxSpeed\": {\r\n" + + " \"type\": \"integer\"\r\n" + + " }\r\n" + + " },\r\n" + + " \"required\": [\r\n" + + " \"maxSpeed\"\r\n" + + " ]\r\n" + + " }\r\n" + + " ]\r\n" + + " }\r\n" + + " }\r\n" + + " }\r\n" + + "}"; + + String inputData = "{\"@type\":\"bed\"}"; + + SchemaRegistry factory = SchemaRegistry.withDialect(Dialects.getOpenApi31()); + Schema schema = factory.getSchema(schemaData); + List messages = schema.validate(inputData, InputFormat.JSON); + List list = messages.stream().collect(Collectors.toList()); + // There should be no errors as discriminator should not affect the validation result of anyOf + // Although the matched schema has the following error + // : required property 'numberOfBeds' not found + // There is still a schema in the anyOf that matches + assertTrue(list.isEmpty()); } + } diff --git a/src/test/java/com/networknt/schema/DurationFormatValidatorTest.java b/src/test/java/com/networknt/schema/DurationFormatValidatorTest.java index 00b1086cc..e71e00539 100644 --- a/src/test/java/com/networknt/schema/DurationFormatValidatorTest.java +++ b/src/test/java/com/networknt/schema/DurationFormatValidatorTest.java @@ -34,14 +34,14 @@ void durationFormatValidatorTest() throws IOException { final JsonNode validTargetNode = objectMapper.readTree("\"P1D\""); final JsonNode invalidTargetNode = objectMapper.readTree("\"INVALID_DURATION\""); - final JsonSchemaFactory validatorFactory = JsonSchemaFactory.builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V201909)).build(); - final JsonSchema validatorSchema = validatorFactory.getSchema(schema); + final SchemaRegistry validatorFactory = SchemaRegistry.builder(SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2019_09)).build(); + final Schema validatorSchema = validatorFactory.getSchema(schema); - List messages = validatorSchema.validate(validTargetNode); + List messages = validatorSchema.validate(validTargetNode); assertEquals(0, messages.size()); - messages = validatorSchema.validate(invalidTargetNode, OutputFormat.DEFAULT, (executionContext, validationContext) -> { - executionContext.getExecutionConfig().setFormatAssertionsEnabled(true); + messages = validatorSchema.validate(invalidTargetNode, OutputFormat.DEFAULT, (executionContext, schemaContext) -> { + executionContext.executionConfig(executionConfig -> executionConfig.formatAssertionsEnabled(true)); }); assertEquals(1, messages.size()); diff --git a/src/test/java/com/networknt/schema/EnumValidatorTest.java b/src/test/java/com/networknt/schema/EnumValidatorTest.java index ef8b6c496..2e78e3b5c 100644 --- a/src/test/java/com/networknt/schema/EnumValidatorTest.java +++ b/src/test/java/com/networknt/schema/EnumValidatorTest.java @@ -22,8 +22,6 @@ import org.junit.jupiter.api.Test; -import com.networknt.schema.SpecVersion.VersionFlag; - /** * EnumValidator test. */ @@ -85,11 +83,10 @@ void enumWithObjectNodes() { + " \"name\": \"FOO\",\r\n" + " \"cardinality\": 50\r\n" + "}"; - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, - SchemaValidatorsConfig.builder().build()); - List messages = schema.validate(inputData, InputFormat.JSON).stream().collect(Collectors.toList()); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12).getSchema(schemaData); + List messages = schema.validate(inputData, InputFormat.JSON).stream().collect(Collectors.toList()); assertEquals(1, messages.size()); - ValidationMessage message = messages.get(0); + Error message = messages.get(0); assertEquals( ": does not have a value in the enumeration [{\"name\":\"EMPTY\",\"cardinality\":0}, {\"name\":\"OK\",\"cardinality\":20}, {\"name\":\"UNKNOWN\",\"cardinality\":30}, {\"name\":\"WARNING\",\"cardinality\":40}, {\"name\":\"CRITICAL\",\"cardinality\":50}]", message.toString()); @@ -105,11 +102,10 @@ void enumWithHeterogenousNodes() { + " \"name\": \"FOO\",\r\n" + " \"cardinality\": 50\r\n" + "}"; - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, - SchemaValidatorsConfig.builder().build()); - List messages = schema.validate(inputData, InputFormat.JSON).stream().collect(Collectors.toList()); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12).getSchema(schemaData); + List messages = schema.validate(inputData, InputFormat.JSON).stream().collect(Collectors.toList()); assertEquals(1, messages.size()); - ValidationMessage message = messages.get(0); + Error message = messages.get(0); assertEquals(": does not have a value in the enumeration [6, \"foo\", [], true, {\"foo\":12}]", message.toString()); } } diff --git a/src/test/java/com/networknt/schema/ValidationMessageHandlerTest.java b/src/test/java/com/networknt/schema/ErrorHandlerTest.java similarity index 76% rename from src/test/java/com/networknt/schema/ValidationMessageHandlerTest.java rename to src/test/java/com/networknt/schema/ErrorHandlerTest.java index 4ff9a8ef7..7b1463d53 100644 --- a/src/test/java/com/networknt/schema/ValidationMessageHandlerTest.java +++ b/src/test/java/com/networknt/schema/ErrorHandlerTest.java @@ -22,12 +22,10 @@ import org.junit.jupiter.api.Test; -import com.networknt.schema.SpecVersion.VersionFlag; - /** - * ValidationMessageHandlerTest. + * ErrorHandlerTest. */ -class ValidationMessageHandlerTest { +class ErrorHandlerTest { @Test void errorMessage() { String schemaData = "{\r\n" @@ -51,9 +49,11 @@ void errorMessage() { + " \"foo\": \"a\",\r\n" + " \"bar\": 2\r\n" + "}"; - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, - SchemaValidatorsConfig.builder().errorMessageKeyword("errorMessage").build()); - List messages = schema.validate(inputData, InputFormat.JSON).stream().collect(Collectors.toList()); + SchemaRegistryConfig config = SchemaRegistryConfig.builder().errorMessageKeyword("errorMessage").build(); + Schema schema = SchemaRegistry + .withDefaultDialect(SpecificationVersion.DRAFT_2020_12, builder -> builder.schemaRegistryConfig(config)) + .getSchema(schemaData); + List messages = schema.validate(inputData, InputFormat.JSON).stream().collect(Collectors.toList()); assertFalse(messages.isEmpty()); assertEquals("/foo", messages.get(0).getInstanceLocation().toString()); assertEquals("should be an object", messages.get(0).getMessage()); @@ -81,9 +81,9 @@ void errorMessageUnionType() { String inputData = "{\r\n" + " \"keyword1\": 2\r\n" + "}"; - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, - SchemaValidatorsConfig.builder().errorMessageKeyword("errorMessage").build()); - List messages = schema.validate(inputData, InputFormat.JSON).stream().collect(Collectors.toList()); + SchemaRegistryConfig config = SchemaRegistryConfig.builder().errorMessageKeyword("errorMessage").build(); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12, builder -> builder.schemaRegistryConfig(config)).getSchema(schemaData); + List messages = schema.validate(inputData, InputFormat.JSON).stream().collect(Collectors.toList()); assertFalse(messages.isEmpty()); assertEquals("/keyword1", messages.get(0).getInstanceLocation().toString()); assertEquals("关键字1必须为字符串", messages.get(0).getMessage()); diff --git a/src/test/java/com/networknt/schema/ValidationMessageTest.java b/src/test/java/com/networknt/schema/ErrorTest.java similarity index 86% rename from src/test/java/com/networknt/schema/ValidationMessageTest.java rename to src/test/java/com/networknt/schema/ErrorTest.java index 2357e395b..a24746c4f 100644 --- a/src/test/java/com/networknt/schema/ValidationMessageTest.java +++ b/src/test/java/com/networknt/schema/ErrorTest.java @@ -23,13 +23,13 @@ import com.networknt.schema.serialization.JsonMapperFactory; /** - * ValidationMessageTest. + * ErrorTest. */ -class ValidationMessageTest { +class ErrorTest { @Test void testSerialization() throws JsonProcessingException { String value = JsonMapperFactory.getInstance() - .writeValueAsString(ValidationMessage.builder().messageSupplier(() -> "hello") + .writeValueAsString(Error.builder().messageSupplier(() -> "hello") .schemaLocation(SchemaLocation.of("https://www.example.com/#defs/definition")).build()); assertEquals("{\"message\":\"hello\",\"schemaLocation\":\"https://www.example.com/#defs/definition\"}", value); } diff --git a/src/test/java/com/networknt/schema/ExampleTest.java b/src/test/java/com/networknt/schema/ExampleTest.java index 8b559e7a2..c12d7014a 100644 --- a/src/test/java/com/networknt/schema/ExampleTest.java +++ b/src/test/java/com/networknt/schema/ExampleTest.java @@ -21,17 +21,16 @@ import org.junit.jupiter.api.Test; -import com.networknt.schema.SpecVersion.VersionFlag; +import com.networknt.schema.dialect.DialectId; class ExampleTest { @Test void exampleSchemaLocation() { // This creates a schema factory that will use Draft 2012-12 as the default if $schema is not specified in the initial schema - JsonSchemaFactory jsonSchemaFactory = JsonSchemaFactory.getInstance(VersionFlag.V202012, builder -> - builder.schemaMappers(schemaMappers -> schemaMappers.mapPrefix("https://www.example.org/", "classpath:schema/")) + SchemaRegistry jsonSchemaFactory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12, builder -> + builder.schemaIdResolvers(schemaIdResolvers -> schemaIdResolvers.mapPrefix("https://www.example.org/", "classpath:schema/")) ); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema schema = jsonSchemaFactory.getSchema(SchemaLocation.of("https://www.example.org/example-main.json"), config); + Schema schema = jsonSchemaFactory.getSchema(SchemaLocation.of("https://www.example.org/example-main.json")); String input = "{\r\n" + " \"DriverProperties\": {\r\n" + " \"CommonProperties\": {\r\n" @@ -40,21 +39,20 @@ void exampleSchemaLocation() { + " }\r\n" + "}"; // The example-main.json schema defines $schema with Draft 07 - assertEquals(SchemaId.V7, schema.getValidationContext().getMetaSchema().getIri()); - List assertions = schema.validate(input, InputFormat.JSON); + assertEquals(DialectId.DRAFT_7, schema.getSchemaContext().getDialect().getId()); + List assertions = schema.validate(input, InputFormat.JSON); assertEquals(1, assertions.size()); // The example-ref.json schema defines $schema with Draft 2019-09 - JsonSchema refSchema = schema.getValidationContext().getSchemaResources().get("https://www.example.org/example-ref.json#"); - assertEquals(SchemaId.V201909, refSchema.getValidationContext().getMetaSchema().getIri()); + Schema refSchema = schema.getSchemaContext().getSchemaResources().get("https://www.example.org/example-ref.json#"); + assertEquals(DialectId.DRAFT_2019_09, refSchema.getSchemaContext().getDialect().getId()); } @Test void exampleClasspath() { // This creates a schema factory that will use Draft 2012-12 as the default if $schema is not specified in the initial schema - JsonSchemaFactory jsonSchemaFactory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema schema = jsonSchemaFactory.getSchema(SchemaLocation.of("classpath:schema/example-main.json"), config); + SchemaRegistry jsonSchemaFactory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12); + Schema schema = jsonSchemaFactory.getSchema(SchemaLocation.of("classpath:schema/example-main.json")); String input = "{\r\n" + " \"DriverProperties\": {\r\n" + " \"CommonProperties\": {\r\n" @@ -63,12 +61,12 @@ void exampleClasspath() { + " }\r\n" + "}"; // The example-main.json schema defines $schema with Draft 07 - assertEquals(SchemaId.V7, schema.getValidationContext().getMetaSchema().getIri()); - List assertions = schema.validate(input, InputFormat.JSON); + assertEquals(DialectId.DRAFT_7, schema.getSchemaContext().getDialect().getId()); + List assertions = schema.validate(input, InputFormat.JSON); assertEquals(1, assertions.size()); // The example-ref.json schema defines $schema with Draft 2019-09 - JsonSchema refSchema = schema.getValidationContext().getSchemaResources().get("classpath:schema/example-ref.json#"); - assertEquals(SchemaId.V201909, refSchema.getValidationContext().getMetaSchema().getIri()); + Schema refSchema = schema.getSchemaContext().getSchemaResources().get("classpath:schema/example-ref.json#"); + assertEquals(DialectId.DRAFT_2019_09, refSchema.getSchemaContext().getDialect().getId()); } } diff --git a/src/test/java/com/networknt/schema/ExclusiveMinimumValidatorTest.java b/src/test/java/com/networknt/schema/ExclusiveMinimumValidatorTest.java index 3d75bc16f..48e17dfff 100644 --- a/src/test/java/com/networknt/schema/ExclusiveMinimumValidatorTest.java +++ b/src/test/java/com/networknt/schema/ExclusiveMinimumValidatorTest.java @@ -22,7 +22,9 @@ import org.junit.jupiter.api.Test; -import com.networknt.schema.SpecVersion.VersionFlag; +import com.networknt.schema.dialect.Dialect; +import com.networknt.schema.dialect.Dialects; +import com.networknt.schema.keyword.DisallowUnknownKeywordFactory; /** * Test ExclusiveMinimumValidator validator. @@ -40,17 +42,16 @@ void draftV4ShouldHaveExclusiveMinimum() { " }" + " }" + "}"; - JsonMetaSchema metaSchema = JsonMetaSchema.builder(JsonMetaSchema.getV4()) + Dialect dialect = Dialect.builder(Dialects.getDraft4()) .unknownKeywordFactory(DisallowUnknownKeywordFactory.getInstance()).build(); - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V4, - builder -> builder.metaSchema(metaSchema)); - JsonSchema schema = factory.getSchema(schemaData); + SchemaRegistry factory = SchemaRegistry.withDialect(dialect); + Schema schema = factory.getSchema(schemaData); String inputData = "{\"value1\":0}"; String validData = "{\"value1\":0.1}"; - List messages = schema.validate(inputData, InputFormat.JSON); + List messages = schema.validate(inputData, InputFormat.JSON); assertEquals(1, messages.size()); - assertEquals(1, messages.stream().filter(m -> "minimum".equals(m.getType())).count()); + assertEquals(1, messages.stream().filter(m -> "minimum".equals(m.getKeyword())).count()); messages = schema.validate(validData, InputFormat.JSON); assertEquals(0, messages.size()); @@ -68,11 +69,10 @@ void draftV6ShouldNotAllowExclusiveMinimumBoolean() { " }" + " }" + "}"; - JsonMetaSchema metaSchema = JsonMetaSchema.builder(JsonMetaSchema.getV6()) + Dialect dialect = Dialect.builder(Dialects.getDraft6()) .unknownKeywordFactory(DisallowUnknownKeywordFactory.getInstance()).build(); - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V6, - builder -> builder.metaSchema(metaSchema)); - assertThrows(JsonSchemaException.class, () -> factory.getSchema(schemaData)); + SchemaRegistry factory = SchemaRegistry.withDialect(dialect); + assertThrows(SchemaException.class, () -> factory.getSchema(schemaData)); } @Test @@ -87,10 +87,9 @@ void draftV7ShouldNotAllowExclusiveMinimumBoolean() { " }" + " }" + "}"; - JsonMetaSchema metaSchema = JsonMetaSchema.builder(JsonMetaSchema.getV7()) + Dialect dialect = Dialect.builder(Dialects.getDraft7()) .unknownKeywordFactory(DisallowUnknownKeywordFactory.getInstance()).build(); - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V7, - builder -> builder.metaSchema(metaSchema)); - assertThrows(JsonSchemaException.class, () -> factory.getSchema(schemaData)); + SchemaRegistry factory = SchemaRegistry.withDialect(dialect); + assertThrows(SchemaException.class, () -> factory.getSchema(schemaData)); } } diff --git a/src/test/java/com/networknt/schema/FormatKeywordFactoryTest.java b/src/test/java/com/networknt/schema/FormatKeywordFactoryTest.java index c709b874a..e780962d2 100644 --- a/src/test/java/com/networknt/schema/FormatKeywordFactoryTest.java +++ b/src/test/java/com/networknt/schema/FormatKeywordFactoryTest.java @@ -22,7 +22,12 @@ import org.junit.jupiter.api.Test; import com.fasterxml.jackson.databind.JsonNode; -import com.networknt.schema.SpecVersion.VersionFlag; +import com.networknt.schema.dialect.Dialect; +import com.networknt.schema.dialect.Dialects; +import com.networknt.schema.format.Format; +import com.networknt.schema.keyword.FormatKeyword; +import com.networknt.schema.keyword.KeywordValidator; +import com.networknt.schema.path.NodePath; class FormatKeywordFactoryTest { @@ -32,20 +37,19 @@ public CustomFormatKeyword(Map formats) { } @Override - public JsonValidator newValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) { + public KeywordValidator newValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, Schema parentSchema, SchemaContext schemaContext) { throw new IllegalArgumentException(); } } @Test void shouldUseFormatKeyword() { - JsonMetaSchema metaSchema = JsonMetaSchema.builder(JsonMetaSchema.getV202012()) + Dialect dialect = Dialect.builder(Dialects.getDraft202012()) .formatKeywordFactory(CustomFormatKeyword::new).build(); - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012, - builder -> builder.metaSchema(metaSchema)); + SchemaRegistry factory = SchemaRegistry.withDialect(dialect); String schemaData = "{\r\n" + " \"format\": \"hello\"\r\n" + "}"; - assertThrows(JsonSchemaException.class, () -> factory.getSchema(schemaData)); + assertThrows(SchemaException.class, () -> factory.getSchema(schemaData)); } } diff --git a/src/test/java/com/networknt/schema/FormatValidatorTest.java b/src/test/java/com/networknt/schema/FormatValidatorTest.java index 801555e1a..37a80e6ca 100644 --- a/src/test/java/com/networknt/schema/FormatValidatorTest.java +++ b/src/test/java/com/networknt/schema/FormatValidatorTest.java @@ -28,9 +28,12 @@ import org.junit.jupiter.params.provider.EnumSource; import com.fasterxml.jackson.databind.JsonNode; -import com.networknt.schema.SpecVersion.VersionFlag; -import com.networknt.schema.format.PatternFormat; +import com.networknt.schema.dialect.Dialect; +import com.networknt.schema.dialect.Dialects; +import com.networknt.schema.format.Format; import com.networknt.schema.output.OutputUnit; +import com.networknt.schema.utils.JsonType; +import com.networknt.schema.utils.TypeFactory; /** * Test for format validator. @@ -41,9 +44,9 @@ void unknownFormatNoVocab() { String schemaData = "{\r\n" + " \"format\":\"unknown\"\r\n" + "}"; - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData); - List messages = schema.validate("\"hello\"", InputFormat.JSON, executionContext -> { - executionContext.getExecutionConfig().setFormatAssertionsEnabled(true); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12).getSchema(schemaData); + List messages = schema.validate("\"hello\"", InputFormat.JSON, executionContext -> { + executionContext.executionConfig(executionConfig -> executionConfig.formatAssertionsEnabled(true)); }); assertEquals(0, messages.size()); } @@ -53,10 +56,10 @@ void unknownFormatNoVocabStrictTrue() { String schemaData = "{\r\n" + " \"format\":\"unknown\"\r\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().strict("format", true).build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, config); - List messages = schema.validate("\"hello\"", InputFormat.JSON, executionContext -> { - executionContext.getExecutionConfig().setFormatAssertionsEnabled(true); + SchemaRegistryConfig config = SchemaRegistryConfig.builder().strict("format", true).build(); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12, builder -> builder.schemaRegistryConfig(config)).getSchema(schemaData); + List messages = schema.validate("\"hello\"", InputFormat.JSON, executionContext -> { + executionContext.executionConfig(executionConfig -> executionConfig.formatAssertionsEnabled(true)); }); assertEquals(1, messages.size()); assertEquals("format.unknown", messages.iterator().next().getMessageKey()); @@ -82,13 +85,12 @@ void unknownFormatAssertionsVocab() { + " \"$schema\": \"https://www.example.com/format-assertion/schema\",\r\n" + " \"format\":\"unknown\"\r\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema schema = JsonSchemaFactory - .getInstance(VersionFlag.V202012, + Schema schema = SchemaRegistry + .withDefaultDialect(SpecificationVersion.DRAFT_2020_12, builder -> builder - .schemaLoaders(schemaLoaders -> schemaLoaders.schemas(Collections.singletonMap("https://www.example.com/format-assertion/schema", metaSchemaData)))) - .getSchema(schemaData, config); - List messages = schema.validate("\"hello\"", InputFormat.JSON); + .resourceLoaders(resourceLoaders -> resourceLoaders.resources(Collections.singletonMap("https://www.example.com/format-assertion/schema", metaSchemaData)))) + .getSchema(schemaData); + List messages = schema.validate("\"hello\"", InputFormat.JSON); assertEquals(1, messages.size()); assertEquals("format.unknown", messages.iterator().next().getMessageKey()); } @@ -98,11 +100,12 @@ void unknownFormatShouldCollectAnnotations() { String schemaData = "{\r\n" + " \"format\":\"unknown\"\r\n" + "}"; - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData); - OutputUnit outputUnit = schema.validate("\"hello\"", InputFormat.JSON, OutputFormat.HIERARCHICAL, executionContext -> { - executionContext.getExecutionConfig().setAnnotationCollectionEnabled(true); - executionContext.getExecutionConfig().setAnnotationCollectionFilter(keyword -> true); - }); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12).getSchema(schemaData); + OutputUnit outputUnit = schema.validate("\"hello\"", InputFormat.JSON, OutputFormat.HIERARCHICAL, + executionContext -> { + executionContext.executionConfig(executionConfig -> executionConfig + .annotationCollectionEnabled(true).annotationCollectionFilter(keyword -> true)); + }); assertEquals("unknown", outputUnit.getAnnotations().get("format")); assertTrue(outputUnit.isValid()); // as no assertion vocab and assertions not enabled } @@ -141,45 +144,14 @@ void formatAssertions(FormatInput formatInput) { + " \"type\": \"string\",\r\n" + " \"format\": \""+formatInput.format+"\"\r\n" + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema schema = factory.getSchema(formatSchema, config); - List messages = schema.validate("\"inval!i:d^(abc]\"", InputFormat.JSON, executionConfiguration -> { - executionConfiguration.getExecutionConfig().setFormatAssertionsEnabled(true); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12); + Schema schema = factory.getSchema(formatSchema); + List messages = schema.validate("\"inval!i:d^(abc]\"", InputFormat.JSON, executionConfiguration -> { + executionConfiguration.executionConfig(executionConfig -> executionConfig.formatAssertionsEnabled(true)); }); assertFalse(messages.isEmpty()); } - /** - * This tests that the changes to use message key doesn't cause a regression to - * the existing message. - */ - @SuppressWarnings("deprecation") - @Test - void patternFormatDeprecated() { - JsonMetaSchema customMetaSchema = JsonMetaSchema - .builder("https://www.example.com/schema", JsonMetaSchema.getV7()) - .formats(formats -> { - PatternFormat format = new PatternFormat("custom", "test", "must be test"); - formats.put(format.getName(), format); - }) - .build(); - - JsonSchemaFactory factory = new JsonSchemaFactory.Builder().defaultMetaSchemaIri(customMetaSchema.getIri()) - .metaSchema(customMetaSchema).build(); - String formatSchema = "{\r\n" - + " \"type\": \"string\",\r\n" - + " \"format\": \"custom\"\r\n" - + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema schema = factory.getSchema(formatSchema, config); - List messages = schema.validate("\"inval!i:d^(abc]\"", InputFormat.JSON, executionConfiguration -> { - executionConfiguration.getExecutionConfig().setFormatAssertionsEnabled(true); - }); - assertFalse(messages.isEmpty()); - assertEquals(": does not match the custom pattern must be test", messages.iterator().next().getMessage()); - } - static class CustomNumberFormat implements Format { private final BigDecimal compare; @@ -188,8 +160,8 @@ static class CustomNumberFormat implements Format { } @Override - public boolean matches(ExecutionContext executionContext, ValidationContext validationContext, JsonNode value) { - JsonType nodeType = TypeFactory.getValueNodeType(value, validationContext.getConfig()); + public boolean matches(ExecutionContext executionContext, SchemaContext schemaContext, JsonNode value) { + JsonType nodeType = TypeFactory.getValueNodeType(value, schemaContext.getSchemaRegistryConfig()); if (nodeType != JsonType.NUMBER && nodeType != JsonType.INTEGER) { return true; } @@ -202,33 +174,36 @@ public boolean matches(ExecutionContext executionContext, ValidationContext vali public String getName() { return "custom-number"; } + + @Override + public String getMessageKey() { + return "does not match the {0} pattern"; + } } @Test void shouldAllowNumberFormat() { - JsonMetaSchema customMetaSchema = JsonMetaSchema - .builder("https://www.example.com/schema", JsonMetaSchema.getV7()) + Dialect customDialect = Dialect + .builder("https://www.example.com/schema", Dialects.getDraft7()) .formats(formats -> { CustomNumberFormat format = new CustomNumberFormat(new BigDecimal("12345")); formats.put(format.getName(), format); }) .build(); - JsonSchemaFactory factory = new JsonSchemaFactory.Builder().defaultMetaSchemaIri(customMetaSchema.getIri()) - .metaSchema(customMetaSchema).build(); + SchemaRegistry factory = SchemaRegistry.withDialect(customDialect); String formatSchema = "{\r\n" + " \"type\": \"number\",\r\n" + " \"format\": \"custom-number\"\r\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema schema = factory.getSchema(formatSchema, config); - List messages = schema.validate("123451", InputFormat.JSON, executionConfiguration -> { - executionConfiguration.getExecutionConfig().setFormatAssertionsEnabled(true); + Schema schema = factory.getSchema(formatSchema); + List messages = schema.validate("123451", InputFormat.JSON, executionConfiguration -> { + executionConfiguration.executionConfig(executionConfig -> executionConfig.formatAssertionsEnabled(true)); }); assertFalse(messages.isEmpty()); - assertEquals(": does not match the custom-number pattern ", messages.iterator().next().getMessage()); + assertEquals(": does not match the custom-number pattern", messages.iterator().next().toString()); messages = schema.validate("12345", InputFormat.JSON, executionConfiguration -> { - executionConfiguration.getExecutionConfig().setFormatAssertionsEnabled(true); + executionConfiguration.executionConfig(executionConfig -> executionConfig.formatAssertionsEnabled(true)); }); assertTrue(messages.isEmpty()); @@ -239,9 +214,9 @@ void draft7DisableFormat() { String schemaData = "{\r\n" + " \"format\":\"uri\"\r\n" + "}"; - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V7).getSchema(schemaData); - List messages = schema.validate("\"hello\"", InputFormat.JSON, executionContext -> { - executionContext.getExecutionConfig().setFormatAssertionsEnabled(false); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7).getSchema(schemaData); + List messages = schema.validate("\"hello\"", InputFormat.JSON, executionContext -> { + executionContext.executionConfig(executionConfig -> executionConfig.formatAssertionsEnabled(false)); }); assertEquals(0, messages.size()); } diff --git a/src/test/java/com/networknt/schema/IfValidatorTest.java b/src/test/java/com/networknt/schema/IfValidatorTest.java index 04573e8ee..68b3a593c 100644 --- a/src/test/java/com/networknt/schema/IfValidatorTest.java +++ b/src/test/java/com/networknt/schema/IfValidatorTest.java @@ -24,8 +24,11 @@ import org.junit.jupiter.api.Test; -import com.networknt.schema.SpecVersion.VersionFlag; -import com.networknt.schema.walk.JsonSchemaWalkListener; +import com.networknt.schema.keyword.KeywordType; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.walk.WalkListener; +import com.networknt.schema.walk.KeywordWalkListenerRunner; +import com.networknt.schema.walk.WalkConfig; import com.networknt.schema.walk.WalkEvent; import com.networknt.schema.walk.WalkFlow; @@ -47,31 +50,33 @@ void walkValidateThen() { + " \"type\": \"number\"\r\n" + " }\r\n" + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder() - .keywordWalkListener(ValidatorTypeCode.TYPE.getValue(), new JsonSchemaWalkListener() { + KeywordWalkListenerRunner keywordWalkListenerRunner = KeywordWalkListenerRunner.builder() + .keywordWalkListener(KeywordType.TYPE.getValue(), new WalkListener() { @Override public WalkFlow onWalkStart(WalkEvent walkEvent) { return WalkFlow.CONTINUE; } @Override - public void onWalkEnd(WalkEvent walkEvent, List validationMessages) { + public void onWalkEnd(WalkEvent walkEvent, List errors) { @SuppressWarnings("unchecked") List types = (List) walkEvent.getExecutionContext() .getCollectorContext() - .getCollectorMap() - .computeIfAbsent("types", key -> new ArrayList()); + .getData() + .computeIfAbsent("types", key -> new ArrayList()); types.add(walkEvent); } }) .build(); - JsonSchema schema = factory.getSchema(schemaData, config); - ValidationResult result = schema.walk("\"false\"", InputFormat.JSON, true); - assertFalse(result.getValidationMessages().isEmpty()); + WalkConfig walkConfig = WalkConfig.builder() + .keywordWalkListenerRunner(keywordWalkListenerRunner) + .build(); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12); + Schema schema = factory.getSchema(schemaData); + Result result = schema.walk("\"false\"", InputFormat.JSON, true, executionContext -> executionContext.setWalkConfig(walkConfig)); + assertFalse(result.getErrors().isEmpty()); - @SuppressWarnings("unchecked") - List types = (List) result.getExecutionContext().getCollectorContext().get("types"); + List types = result.getExecutionContext().getCollectorContext().get("types"); assertEquals(1, types.size()); assertEquals("", types.get(0).getInstanceLocation().toString()); assertEquals("/then", types.get(0).getSchema().getEvaluationPath().toString()); @@ -90,28 +95,31 @@ void walkValidateElse() { + " \"type\": \"number\"\r\n" + " }\r\n" + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder() - .keywordWalkListener(ValidatorTypeCode.TYPE.getValue(), new JsonSchemaWalkListener() { + KeywordWalkListenerRunner keywordWalkListenerRunner = KeywordWalkListenerRunner.builder() + .keywordWalkListener(KeywordType.TYPE.getValue(), new WalkListener() { @Override public WalkFlow onWalkStart(WalkEvent walkEvent) { return WalkFlow.CONTINUE; } @Override - public void onWalkEnd(WalkEvent walkEvent, List validationMessages) { + public void onWalkEnd(WalkEvent walkEvent, List errors) { @SuppressWarnings("unchecked") List types = (List) walkEvent.getExecutionContext() .getCollectorContext() - .getCollectorMap() - .computeIfAbsent("types", key -> new ArrayList()); + .getData() + .computeIfAbsent("types", key -> new ArrayList()); types.add(walkEvent); } }) .build(); - JsonSchema schema = factory.getSchema(schemaData, config); - ValidationResult result = schema.walk("\"hello\"", InputFormat.JSON, true); - assertFalse(result.getValidationMessages().isEmpty()); + WalkConfig walkConfig = WalkConfig.builder() + .keywordWalkListenerRunner(keywordWalkListenerRunner) + .build(); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12); + Schema schema = factory.getSchema(schemaData); + Result result = schema.walk("\"hello\"", InputFormat.JSON, true, executionContext -> executionContext.setWalkConfig(walkConfig)); + assertFalse(result.getErrors().isEmpty()); @SuppressWarnings("unchecked") List types = (List) result.getExecutionContext().getCollectorContext().get("types"); @@ -133,28 +141,31 @@ void walkValidateNull() { + " \"type\": \"number\"\r\n" + " }\r\n" + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder() - .keywordWalkListener(ValidatorTypeCode.TYPE.getValue(), new JsonSchemaWalkListener() { + KeywordWalkListenerRunner keywordWalkListenerRunner = KeywordWalkListenerRunner.builder() + .keywordWalkListener(KeywordType.TYPE.getValue(), new WalkListener() { @Override public WalkFlow onWalkStart(WalkEvent walkEvent) { return WalkFlow.CONTINUE; } @Override - public void onWalkEnd(WalkEvent walkEvent, List validationMessages) { + public void onWalkEnd(WalkEvent walkEvent, List errors) { @SuppressWarnings("unchecked") List types = (List) walkEvent.getExecutionContext() .getCollectorContext() - .getCollectorMap() - .computeIfAbsent("types", key -> new ArrayList()); + .getData() + .computeIfAbsent("types", key -> new ArrayList()); types.add(walkEvent); } }) .build(); - JsonSchema schema = factory.getSchema(schemaData, config); - ValidationResult result = schema.walk(null, true); - assertTrue(result.getValidationMessages().isEmpty()); + WalkConfig walkConfig = WalkConfig.builder() + .keywordWalkListenerRunner(keywordWalkListenerRunner) + .build(); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12); + Schema schema = factory.getSchema(schemaData); + Result result = schema.walk(null, true, executionContext -> executionContext.setWalkConfig(walkConfig)); + assertTrue(result.getErrors().isEmpty()); @SuppressWarnings("unchecked") List types = (List) result.getExecutionContext().getCollectorContext().get("types"); @@ -174,28 +185,31 @@ void walkNoValidate() { + " \"type\": \"number\"\r\n" + " }\r\n" + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder() - .keywordWalkListener(ValidatorTypeCode.TYPE.getValue(), new JsonSchemaWalkListener() { + KeywordWalkListenerRunner keywordWalkListenerRunner = KeywordWalkListenerRunner.builder() + .keywordWalkListener(KeywordType.TYPE.getValue(), new WalkListener() { @Override public WalkFlow onWalkStart(WalkEvent walkEvent) { return WalkFlow.CONTINUE; } @Override - public void onWalkEnd(WalkEvent walkEvent, List validationMessages) { + public void onWalkEnd(WalkEvent walkEvent, List errors) { @SuppressWarnings("unchecked") List types = (List) walkEvent.getExecutionContext() .getCollectorContext() - .getCollectorMap() - .computeIfAbsent("types", key -> new ArrayList()); + .getData() + .computeIfAbsent("types", key -> new ArrayList()); types.add(walkEvent); } }) .build(); - JsonSchema schema = factory.getSchema(schemaData, config); - ValidationResult result = schema.walk("\"false\"", InputFormat.JSON, false); - assertTrue(result.getValidationMessages().isEmpty()); + WalkConfig walkConfig = WalkConfig.builder() + .keywordWalkListenerRunner(keywordWalkListenerRunner) + .build(); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12); + Schema schema = factory.getSchema(schemaData); + Result result = schema.walk("\"false\"", InputFormat.JSON, false, executionContext -> executionContext.setWalkConfig(walkConfig)); + assertTrue(result.getErrors().isEmpty()); @SuppressWarnings("unchecked") List types = (List) result.getExecutionContext().getCollectorContext().get("types"); diff --git a/src/test/java/com/networknt/schema/Issue1091Test.java b/src/test/java/com/networknt/schema/Issue1091Test.java index 2f11b5c53..854e0e538 100644 --- a/src/test/java/com/networknt/schema/Issue1091Test.java +++ b/src/test/java/com/networknt/schema/Issue1091Test.java @@ -24,23 +24,22 @@ import org.junit.jupiter.api.Test; import com.fasterxml.jackson.databind.JsonNode; -import com.networknt.schema.SpecVersion.VersionFlag; import com.networknt.schema.serialization.JsonMapperFactory; class Issue1091Test { @Test @Disabled // Disabled as this test takes quite long to run for ci void testHasAdjacentKeywordInEvaluationPath() throws Exception { - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().cacheRefs(false).build(); + SchemaRegistryConfig config = SchemaRegistryConfig.builder().cacheRefs(false).build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V4) - .getSchema(SchemaLocation.of("classpath:schema/issue1091.json"), config); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_4, builder -> builder.schemaRegistryConfig(config)) + .getSchema(SchemaLocation.of("classpath:schema/issue1091.json")); JsonNode node = JsonMapperFactory.getInstance() .readTree(Issue1091Test.class.getClassLoader().getResource("data/issue1091.json")); List messages = schema.validate(node) .stream() - .map(ValidationMessage::getMessage) + .map(Error::getMessage) .collect(Collectors.toList()); assertEquals(0, messages.size()); diff --git a/src/test/java/com/networknt/schema/Issue255Test.java b/src/test/java/com/networknt/schema/Issue255Test.java index 4af40b527..dc6dbba81 100644 --- a/src/test/java/com/networknt/schema/Issue255Test.java +++ b/src/test/java/com/networknt/schema/Issue255Test.java @@ -24,8 +24,8 @@ import java.util.List; class Issue255Test { - protected JsonSchema getJsonSchemaFromStreamContent(InputStream schemaContent) { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7); + protected Schema getJsonSchemaFromStreamContent(InputStream schemaContent) { + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7); return factory.getSchema(schemaContent); } @@ -40,10 +40,10 @@ void shouldFailWhenRequiredPropertiesDoNotExistInReferencedSubSchema() throws Ex String schemaPath = "/draft2019-09/issue255.json"; String dataPath = "/data/issue255.json"; InputStream schemaInputStream = getClass().getResourceAsStream(schemaPath); - JsonSchema schema = getJsonSchemaFromStreamContent(schemaInputStream); + Schema schema = getJsonSchemaFromStreamContent(schemaInputStream); InputStream dataInputStream = getClass().getResourceAsStream(dataPath); JsonNode node = getJsonNodeFromStreamContent(dataInputStream); - List errors = schema.validate(node); + List errors = schema.validate(node); Assertions.assertEquals(2, errors.size()); } } diff --git a/src/test/java/com/networknt/schema/Issue285Test.java b/src/test/java/com/networknt/schema/Issue285Test.java index c9611d073..ca2a87ce8 100644 --- a/src/test/java/com/networknt/schema/Issue285Test.java +++ b/src/test/java/com/networknt/schema/Issue285Test.java @@ -12,9 +12,9 @@ class Issue285Test { private final ObjectMapper mapper = new ObjectMapper(); - private final JsonSchemaFactory schemaFactory = JsonSchemaFactory - .builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V201909)) - .schemaMappers(schemaMappers -> schemaMappers + private final SchemaRegistry schemaFactory = SchemaRegistry + .builder(SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2019_09)) + .schemaIdResolvers(schemaIdResolvers -> schemaIdResolvers .mapPrefix("http://json-schema.org", "resource:") .mapPrefix("https://json-schema.org", "resource:")) .build(); @@ -56,12 +56,12 @@ class Issue285Test { // The result is as expected, and we get a validation error. @Test void nestedValidation() throws IOException { - JsonSchema jsonSchema = schemaFactory.getSchema(schemaStr); - List validationMessages = jsonSchema.validate(mapper.readTree(person)); + Schema jsonSchema = schemaFactory.getSchema(schemaStr); + List errors = jsonSchema.validate(mapper.readTree(person)); - System.err.println("\n" + Arrays.toString(validationMessages.toArray())); + System.err.println("\n" + Arrays.toString(errors.toArray())); - assertFalse(validationMessages.isEmpty()); + assertFalse(errors.isEmpty()); } @@ -97,12 +97,12 @@ void nestedValidation() throws IOException { @Test void nestedTypeValidation() throws IOException { SchemaLocation uri = SchemaLocation.of("https://json-schema.org/draft/2019-09/schema"); - JsonSchema jsonSchema = schemaFactory.getSchema(uri); - List validationMessages = jsonSchema.validate(mapper.readTree(invalidNestedSchema)); + Schema jsonSchema = schemaFactory.getSchema(uri); + List errors = jsonSchema.validate(mapper.readTree(invalidNestedSchema)); - System.err.println("\n" + Arrays.toString(validationMessages.toArray())); + System.err.println("\n" + Arrays.toString(errors.toArray())); - assertFalse(validationMessages.isEmpty()); + assertFalse(errors.isEmpty()); } String invalidSchema = "{\n" + @@ -120,11 +120,11 @@ void nestedTypeValidation() throws IOException { @Test void typeValidation() throws IOException { SchemaLocation uri = SchemaLocation.of("https://json-schema.org/draft/2019-09/schema"); - JsonSchema jsonSchema = schemaFactory.getSchema(uri); - List validationMessages = jsonSchema.validate(mapper.readTree(invalidSchema)); + Schema jsonSchema = schemaFactory.getSchema(uri); + List errors = jsonSchema.validate(mapper.readTree(invalidSchema)); - System.err.println("\n" + Arrays.toString(validationMessages.toArray())); + System.err.println("\n" + Arrays.toString(errors.toArray())); - assertFalse(validationMessages.isEmpty()); + assertFalse(errors.isEmpty()); } } diff --git a/src/test/java/com/networknt/schema/Issue295Test.java b/src/test/java/com/networknt/schema/Issue295Test.java index 79f85f7a9..27e6d9a36 100644 --- a/src/test/java/com/networknt/schema/Issue295Test.java +++ b/src/test/java/com/networknt/schema/Issue295Test.java @@ -9,8 +9,8 @@ import java.util.List; class Issue295Test { - protected JsonSchema getJsonSchemaFromStreamContentV7(InputStream schemaContent) { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7); + protected Schema getJsonSchemaFromStreamContentV7(InputStream schemaContent) { + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7); return factory.getSchema(schemaContent); } @@ -25,10 +25,10 @@ void shouldWorkV7() throws Exception { String schemaPath = "/schema/issue295-v7.json"; String dataPath = "/data/issue295.json"; InputStream schemaInputStream = getClass().getResourceAsStream(schemaPath); - JsonSchema schema = getJsonSchemaFromStreamContentV7(schemaInputStream); + Schema schema = getJsonSchemaFromStreamContentV7(schemaInputStream); InputStream dataInputStream = getClass().getResourceAsStream(dataPath); JsonNode node = getJsonNodeFromStreamContent(dataInputStream); - List errors = schema.validate(node); + List errors = schema.validate(node); Assertions.assertEquals(0, errors.size()); } } diff --git a/src/test/java/com/networknt/schema/Issue313Test.java b/src/test/java/com/networknt/schema/Issue313Test.java index 002c5cd67..430f9d44b 100644 --- a/src/test/java/com/networknt/schema/Issue313Test.java +++ b/src/test/java/com/networknt/schema/Issue313Test.java @@ -10,13 +10,13 @@ import java.util.List; class Issue313Test { - protected JsonSchema getJsonSchemaFromStreamContentV7(InputStream schemaContent) { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7); + protected Schema getJsonSchemaFromStreamContentV7(InputStream schemaContent) { + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7); return factory.getSchema(schemaContent); } - protected JsonSchema getJsonSchemaFromStreamContentV201909(InputStream schemaContent) { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V201909); + protected Schema getJsonSchemaFromStreamContentV201909(InputStream schemaContent) { + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2019_09); return factory.getSchema(schemaContent); } @@ -32,10 +32,10 @@ void shouldFailV201909() throws Exception { String schemaPath = "/schema/issue313-2019-09.json"; String dataPath = "/data/issue313.json"; InputStream schemaInputStream = getClass().getResourceAsStream(schemaPath); - JsonSchema schema = getJsonSchemaFromStreamContentV201909(schemaInputStream); + Schema schema = getJsonSchemaFromStreamContentV201909(schemaInputStream); InputStream dataInputStream = getClass().getResourceAsStream(dataPath); JsonNode node = getJsonNodeFromStreamContent(dataInputStream); - List errors = schema.validate(node); + List errors = schema.validate(node); Assertions.assertEquals(2, errors.size()); } @@ -44,10 +44,10 @@ void shouldFailV7() throws Exception { String schemaPath = "/schema/issue313-v7.json"; String dataPath = "/data/issue313.json"; InputStream schemaInputStream = getClass().getResourceAsStream(schemaPath); - JsonSchema schema = getJsonSchemaFromStreamContentV7(schemaInputStream); + Schema schema = getJsonSchemaFromStreamContentV7(schemaInputStream); InputStream dataInputStream = getClass().getResourceAsStream(dataPath); JsonNode node = getJsonNodeFromStreamContent(dataInputStream); - List errors = schema.validate(node); + List errors = schema.validate(node); Assertions.assertEquals(2, errors.size()); } diff --git a/src/test/java/com/networknt/schema/Issue314Test.java b/src/test/java/com/networknt/schema/Issue314Test.java index 21fe077ac..44bdfd1d3 100644 --- a/src/test/java/com/networknt/schema/Issue314Test.java +++ b/src/test/java/com/networknt/schema/Issue314Test.java @@ -4,21 +4,22 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import com.networknt.schema.dialect.Dialect; +import com.networknt.schema.dialect.Dialects; + class Issue314Test { - private static final JsonSchemaFactory FACTORY = - JsonSchemaFactory.builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7)) - .metaSchema( - JsonMetaSchema.builder( + private static final SchemaRegistry REGISTRY = + SchemaRegistry.withDialect( + Dialect.builder( "http://iglucentral.com/schemas/com.snowplowanalytics.self-desc/schema/jsonschema/1-0-0#", - JsonMetaSchema.getV7()) - .build()) - .build(); + Dialects.getDraft7()) + .build()); @Test void testNormalizeHttpOnly() { String schemaPath = "/schema/issue314-v7.json"; InputStream schemaInputStream = getClass().getResourceAsStream(schemaPath); - JsonSchema schema = FACTORY.getSchema(schemaInputStream); + Schema schema = REGISTRY.getSchema(schemaInputStream); Assertions.assertNotNull(schema); } diff --git a/src/test/java/com/networknt/schema/Issue327Test.java b/src/test/java/com/networknt/schema/Issue327Test.java index ba74134db..2c80e418e 100644 --- a/src/test/java/com/networknt/schema/Issue327Test.java +++ b/src/test/java/com/networknt/schema/Issue327Test.java @@ -9,8 +9,8 @@ import java.util.List; class Issue327Test { - protected JsonSchema getJsonSchemaFromStreamContentV7(InputStream schemaContent) { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7); + protected Schema getJsonSchemaFromStreamContentV7(InputStream schemaContent) { + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7); return factory.getSchema(schemaContent); } @@ -25,10 +25,10 @@ void shouldWorkV7() throws Exception { String schemaPath = "/schema/issue327-v7.json"; String dataPath = "/data/issue327.json"; InputStream schemaInputStream = getClass().getResourceAsStream(schemaPath); - JsonSchema schema = getJsonSchemaFromStreamContentV7(schemaInputStream); + Schema schema = getJsonSchemaFromStreamContentV7(schemaInputStream); InputStream dataInputStream = getClass().getResourceAsStream(dataPath); JsonNode node = getJsonNodeFromStreamContent(dataInputStream); - List errors = schema.validate(node); + List errors = schema.validate(node); Assertions.assertEquals(0, errors.size()); } } diff --git a/src/test/java/com/networknt/schema/Issue342Test.java b/src/test/java/com/networknt/schema/Issue342Test.java index 89e3f7e9c..94ef7e0a5 100644 --- a/src/test/java/com/networknt/schema/Issue342Test.java +++ b/src/test/java/com/networknt/schema/Issue342Test.java @@ -10,8 +10,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; class Issue342Test { - protected JsonSchema getJsonSchemaFromStreamContentV7(InputStream schemaContent) { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7); + protected Schema getJsonSchemaFromStreamContentV7(InputStream schemaContent) { + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7); return factory.getSchema(schemaContent); } @@ -26,13 +26,13 @@ void propertyNameEnumShouldFailV7() throws Exception { String schemaPath = "/schema/issue342-v7.json"; String dataPath = "/data/issue342.json"; InputStream schemaInputStream = getClass().getResourceAsStream(schemaPath); - JsonSchema schema = getJsonSchemaFromStreamContentV7(schemaInputStream); + Schema schema = getJsonSchemaFromStreamContentV7(schemaInputStream); InputStream dataInputStream = getClass().getResourceAsStream(dataPath); JsonNode node = getJsonNodeFromStreamContent(dataInputStream); - List errors = schema.validate(node); + List errors = schema.validate(node); Assertions.assertEquals(1, errors.size()); - final ValidationMessage error = errors.iterator().next(); - Assertions.assertEquals("$", error.getInstanceLocation().toString()); - Assertions.assertEquals("$: property 'z' name is not valid: does not have a value in the enumeration [\"a\", \"b\", \"c\"]", error.getMessage()); + final Error error = errors.iterator().next(); + Assertions.assertEquals("", error.getInstanceLocation().toString()); + Assertions.assertEquals(": property 'z' name is not valid: does not have a value in the enumeration [\"a\", \"b\", \"c\"]", error.toString()); } } diff --git a/src/test/java/com/networknt/schema/Issue347Test.java b/src/test/java/com/networknt/schema/Issue347Test.java index c5e47c386..649b82657 100644 --- a/src/test/java/com/networknt/schema/Issue347Test.java +++ b/src/test/java/com/networknt/schema/Issue347Test.java @@ -11,13 +11,13 @@ class Issue347Test { @Test void failure() { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7); - assertThrows(JsonSchemaException.class, () -> factory.getSchema(Thread.currentThread().getContextClassLoader().getResourceAsStream("schema/issue347-v7.json"))); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7); + assertThrows(SchemaException.class, () -> factory.getSchema(Thread.currentThread().getContextClassLoader().getResourceAsStream("schema/issue347-v7.json"))); try { factory.getSchema(Thread.currentThread().getContextClassLoader().getResourceAsStream("schema/issue347-v7.json")); } catch (Throwable e) { - assertThat(e, instanceOf(JsonSchemaException.class)); - assertEquals("/$id: 'test' is not a valid $id", e.getMessage()); + assertThat(e, instanceOf(SchemaException.class)); + assertEquals("/$id: 'test' is not a valid $id", ((SchemaException) e).getError().toString()); } } } diff --git a/src/test/java/com/networknt/schema/Issue366FailFastTest.java b/src/test/java/com/networknt/schema/Issue366FailFastTest.java index 3fde9a6d8..7c41e4693 100644 --- a/src/test/java/com/networknt/schema/Issue366FailFastTest.java +++ b/src/test/java/com/networknt/schema/Issue366FailFastTest.java @@ -18,21 +18,20 @@ void setup() throws IOException { setupSchema(); } - JsonSchema jsonSchema; + Schema jsonSchema; ObjectMapper objectMapper = new ObjectMapper(); private void setupSchema() throws IOException { - SchemaValidatorsConfig schemaValidatorsConfig = SchemaValidatorsConfig.builder() + SchemaRegistryConfig schemaValidatorsConfig = SchemaRegistryConfig.builder() .failFast(true) .typeLoose(false) .build(); - JsonSchemaFactory schemaFactory = JsonSchemaFactory - .builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7)).build(); + SchemaRegistry schemaFactory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7, builder -> builder.schemaRegistryConfig(schemaValidatorsConfig)); SchemaLocation uri = getSchema(); InputStream in = getClass().getResourceAsStream("/schema/issue366_schema.json"); JsonNode testCases = objectMapper.readValue(in, JsonNode.class); - this.jsonSchema = schemaFactory.getSchema(uri, testCases, schemaValidatorsConfig); + this.jsonSchema = schemaFactory.getSchema(uri, testCases); } protected JsonNode getJsonNodeFromStreamContent(InputStream content) throws Exception { @@ -50,7 +49,7 @@ void firstOneValid() throws Exception { List testNodes = node.findValues("tests"); JsonNode testNode = testNodes.get(0).get(0); JsonNode dataNode = testNode.get("data"); - List errors = jsonSchema.validate(dataNode); + List errors = jsonSchema.validate(dataNode); assertTrue(errors.isEmpty()); } @@ -63,7 +62,7 @@ void secondOneValid() throws Exception { List testNodes = node.findValues("tests"); JsonNode testNode = testNodes.get(0).get(1); JsonNode dataNode = testNode.get("data"); - List errors = jsonSchema.validate(dataNode); + List errors = jsonSchema.validate(dataNode); assertTrue(errors.isEmpty()); } diff --git a/src/test/java/com/networknt/schema/Issue366FailSlowTest.java b/src/test/java/com/networknt/schema/Issue366FailSlowTest.java index b395ebd57..bd00d2558 100644 --- a/src/test/java/com/networknt/schema/Issue366FailSlowTest.java +++ b/src/test/java/com/networknt/schema/Issue366FailSlowTest.java @@ -19,21 +19,19 @@ void setup() throws IOException { setupSchema(); } - JsonSchema jsonSchema; + Schema jsonSchema; ObjectMapper objectMapper = new ObjectMapper(); private void setupSchema() throws IOException { - SchemaValidatorsConfig schemaValidatorsConfig = SchemaValidatorsConfig.builder().typeLoose(false).build(); - JsonSchemaFactory schemaFactory = JsonSchemaFactory - .builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7)) - .build(); + SchemaRegistryConfig schemaValidatorsConfig = SchemaRegistryConfig.builder().typeLoose(false).build(); + SchemaRegistry schemaFactory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7, builder -> builder.schemaRegistryConfig(schemaValidatorsConfig)); SchemaLocation uri = getSchema(); InputStream in = getClass().getResourceAsStream("/schema/issue366_schema.json"); JsonNode testCases = objectMapper.readValue(in, JsonNode.class); - this.jsonSchema = schemaFactory.getSchema(uri, testCases, schemaValidatorsConfig); + this.jsonSchema = schemaFactory.getSchema(uri, testCases); } protected JsonNode getJsonNodeFromStreamContent(InputStream content) throws Exception { @@ -51,7 +49,7 @@ void firstOneValid() throws Exception { List testNodes = node.findValues("tests"); JsonNode testNode = testNodes.get(0).get(0); JsonNode dataNode = testNode.get("data"); - List errors = jsonSchema.validate(dataNode); + List errors = jsonSchema.validate(dataNode); assertTrue(errors.isEmpty()); } @@ -64,7 +62,7 @@ void secondOneValid() throws Exception { List testNodes = node.findValues("tests"); JsonNode testNode = testNodes.get(0).get(1); JsonNode dataNode = testNode.get("data"); - List errors = jsonSchema.validate(dataNode); + List errors = jsonSchema.validate(dataNode); assertTrue(errors.isEmpty()); } @@ -77,7 +75,7 @@ void bothValid() throws Exception { List testNodes = node.findValues("tests"); JsonNode testNode = testNodes.get(0).get(2); JsonNode dataNode = testNode.get("data"); - List errors = jsonSchema.validate(dataNode); + List errors = jsonSchema.validate(dataNode); assertFalse(errors.isEmpty()); assertEquals(errors.size(), 1); } @@ -91,7 +89,7 @@ void neitherValid() throws Exception { List testNodes = node.findValues("tests"); JsonNode testNode = testNodes.get(0).get(3); JsonNode dataNode = testNode.get("data"); - List errors = jsonSchema.validate(dataNode); + List errors = jsonSchema.validate(dataNode); assertFalse(errors.isEmpty()); assertEquals(errors.size(), 3); } diff --git a/src/test/java/com/networknt/schema/Issue375Test.java b/src/test/java/com/networknt/schema/Issue375Test.java index 7e60581d2..4974513f3 100644 --- a/src/test/java/com/networknt/schema/Issue375Test.java +++ b/src/test/java/com/networknt/schema/Issue375Test.java @@ -17,7 +17,6 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.networknt.schema.SpecVersion.VersionFlag; import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; @@ -27,8 +26,8 @@ import org.junit.jupiter.api.Test; class Issue375Test { - protected JsonSchema getJsonSchemaFromStreamContent(InputStream schemaContent) { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V201909); + protected Schema getJsonSchemaFromStreamContent(InputStream schemaContent) { + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2019_09); return factory.getSchema(schemaContent); } @@ -42,19 +41,19 @@ void shouldFailAndShowValidationValuesWithError() throws Exception { String schemaPath = "/draft2019-09/issue375.json"; String dataPath = "/data/issue375.json"; InputStream schemaInputStream = getClass().getResourceAsStream(schemaPath); - JsonSchema schema = getJsonSchemaFromStreamContent(schemaInputStream); + Schema schema = getJsonSchemaFromStreamContent(schemaInputStream); InputStream dataInputStream = getClass().getResourceAsStream(dataPath); JsonNode node = getJsonNodeFromStreamContent(dataInputStream); - List errors = schema.validate(node); + List errors = schema.validate(node); List errorMessages = new ArrayList(); - for (ValidationMessage error: errors) { - errorMessages.add(error.getMessage()); + for (Error error: errors) { + errorMessages.add(error.toString()); } List expectedMessages = Arrays.asList( - "$.fields: property 'longName123' name is not valid: must be at most 5 characters long", - "$.fields: property 'longName123' name is not valid: does not match the regex pattern ^[a-zA-Z]+$", - "$.fields: property 'a' name is not valid: must be at least 3 characters long"); + "/fields: property 'longName123' name is not valid: must be at most 5 characters long", + "/fields: property 'longName123' name is not valid: does not match the regex pattern ^[a-zA-Z]+$", + "/fields: property 'a' name is not valid: must be at least 3 characters long"); MatcherAssert.assertThat(errorMessages, Matchers.containsInAnyOrder(expectedMessages.toArray())); } } diff --git a/src/test/java/com/networknt/schema/Issue383Test.java b/src/test/java/com/networknt/schema/Issue383Test.java index d22009c98..3fdf85f32 100644 --- a/src/test/java/com/networknt/schema/Issue383Test.java +++ b/src/test/java/com/networknt/schema/Issue383Test.java @@ -10,8 +10,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; class Issue383Test { - protected JsonSchema getJsonSchemaFromStreamContentV7(InputStream schemaContent) { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7); + protected Schema getJsonSchemaFromStreamContentV7(InputStream schemaContent) { + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7); return factory.getSchema(schemaContent); } @@ -26,10 +26,10 @@ void nestedOneOfsShouldStillMatchV7() throws Exception { String schemaPath = "/schema/issue383-v7.json"; String dataPath = "/data/issue383.json"; InputStream schemaInputStream = getClass().getResourceAsStream(schemaPath); - JsonSchema schema = getJsonSchemaFromStreamContentV7(schemaInputStream); + Schema schema = getJsonSchemaFromStreamContentV7(schemaInputStream); InputStream dataInputStream = getClass().getResourceAsStream(dataPath); JsonNode node = getJsonNodeFromStreamContent(dataInputStream); - List errors = schema.validate(node); + List errors = schema.validate(node); Assertions.assertEquals(0, errors.size()); } } diff --git a/src/test/java/com/networknt/schema/Issue396Test.java b/src/test/java/com/networknt/schema/Issue396Test.java index df89d7a6e..e625cdde9 100644 --- a/src/test/java/com/networknt/schema/Issue396Test.java +++ b/src/test/java/com/networknt/schema/Issue396Test.java @@ -13,8 +13,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; class Issue396Test { - protected JsonSchema getJsonSchemaFromStreamContentV7(InputStream schemaContent) { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7); + protected Schema getJsonSchemaFromStreamContentV7(InputStream schemaContent) { + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7); return factory.getSchema(schemaContent); } @@ -29,7 +29,7 @@ void testComplexPropertyNamesV7() throws Exception { String schemaPath = "/schema/issue396-v7.json"; String dataPath = "/data/issue396.json"; InputStream schemaInputStream = getClass().getResourceAsStream(schemaPath); - JsonSchema schema = getJsonSchemaFromStreamContentV7(schemaInputStream); + Schema schema = getJsonSchemaFromStreamContentV7(schemaInputStream); InputStream dataInputStream = getClass().getResourceAsStream(dataPath); JsonNode node = getJsonNodeFromStreamContent(dataInputStream); @@ -39,8 +39,8 @@ void testComplexPropertyNamesV7() throws Exception { expected.add(entry.getKey()); }); - List errors = schema.validate(node); - final Set actual = errors.stream().map(ValidationMessage::getProperty).map(Object::toString).collect(Collectors.toSet()); + List errors = schema.validate(node); + final Set actual = errors.stream().map(Error::getProperty).map(Object::toString).collect(Collectors.toSet()); Assertions.assertEquals(expected, actual); } } diff --git a/src/test/java/com/networknt/schema/Issue404Test.java b/src/test/java/com/networknt/schema/Issue404Test.java index 52581d49d..f9b560ebe 100644 --- a/src/test/java/com/networknt/schema/Issue404Test.java +++ b/src/test/java/com/networknt/schema/Issue404Test.java @@ -2,15 +2,15 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.jupiter.api.Assertions; +import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.Test; import java.io.InputStream; import java.util.List; class Issue404Test { - protected JsonSchema getJsonSchemaFromStreamContentV7(InputStream schemaContent) { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7); + protected Schema getJsonSchemaFromStreamContentV7(InputStream schemaContent) { + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7); return factory.getSchema(schemaContent); } @@ -25,11 +25,15 @@ void expectObjectNotIntegerV7() throws Exception { String schemaPath = "/schema/issue404-v7.json"; String dataPath = "/data/issue404.json"; InputStream schemaInputStream = getClass().getResourceAsStream(schemaPath); - JsonSchema schema = getJsonSchemaFromStreamContentV7(schemaInputStream); + Schema schema = getJsonSchemaFromStreamContentV7(schemaInputStream); InputStream dataInputStream = getClass().getResourceAsStream(dataPath); JsonNode node = getJsonNodeFromStreamContent(dataInputStream); - List errors = schema.validate(node); - Assertions.assertEquals(0, errors.size()); + List errors = schema.validate(node); + assertEquals(1, errors.size()); + assertEquals("type", errors.get(0).getKeyword()); + assertEquals("/bar", errors.get(0).getInstanceLocation().toString()); + assertEquals("/properties/bar/$ref/type", errors.get(0).getEvaluationPath().toString()); + assertEquals("https://example.com/address.schema.json#/properties/foo/type", errors.get(0).getSchemaLocation().toString()); } } diff --git a/src/test/java/com/networknt/schema/Issue406Test.java b/src/test/java/com/networknt/schema/Issue406Test.java index e05da6a83..36273254e 100644 --- a/src/test/java/com/networknt/schema/Issue406Test.java +++ b/src/test/java/com/networknt/schema/Issue406Test.java @@ -14,17 +14,17 @@ class Issue406Test { @Test void testPreloadingNotHappening() { - final JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7); - final JsonSchema schema = factory.getSchema(INVALID_$REF_SCHEMA); + final SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7); + final Schema schema = factory.getSchema(INVALID_$REF_SCHEMA); // not breaking - pass Assertions.assertNotNull(schema); } @Test void testPreloadingHappening() { - final JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7); - final JsonSchema schema = factory.getSchema(INVALID_$REF_SCHEMA); - Assertions.assertThrows(JsonSchemaException.class, + final SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7); + final Schema schema = factory.getSchema(INVALID_$REF_SCHEMA); + Assertions.assertThrows(SchemaException.class, new Executable() { @Override public void execute() { @@ -36,8 +36,8 @@ public void execute() { @Test void testPreloadingHappeningForCircularDependency() { - final JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7); - final JsonSchema schema = factory.getSchema(CIRCULAR_$REF_SCHEMA); + final SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7); + final Schema schema = factory.getSchema(CIRCULAR_$REF_SCHEMA); schema.initializeValidators(); } } diff --git a/src/test/java/com/networknt/schema/Issue426Test.java b/src/test/java/com/networknt/schema/Issue426Test.java index c7dd2f547..a3b27e0fa 100644 --- a/src/test/java/com/networknt/schema/Issue426Test.java +++ b/src/test/java/com/networknt/schema/Issue426Test.java @@ -12,8 +12,9 @@ * Validating custom message */ class Issue426Test { - protected JsonSchema getJsonSchemaFromStreamContentV7(InputStream schemaContent) { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7); + protected Schema getJsonSchemaFromStreamContentV7(InputStream schemaContent) { + SchemaRegistryConfig config = SchemaRegistryConfig.builder().errorMessageKeyword("message").build(); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7, builder -> builder.schemaRegistryConfig(config)); return factory.getSchema(schemaContent); } @@ -27,15 +28,15 @@ void shouldWorkV7() throws Exception { String schemaPath = "/schema/issue426-v7.json"; String dataPath = "/data/issue426.json"; InputStream schemaInputStream = getClass().getResourceAsStream(schemaPath); - JsonSchema schema = getJsonSchemaFromStreamContentV7(schemaInputStream); + Schema schema = getJsonSchemaFromStreamContentV7(schemaInputStream); InputStream dataInputStream = getClass().getResourceAsStream(dataPath); JsonNode node = getJsonNodeFromStreamContent(dataInputStream); - List errors = schema.validate(node); + List errors = schema.validate(node); Assertions.assertEquals(2, errors.size()); final JsonNode message = schema.schemaNode.get("message"); - for(ValidationMessage error : errors) { + for(Error error : errors) { //validating custom message - Assertions.assertEquals(message.get(error.getType()).asText(), error.getMessage()); + Assertions.assertEquals(message.get(error.getKeyword()).asText(), error.getMessage()); } } } diff --git a/src/test/java/com/networknt/schema/Issue428Test.java b/src/test/java/com/networknt/schema/Issue428Test.java index f5d7e725f..166ddc96c 100644 --- a/src/test/java/com/networknt/schema/Issue428Test.java +++ b/src/test/java/com/networknt/schema/Issue428Test.java @@ -14,8 +14,6 @@ class Issue428Test { protected ObjectMapper mapper = new ObjectMapper(); - protected JsonSchemaFactory validatorFactory = JsonSchemaFactory - .builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V4)).build(); private void runTestFile(String testCaseFile) throws Exception { final SchemaLocation testCaseFileUri = SchemaLocation.of("classpath:" + testCaseFile); @@ -35,12 +33,14 @@ private void runTestFile(String testCaseFile) throws Exception { JsonNode typeLooseNode = test.get("isTypeLoose"); // Configure the schemaValidator to set typeLoose's value based on the test file, // if test file do not contains typeLoose flag, use default value: true. - SchemaValidatorsConfig.Builder configBuilder = SchemaValidatorsConfig.builder(); + SchemaRegistryConfig.Builder configBuilder = SchemaRegistryConfig.builder(); configBuilder.typeLoose(typeLooseNode != null && typeLooseNode.asBoolean()); - configBuilder.discriminatorKeywordEnabled(false); - JsonSchema schema = validatorFactory.getSchema(testCaseFileUri, testCase.get("schema"), configBuilder.build()); + SchemaRegistryConfig config = configBuilder.build(); - List errors = new ArrayList(schema.validate(node)); + SchemaRegistry validatorFactory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_4, builder -> builder.schemaRegistryConfig(config)); + Schema schema = validatorFactory.getSchema(testCaseFileUri, testCase.get("schema")); + + List errors = new ArrayList(schema.validate(node)); if (test.get("valid").asBoolean()) { if (!errors.isEmpty()) { @@ -48,7 +48,7 @@ private void runTestFile(String testCaseFile) throws Exception { System.out.println("schema: " + schema); System.out.println("data: " + test.get("data")); System.out.println("errors:"); - for (ValidationMessage error : errors) { + for (Error error : errors) { System.out.println(error); } } @@ -65,7 +65,7 @@ private void runTestFile(String testCaseFile) throws Exception { System.out.println("schema: " + schema); System.out.println("data: " + test.get("data")); System.out.println("errors: " + errors); - for (ValidationMessage error : errors) { + for (Error error : errors) { System.out.println(error); } assertEquals(errorCount.asInt(), errors.size(), "expected error count"); @@ -77,7 +77,7 @@ private void runTestFile(String testCaseFile) throws Exception { } - } catch (JsonSchemaException e) { + } catch (SchemaException e) { throw new IllegalStateException(String.format("Current schema should not be invalid: %s", testCaseFile), e); } } diff --git a/src/test/java/com/networknt/schema/Issue451Test.java b/src/test/java/com/networknt/schema/Issue451Test.java index 5d873377b..229bfc478 100644 --- a/src/test/java/com/networknt/schema/Issue451Test.java +++ b/src/test/java/com/networknt/schema/Issue451Test.java @@ -2,7 +2,9 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.networknt.schema.walk.JsonSchemaWalkListener; +import com.networknt.schema.walk.WalkListener; +import com.networknt.schema.walk.PropertyWalkListenerRunner; +import com.networknt.schema.walk.WalkConfig; import com.networknt.schema.walk.WalkEvent; import com.networknt.schema.walk.WalkFlow; import org.junit.jupiter.api.Assertions; @@ -19,13 +21,11 @@ class Issue451Test { private static final String COLLECTOR_ID = "collector-451"; + + protected Schema getJsonSchemaFromStreamContentV7(InputStream schemaContent) { - protected JsonSchema getJsonSchemaFromStreamContentV7(InputStream schemaContent) { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7); - SchemaValidatorsConfig svc = SchemaValidatorsConfig.builder() - .propertyWalkListener(new CountingWalker()) - .build(); - return factory.getSchema(schemaContent, svc); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7); + return factory.getSchema(schemaContent); } protected JsonNode getJsonNodeFromStreamContent(InputStream content) throws Exception { @@ -56,9 +56,11 @@ void shouldWalkAnyOfPropertiesWithWithPayload() throws Exception { private void walk(JsonNode data, boolean shouldValidate) { String schemaPath = "/schema/issue451-v7.json"; InputStream schemaInputStream = getClass().getResourceAsStream(schemaPath); - JsonSchema schema = getJsonSchemaFromStreamContentV7(schemaInputStream); + Schema schema = getJsonSchemaFromStreamContentV7(schemaInputStream); - CollectorContext collectorContext = schema.walk(data, shouldValidate).getCollectorContext(); + WalkConfig walkConfig = WalkConfig.builder().propertyWalkListenerRunner( + PropertyWalkListenerRunner.builder().propertyWalkListener(new CountingWalker()).build()).build(); + CollectorContext collectorContext = schema.walk(data, shouldValidate, executionContext -> executionContext.setWalkConfig(walkConfig)).getCollectorContext(); Map collector = (Map) collectorContext.get(COLLECTOR_ID); Assertions.assertEquals(2, @@ -68,7 +70,7 @@ private void walk(JsonNode data, boolean shouldValidate) { } - private static class CountingWalker implements JsonSchemaWalkListener { + private static class CountingWalker implements WalkListener { @Override public WalkFlow onWalkStart(WalkEvent walkEvent) { SchemaLocation path = walkEvent.getSchema().getSchemaLocation(); @@ -77,7 +79,7 @@ public WalkFlow onWalkStart(WalkEvent walkEvent) { } @Override - public void onWalkEnd(WalkEvent walkEvent, List validationMessages) { + public void onWalkEnd(WalkEvent walkEvent, List errors) { } @@ -86,7 +88,7 @@ private Map collector(ExecutionContext executionContext) { Map collector = (Map) executionContext.getCollectorContext().get(COLLECTOR_ID); if(collector == null) { collector = new HashMap<>(); - executionContext.getCollectorContext().add(COLLECTOR_ID, collector); + executionContext.getCollectorContext().put(COLLECTOR_ID, collector); } return collector; diff --git a/src/test/java/com/networknt/schema/Issue456Test.java b/src/test/java/com/networknt/schema/Issue456Test.java index 473ab9996..7dc2566be 100644 --- a/src/test/java/com/networknt/schema/Issue456Test.java +++ b/src/test/java/com/networknt/schema/Issue456Test.java @@ -10,8 +10,8 @@ class Issue456Test { - protected JsonSchema getJsonSchemaFromStreamContentV7(InputStream schemaContent) { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7); + protected Schema getJsonSchemaFromStreamContentV7(InputStream schemaContent) { + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7); return factory.getSchema(schemaContent); } @@ -26,10 +26,10 @@ void shouldWorkT2() throws Exception { String dataPath = "/data/issue456-T2.json"; // String dataT3Path = "/data/issue456-T3.json"; InputStream schemaInputStream = getClass().getResourceAsStream(schemaPath); - JsonSchema schema = getJsonSchemaFromStreamContentV7(schemaInputStream); + Schema schema = getJsonSchemaFromStreamContentV7(schemaInputStream); InputStream dataInputStream = getClass().getResourceAsStream(dataPath); JsonNode node = getJsonNodeFromStreamContent(dataInputStream); - List errors = schema.validate(node); + List errors = schema.validate(node); Assertions.assertEquals(0, errors.size()); } @@ -38,10 +38,10 @@ void shouldWorkT3() throws Exception { String schemaPath = "/schema/issue456-v7.json"; String dataPath = "/data/issue456-T3.json"; InputStream schemaInputStream = getClass().getResourceAsStream(schemaPath); - JsonSchema schema = getJsonSchemaFromStreamContentV7(schemaInputStream); + Schema schema = getJsonSchemaFromStreamContentV7(schemaInputStream); InputStream dataInputStream = getClass().getResourceAsStream(dataPath); JsonNode node = getJsonNodeFromStreamContent(dataInputStream); - List errors = schema.validate(node); + List errors = schema.validate(node); Assertions.assertEquals(0, errors.size()); } diff --git a/src/test/java/com/networknt/schema/Issue461Test.java b/src/test/java/com/networknt/schema/Issue461Test.java index a95788fb4..72cbee461 100644 --- a/src/test/java/com/networknt/schema/Issue461Test.java +++ b/src/test/java/com/networknt/schema/Issue461Test.java @@ -2,8 +2,11 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import com.networknt.schema.keyword.KeywordType; import com.networknt.schema.serialization.JsonMapperFactory; -import com.networknt.schema.walk.JsonSchemaWalkListener; +import com.networknt.schema.walk.WalkListener; +import com.networknt.schema.walk.KeywordWalkListenerRunner; +import com.networknt.schema.walk.WalkConfig; import com.networknt.schema.walk.WalkEvent; import com.networknt.schema.walk.WalkFlow; import org.junit.jupiter.api.Assertions; @@ -15,26 +18,30 @@ class Issue461Test { protected ObjectMapper mapper = JsonMapperFactory.getInstance(); - protected JsonSchema getJsonSchemaFromStreamContentV7(SchemaLocation schemaUri) { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7); - SchemaValidatorsConfig svc = SchemaValidatorsConfig.builder() - .keywordWalkListener(ValidatorTypeCode.PROPERTIES.getValue(), new Walker()) - .build(); - return factory.getSchema(schemaUri, svc); + protected Schema getJsonSchemaFromStreamContentV7(SchemaLocation schemaUri) { + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7); + return factory.getSchema(schemaUri); } @Test void shouldWalkWithValidation() throws IOException { - JsonSchema schema = getJsonSchemaFromStreamContentV7(SchemaLocation.of("resource:/draft-07/schema#")); + KeywordWalkListenerRunner keywordWalkListenerRunner = KeywordWalkListenerRunner.builder() + .keywordWalkListener(KeywordType.PROPERTIES.getValue(), new Walker()) + .build(); + WalkConfig walkConfig = WalkConfig.builder() + .keywordWalkListenerRunner(keywordWalkListenerRunner) + .build(); + + Schema schema = getJsonSchemaFromStreamContentV7(SchemaLocation.of("resource:/draft-07/schema#")); JsonNode data = mapper.readTree(Issue461Test.class.getResource("/data/issue461-v7.json")); - ValidationResult result = schema.walk(data, true); - Assertions.assertTrue(result.getValidationMessages().isEmpty()); + Result result = schema.walk(data, true, executionContext -> executionContext.setWalkConfig(walkConfig)); + Assertions.assertTrue(result.getErrors().isEmpty()); } /** * Example NOP walker */ - private static class Walker implements JsonSchemaWalkListener { + private static class Walker implements WalkListener { @Override public WalkFlow onWalkStart(final WalkEvent walkEvent) { return WalkFlow.CONTINUE; @@ -42,7 +49,7 @@ public WalkFlow onWalkStart(final WalkEvent walkEvent) { @Override public void onWalkEnd(final WalkEvent walkEvent, - final List validationMessages) { + final List errors) { } } } diff --git a/src/test/java/com/networknt/schema/Issue467Test.java b/src/test/java/com/networknt/schema/Issue467Test.java index ff92735ba..f32c0bb32 100644 --- a/src/test/java/com/networknt/schema/Issue467Test.java +++ b/src/test/java/com/networknt/schema/Issue467Test.java @@ -31,12 +31,16 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.networknt.schema.walk.JsonSchemaWalkListener; +import com.networknt.schema.keyword.KeywordType; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.walk.WalkListener; +import com.networknt.schema.walk.KeywordWalkListenerRunner; +import com.networknt.schema.walk.PropertyWalkListenerRunner; +import com.networknt.schema.walk.WalkConfig; import com.networknt.schema.walk.WalkEvent; import com.networknt.schema.walk.WalkFlow; class Issue467Test { - private static final JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7); private static final String schemaPath = "/schema/issue467.json"; protected ObjectMapper mapper = new ObjectMapper(); @@ -44,9 +48,9 @@ class Issue467Test { @Test void shouldWalkKeywordWithValidation() throws URISyntaxException, IOException { InputStream schemaInputStream = Issue467Test.class.getResourceAsStream(schemaPath); - final Set properties = new LinkedHashSet<>(); - final SchemaValidatorsConfig config = SchemaValidatorsConfig.builder() - .keywordWalkListener(ValidatorTypeCode.PROPERTIES.getValue(), new JsonSchemaWalkListener() { + final Set properties = new LinkedHashSet<>(); + KeywordWalkListenerRunner keywordWalkListenerRunner = KeywordWalkListenerRunner.builder() + .keywordWalkListener(KeywordType.PROPERTIES.getValue(), new WalkListener() { @Override public WalkFlow onWalkStart(WalkEvent walkEvent) { properties.add(walkEvent.getSchema().getEvaluationPath().append(walkEvent.getKeyword())); @@ -54,24 +58,28 @@ public WalkFlow onWalkStart(WalkEvent walkEvent) { } @Override - public void onWalkEnd(WalkEvent walkEvent, List set) { + public void onWalkEnd(WalkEvent walkEvent, List set) { } }) .build(); - JsonSchema schema = factory.getSchema(schemaInputStream, config); + WalkConfig walkConfig = WalkConfig.builder() + .keywordWalkListenerRunner(keywordWalkListenerRunner) + .build(); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7); + Schema schema = factory.getSchema(schemaInputStream); JsonNode data = mapper.readTree(Issue467Test.class.getResource("/data/issue467.json")); - ValidationResult result = schema.walk(data, true); + Result result = schema.walk(data, true, executionContext -> executionContext.setWalkConfig(walkConfig)); assertEquals(new HashSet<>(Arrays.asList("/properties", "/properties/tags/items/0/properties")), properties.stream().map(Object::toString).collect(Collectors.toSet())); - assertEquals(1, result.getValidationMessages().size()); + assertEquals(1, result.getErrors().size()); } @Test void shouldWalkPropertiesWithValidation() throws URISyntaxException, IOException { InputStream schemaInputStream = Issue467Test.class.getResourceAsStream(schemaPath); - final Set properties = new LinkedHashSet<>(); - final SchemaValidatorsConfig config = SchemaValidatorsConfig.builder() - .propertyWalkListener(new JsonSchemaWalkListener() { + final Set properties = new LinkedHashSet<>(); + PropertyWalkListenerRunner propertyWalkListenerRunner = PropertyWalkListenerRunner.builder() + .propertyWalkListener(new WalkListener() { @Override public WalkFlow onWalkStart(WalkEvent walkEvent) { properties.add(walkEvent.getSchema().getEvaluationPath()); @@ -79,17 +87,21 @@ public WalkFlow onWalkStart(WalkEvent walkEvent) { } @Override - public void onWalkEnd(WalkEvent walkEvent, List set) { + public void onWalkEnd(WalkEvent walkEvent, List set) { } }) .build(); - JsonSchema schema = factory.getSchema(schemaInputStream, config); + WalkConfig walkConfig = WalkConfig.builder() + .propertyWalkListenerRunner(propertyWalkListenerRunner) + .build(); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7); + Schema schema = factory.getSchema(schemaInputStream); JsonNode data = mapper.readTree(Issue467Test.class.getResource("/data/issue467.json")); - ValidationResult result = schema.walk(data, true); + Result result = schema.walk(data, true, executionContext -> executionContext.setWalkConfig(walkConfig)); assertEquals( new HashSet<>(Arrays.asList("/properties/tags", "/properties/tags/items/0/properties/category", "/properties/tags/items/0/properties/value")), properties.stream().map(Object::toString).collect(Collectors.toSet())); - assertEquals(1, result.getValidationMessages().size()); + assertEquals(1, result.getErrors().size()); } } diff --git a/src/test/java/com/networknt/schema/Issue471Test.java b/src/test/java/com/networknt/schema/Issue471Test.java index fc4f7bf1e..903a493a8 100644 --- a/src/test/java/com/networknt/schema/Issue471Test.java +++ b/src/test/java/com/networknt/schema/Issue471Test.java @@ -20,7 +20,7 @@ class Issue471Test { @Test @Disabled - void shouldFailV201909_with_enUS() throws Exception { + void shouldFailDRAFT_2019_09_with_enUS() throws Exception { Locale.setDefault(Locale.US); Map errorsMap = validate(); Assertions.assertEquals("$.title: may only be 10 characters long", errorsMap.get("$.title")); @@ -29,7 +29,7 @@ void shouldFailV201909_with_enUS() throws Exception { @Test @Disabled - void shouldFailV201909_with_zhCN() throws Exception { + void shouldFailDRAFT_2019_09_with_zhCN() throws Exception { Locale.setDefault(Locale.CHINA); Map errorsMap = validate(); Assertions.assertEquals("$.title:å¯èƒ½åªæœ‰ 10 个字符长", errorsMap.get("$.title")); @@ -38,7 +38,7 @@ void shouldFailV201909_with_zhCN() throws Exception { @Test @Disabled - void shouldFailV201909_with_deDE() throws Exception { + void shouldFailDRAFT_2019_09_with_deDE() throws Exception { Locale.setDefault(Locale.GERMANY); Map errorsMap = validate(); Assertions.assertEquals("$.title darf höchstens 10 Zeichen lang sein", errorsMap.get("$.title")); @@ -47,7 +47,7 @@ void shouldFailV201909_with_deDE() throws Exception { @Test @Disabled - void shouldFailV201909_with_frFR() throws Exception { + void shouldFailDRAFT_2019_09_with_frFR() throws Exception { Locale.setDefault(Locale.FRANCE); Map errorsMap = validate(); Assertions.assertEquals("$.title: ne doit pas dépasser 10 caractères", errorsMap.get("$.title")); @@ -56,7 +56,7 @@ void shouldFailV201909_with_frFR() throws Exception { @Test @Disabled - void shouldFailV201909_with_frIT() throws Exception { + void shouldFailDRAFT_2019_09_with_frIT() throws Exception { Locale.setDefault(Locale.ITALIAN); Map errorsMap = validate(); Assertions.assertEquals("$.title: può avere lunghezza massima di 10", errorsMap.get("$.title")); @@ -65,20 +65,20 @@ void shouldFailV201909_with_frIT() throws Exception { private Map validate() throws Exception { InputStream schemaInputStream = Issue471Test.class.getResourceAsStream(SCHEMA_PATH); - JsonSchema schema = getJsonSchemaFromStreamContentV201909(schemaInputStream); + Schema schema = getJsonSchemaFromStreamContentV201909(schemaInputStream); InputStream dataInputStream = Issue471Test.class.getResourceAsStream(DATA_PATH); JsonNode node = getJsonNodeFromStreamContent(dataInputStream); - List validationMessages = schema.validate(node); - return convertValidationMessagesToMap(validationMessages); + List errors = schema.validate(node); + return convertErrorsToMap(errors); } - private Map convertValidationMessagesToMap(List validationMessages) { - return validationMessages.stream().collect(Collectors.toMap(m -> m.getInstanceLocation().toString(), ValidationMessage::getMessage)); + private Map convertErrorsToMap(List errors) { + return errors.stream().collect(Collectors.toMap(m -> m.getInstanceLocation().toString(), Error::getMessage)); } - private JsonSchema getJsonSchemaFromStreamContentV201909(InputStream schemaContent) { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V201909); + private Schema getJsonSchemaFromStreamContentV201909(InputStream schemaContent) { + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2019_09); return factory.getSchema(schemaContent); } diff --git a/src/test/java/com/networknt/schema/Issue475Test.java b/src/test/java/com/networknt/schema/Issue475Test.java index 9cb928b94..69aed0ffd 100644 --- a/src/test/java/com/networknt/schema/Issue475Test.java +++ b/src/test/java/com/networknt/schema/Issue475Test.java @@ -21,7 +21,7 @@ import org.junit.jupiter.api.Test; -import com.networknt.schema.SpecVersion.VersionFlag; +import com.networknt.schema.dialect.DialectId; import com.networknt.schema.serialization.JsonMapperFactory; /** @@ -50,12 +50,11 @@ class Issue475Test { @Test void draft4() throws Exception { - JsonSchemaFactory jsonSchemaFactory = JsonSchemaFactory.getInstance(VersionFlag.V4, builder -> builder - .schemaMappers(schemaMappers -> schemaMappers.mapPrefix("http://json-schema.org", "classpath:"))); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema schema = jsonSchemaFactory.getSchema(SchemaLocation.of(SchemaId.V4), config); + SchemaRegistry jsonSchemaFactory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_4, builder -> builder + .schemaIdResolvers(schemaIdResolvers -> schemaIdResolvers.mapPrefix("http://json-schema.org", "classpath:"))); + Schema schema = jsonSchemaFactory.getSchema(SchemaLocation.of(DialectId.DRAFT_4)); - List assertions = schema.validate(JsonMapperFactory.getInstance().readTree(INVALID_INPUT)); + List assertions = schema.validate(JsonMapperFactory.getInstance().readTree(INVALID_INPUT)); assertEquals(2, assertions.size()); assertions = schema.validate(JsonMapperFactory.getInstance().readTree(VALID_INPUT)); @@ -64,12 +63,11 @@ void draft4() throws Exception { @Test void draft6() throws Exception { - JsonSchemaFactory jsonSchemaFactory = JsonSchemaFactory.getInstance(VersionFlag.V6, builder -> builder - .schemaMappers(schemaMappers -> schemaMappers.mapPrefix("http://json-schema.org", "classpath:"))); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema schema = jsonSchemaFactory.getSchema(SchemaLocation.of(SchemaId.V6), config); + SchemaRegistry jsonSchemaFactory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_6, builder -> builder + .schemaIdResolvers(schemaIdResolvers -> schemaIdResolvers.mapPrefix("http://json-schema.org", "classpath:"))); + Schema schema = jsonSchemaFactory.getSchema(SchemaLocation.of(DialectId.DRAFT_6)); - List assertions = schema.validate(JsonMapperFactory.getInstance().readTree(INVALID_INPUT)); + List assertions = schema.validate(JsonMapperFactory.getInstance().readTree(INVALID_INPUT)); assertEquals(2, assertions.size()); assertions = schema.validate(JsonMapperFactory.getInstance().readTree(VALID_INPUT)); @@ -78,12 +76,11 @@ void draft6() throws Exception { @Test void draft7() throws Exception { - JsonSchemaFactory jsonSchemaFactory = JsonSchemaFactory.getInstance(VersionFlag.V7, builder -> builder - .schemaMappers(schemaMappers -> schemaMappers.mapPrefix("http://json-schema.org", "classpath:"))); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema schema = jsonSchemaFactory.getSchema(SchemaLocation.of(SchemaId.V7), config); + SchemaRegistry jsonSchemaFactory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7, builder -> builder + .schemaIdResolvers(schemaIdResolvers -> schemaIdResolvers.mapPrefix("http://json-schema.org", "classpath:"))); + Schema schema = jsonSchemaFactory.getSchema(SchemaLocation.of(DialectId.DRAFT_7)); - List assertions = schema.validate(JsonMapperFactory.getInstance().readTree(INVALID_INPUT)); + List assertions = schema.validate(JsonMapperFactory.getInstance().readTree(INVALID_INPUT)); assertEquals(2, assertions.size()); assertions = schema.validate(JsonMapperFactory.getInstance().readTree(VALID_INPUT)); @@ -92,12 +89,11 @@ void draft7() throws Exception { @Test void draft201909() throws Exception { - JsonSchemaFactory jsonSchemaFactory = JsonSchemaFactory.getInstance(VersionFlag.V201909, builder -> builder - .schemaMappers(schemaMappers -> schemaMappers.mapPrefix("https://json-schema.org", "classpath:"))); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema schema = jsonSchemaFactory.getSchema(SchemaLocation.of(SchemaId.V201909), config); + SchemaRegistry jsonSchemaFactory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2019_09, builder -> builder + .schemaIdResolvers(schemaIdResolvers -> schemaIdResolvers.mapPrefix("https://json-schema.org", "classpath:"))); + Schema schema = jsonSchemaFactory.getSchema(SchemaLocation.of(DialectId.DRAFT_2019_09)); - List assertions = schema.validate(JsonMapperFactory.getInstance().readTree(INVALID_INPUT)); + List assertions = schema.validate(JsonMapperFactory.getInstance().readTree(INVALID_INPUT)); assertEquals(2, assertions.size()); assertions = schema.validate(JsonMapperFactory.getInstance().readTree(VALID_INPUT)); @@ -106,12 +102,11 @@ void draft201909() throws Exception { @Test void draft202012() throws Exception { - JsonSchemaFactory jsonSchemaFactory = JsonSchemaFactory.getInstance(VersionFlag.V202012, builder -> builder - .schemaMappers(schemaMappers -> schemaMappers.mapPrefix("https://json-schema.org", "classpath:"))); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema schema = jsonSchemaFactory.getSchema(SchemaLocation.of(SchemaId.V202012), config); + SchemaRegistry jsonSchemaFactory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12, builder -> builder + .schemaIdResolvers(schemaIdResolvers -> schemaIdResolvers.mapPrefix("https://json-schema.org", "classpath:"))); + Schema schema = jsonSchemaFactory.getSchema(SchemaLocation.of(DialectId.DRAFT_2020_12)); - List assertions = schema.validate(JsonMapperFactory.getInstance().readTree(INVALID_INPUT)); + List assertions = schema.validate(JsonMapperFactory.getInstance().readTree(INVALID_INPUT)); assertEquals(2, assertions.size()); assertions = schema.validate(JsonMapperFactory.getInstance().readTree(VALID_INPUT)); diff --git a/src/test/java/com/networknt/schema/Issue493Test.java b/src/test/java/com/networknt/schema/Issue493Test.java index 591fbab9d..d0926d9bc 100644 --- a/src/test/java/com/networknt/schema/Issue493Test.java +++ b/src/test/java/com/networknt/schema/Issue493Test.java @@ -18,7 +18,7 @@ class Issue493Test { - private static final JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V201909); + private static final SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2019_09); private static final String schemaPath1 = "/schema/issue493.json"; private JsonNode getJsonNodeFromJsonData (String jsonFilePath) @@ -35,9 +35,9 @@ void testValidJson1 () throws Exception { InputStream schemaInputStream = Issue493Test.class.getResourceAsStream(schemaPath1); - JsonSchema schema = factory.getSchema(schemaInputStream); + Schema schema = factory.getSchema(schemaInputStream); JsonNode node = getJsonNodeFromJsonData("/data/issue493-valid-1.json"); - List errors = schema.validate(node); + List errors = schema.validate(node); Assertions.assertTrue(errors.isEmpty()); } @@ -47,9 +47,9 @@ void testValidJson2 () throws Exception { InputStream schemaInputStream = Issue493Test.class.getResourceAsStream(schemaPath1); - JsonSchema schema = factory.getSchema(schemaInputStream); + Schema schema = factory.getSchema(schemaInputStream); JsonNode node = getJsonNodeFromJsonData("/data/issue493-valid-2.json"); - List errors = schema.validate(node); + List errors = schema.validate(node); Assertions.assertTrue(errors.isEmpty()); } @@ -59,18 +59,18 @@ void testInvalidJson1 () throws Exception { InputStream schemaInputStream = Issue493Test.class.getResourceAsStream(schemaPath1); - JsonSchema schema = factory.getSchema(schemaInputStream); + Schema schema = factory.getSchema(schemaInputStream); JsonNode node = getJsonNodeFromJsonData("/data/issue493-invalid-1.json"); - List errors = schema.validate(node); + List errors = schema.validate(node); Assertions.assertEquals(2, errors.size()); Set allErrorMessages = new HashSet<>(); errors.forEach(vm -> { - allErrorMessages.add(vm.getMessage()); + allErrorMessages.add(vm.toString()); }); assertThat(allErrorMessages, - Matchers.containsInAnyOrder("$.parameters[0].value: string found, integer expected", - "$.parameters[0].value: does not match the regex pattern ^\\{\\{.+\\}\\}$")); + Matchers.containsInAnyOrder("/parameters/0/value: string found, integer expected", + "/parameters/0/value: does not match the regex pattern ^\\{\\{.+\\}\\}$")); } @Test @@ -79,19 +79,19 @@ void testInvalidJson2 () throws Exception { InputStream schemaInputStream = Issue493Test.class.getResourceAsStream(schemaPath1); - JsonSchema schema = factory.getSchema(schemaInputStream); + Schema schema = factory.getSchema(schemaInputStream); JsonNode node = getJsonNodeFromJsonData("/data/issue493-invalid-2.json"); - List errors = schema.validate(node); + List errors = schema.validate(node); Assertions.assertEquals(3, errors.size()); Set allErrorMessages = new HashSet<>(); errors.forEach(vm -> { - allErrorMessages.add(vm.getMessage()); + allErrorMessages.add(vm.toString()); }); assertThat(allErrorMessages, Matchers.containsInAnyOrder( - "$.parameters[1].value: string found, integer expected", - "$.parameters[1].value: does not match the regex pattern ^\\{\\{.+\\}\\}$", - "$.parameters[1]: must be valid to one and only one schema, but 0 are valid" + "/parameters/1/value: string found, integer expected", + "/parameters/1/value: does not match the regex pattern ^\\{\\{.+\\}\\}$", + "/parameters/1: must be valid to one and only one schema, but 0 are valid" )); } } diff --git a/src/test/java/com/networknt/schema/Issue518Test.java b/src/test/java/com/networknt/schema/Issue518Test.java index 541a9312f..f96aeed1c 100644 --- a/src/test/java/com/networknt/schema/Issue518Test.java +++ b/src/test/java/com/networknt/schema/Issue518Test.java @@ -3,25 +3,25 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import com.networknt.schema.dialect.Dialect; +import com.networknt.schema.dialect.Dialects; + import java.io.InputStream; class Issue518Test { - private static final JsonMetaSchema igluMetaSchema = - JsonMetaSchema - .builder("http://iglucentral.com/schemas/com.snowplowanalytics.self-desc/schema/jsonschema/1-0-0#", JsonMetaSchema.getV7()) + private static final Dialect igluMetaSchema = + Dialect + .builder("http://iglucentral.com/schemas/com.snowplowanalytics.self-desc/schema/jsonschema/1-0-0#", Dialects.getDraft7()) .build(); - private static final JsonSchemaFactory FACTORY = - JsonSchemaFactory - .builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7)) - .metaSchema(igluMetaSchema) - .build(); + private static final SchemaRegistry REGISTRY = + SchemaRegistry.withDialect(igluMetaSchema); @Test void testPreservingEmptyFragmentSuffix() { String schemaPath = "/schema/issue518-v7.json"; InputStream schemaInputStream = getClass().getResourceAsStream(schemaPath); - JsonSchema schema = FACTORY.getSchema(schemaInputStream); + Schema schema = REGISTRY.getSchema(schemaInputStream); Assertions.assertNotNull(schema); } diff --git a/src/test/java/com/networknt/schema/Issue532Test.java b/src/test/java/com/networknt/schema/Issue532Test.java index eb49b68da..fa537fdd8 100644 --- a/src/test/java/com/networknt/schema/Issue532Test.java +++ b/src/test/java/com/networknt/schema/Issue532Test.java @@ -7,10 +7,10 @@ class Issue532Test { @Test void failure() { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7); - JsonSchemaException ex = assertThrows(JsonSchemaException.class, () -> { + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7); + SchemaException ex = assertThrows(SchemaException.class, () -> { factory.getSchema("{ \"$schema\": true }"); }); - assertEquals("Unknown MetaSchema: true", ex.getMessage()); + assertEquals("Unknown dialect: true", ex.getMessage()); } } diff --git a/src/test/java/com/networknt/schema/Issue550Test.java b/src/test/java/com/networknt/schema/Issue550Test.java index fbe39f7f3..4c65f08b8 100644 --- a/src/test/java/com/networknt/schema/Issue550Test.java +++ b/src/test/java/com/networknt/schema/Issue550Test.java @@ -10,9 +10,9 @@ class Issue550Test { - protected JsonSchema getJsonSchemaFromStreamContentV7(String schemaPath) { + protected Schema getJsonSchemaFromStreamContentV7(String schemaPath) { InputStream schemaContent = getClass().getResourceAsStream(schemaPath); - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7); return factory.getSchema(schemaContent); } @@ -27,13 +27,13 @@ protected JsonNode getJsonNodeFromStreamContent(String dataPath) throws Exceptio void testValidationMessageDoContainSchemaPath() throws Exception { String schemaPath = "/schema/issue500_1-v7.json"; String dataPath = "/data/issue500_1.json"; - JsonSchema schema = getJsonSchemaFromStreamContentV7(schemaPath); + Schema schema = getJsonSchemaFromStreamContentV7(schemaPath); JsonNode node = getJsonNodeFromStreamContent(dataPath); - List errors = schema.validate(node); - ValidationMessage validationMessage = errors.stream().findFirst().get(); + List errors = schema.validate(node); + Error error = errors.stream().findFirst().get(); - Assertions.assertEquals("https://example.com/person.schema.json#/properties/age/minimum", validationMessage.getSchemaLocation().toString()); + Assertions.assertEquals("https://example.com/person.schema.json#/properties/age/minimum", error.getSchemaLocation().toString()); Assertions.assertEquals(1, errors.size()); } @@ -41,14 +41,14 @@ void testValidationMessageDoContainSchemaPath() throws Exception { void testValidationMessageDoContainSchemaPathForOneOf() throws Exception { String schemaPath = "/schema/issue500_2-v7.json"; String dataPath = "/data/issue500_2.json"; - JsonSchema schema = getJsonSchemaFromStreamContentV7(schemaPath); + Schema schema = getJsonSchemaFromStreamContentV7(schemaPath); JsonNode node = getJsonNodeFromStreamContent(dataPath); - List errors = schema.validate(node); - ValidationMessage validationMessage = errors.stream().findFirst().get(); + List errors = schema.validate(node); + Error error = errors.stream().findFirst().get(); // Instead of capturing all subSchema within oneOf, a pointer to oneOf should be provided. - Assertions.assertEquals("https://example.com/person.schema.json#/oneOf", validationMessage.getSchemaLocation().toString()); + Assertions.assertEquals("https://example.com/person.schema.json#/oneOf", error.getSchemaLocation().toString()); Assertions.assertEquals(1, errors.size()); } diff --git a/src/test/java/com/networknt/schema/Issue575Test.java b/src/test/java/com/networknt/schema/Issue575Test.java index 52cdddc87..e54e05ae7 100644 --- a/src/test/java/com/networknt/schema/Issue575Test.java +++ b/src/test/java/com/networknt/schema/Issue575Test.java @@ -21,11 +21,11 @@ * updated to version 1.7.0 or later. */ class Issue575Test { - private static JsonSchema schema; + private static Schema schema; @BeforeAll static void init() { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V201909); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2019_09); String schemaPath = "/schema/issue575-2019-09.json"; InputStream schemaInputStream = Issue575Test.class.getResourceAsStream(schemaPath); schema = factory.getSchema(schemaInputStream); @@ -79,7 +79,7 @@ static Stream validTimeZoneOffsets() { @ParameterizedTest @MethodSource("validTimeZoneOffsets") void testValidTimeZoneOffsets(String jsonObject) throws JsonProcessingException { - List errors = schema.validate(new ObjectMapper().readTree(jsonObject)); + List errors = schema.validate(new ObjectMapper().readTree(jsonObject)); Assertions.assertTrue(errors.isEmpty()); } @@ -121,8 +121,8 @@ static Stream invalidTimeRepresentations() { @ParameterizedTest @MethodSource("invalidTimeRepresentations") void testInvalidTimeRepresentations(String jsonObject) throws JsonProcessingException { - List errors = schema.validate(new ObjectMapper().readTree(jsonObject), OutputFormat.DEFAULT, (executionContext, validationContext) -> { - executionContext.getExecutionConfig().setFormatAssertionsEnabled(true); + List errors = schema.validate(new ObjectMapper().readTree(jsonObject), OutputFormat.DEFAULT, (executionContext, schemaContext) -> { + executionContext.executionConfig(executionConfig -> executionConfig.formatAssertionsEnabled(true)); }); Assertions.assertFalse(errors.isEmpty()); } diff --git a/src/test/java/com/networknt/schema/Issue604Test.java b/src/test/java/com/networknt/schema/Issue604Test.java index 920f7a791..60872c733 100644 --- a/src/test/java/com/networknt/schema/Issue604Test.java +++ b/src/test/java/com/networknt/schema/Issue604Test.java @@ -1,6 +1,9 @@ package com.networknt.schema; import com.fasterxml.jackson.databind.ObjectMapper; +import com.networknt.schema.walk.ApplyDefaultsStrategy; +import com.networknt.schema.walk.WalkConfig; + import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; @@ -8,14 +11,13 @@ class Issue604Test { @Test void failure() { - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder() - .applyDefaultsStrategy(new ApplyDefaultsStrategy(true, false, false)) - .build(); - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7); - JsonSchema schema = factory.getSchema("{ \"type\": \"object\", \"properties\": { \"foo\": { \"type\": \"object\", \"properties\": { \"bar\": { \"type\": \"boolean\", \"default\": false } } } } }", config); + WalkConfig walkConfig = WalkConfig.builder() + .applyDefaultsStrategy(new ApplyDefaultsStrategy(true, false, false)).build(); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7); + Schema schema = factory.getSchema("{ \"type\": \"object\", \"properties\": { \"foo\": { \"type\": \"object\", \"properties\": { \"bar\": { \"type\": \"boolean\", \"default\": false } } } } }"); ObjectMapper objectMapper = new ObjectMapper(); assertDoesNotThrow(() -> { - schema.walk(objectMapper.readTree("{}"), false); + schema.walk(objectMapper.readTree("{}"), false, executionContext -> executionContext.setWalkConfig(walkConfig)); }); } diff --git a/src/test/java/com/networknt/schema/Issue606Test.java b/src/test/java/com/networknt/schema/Issue606Test.java index 999b2fc5b..14ef4eee3 100644 --- a/src/test/java/com/networknt/schema/Issue606Test.java +++ b/src/test/java/com/networknt/schema/Issue606Test.java @@ -9,8 +9,8 @@ import java.util.List; class Issue606Test { - protected JsonSchema getJsonSchemaFromStreamContentV7(InputStream schemaContent) { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7); + protected Schema getJsonSchemaFromStreamContentV7(InputStream schemaContent) { + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7); return factory.getSchema(schemaContent); } @@ -25,10 +25,10 @@ void shouldWorkV7() throws Exception { String schemaPath = "/schema/issue606-v7.json"; String dataPath = "/data/issue606.json"; InputStream schemaInputStream = getClass().getResourceAsStream(schemaPath); - JsonSchema schema = getJsonSchemaFromStreamContentV7(schemaInputStream); + Schema schema = getJsonSchemaFromStreamContentV7(schemaInputStream); InputStream dataInputStream = getClass().getResourceAsStream(dataPath); JsonNode node = getJsonNodeFromStreamContent(dataInputStream); - List errors = schema.validate(node); + List errors = schema.validate(node); Assertions.assertEquals(0, errors.size()); } } diff --git a/src/test/java/com/networknt/schema/Issue619Test.java b/src/test/java/com/networknt/schema/Issue619Test.java index c25fab2c7..97f569974 100644 --- a/src/test/java/com/networknt/schema/Issue619Test.java +++ b/src/test/java/com/networknt/schema/Issue619Test.java @@ -16,7 +16,7 @@ package com.networknt.schema; import com.fasterxml.jackson.databind.JsonNode; -import com.networknt.schema.resource.SchemaLoader; +import com.networknt.schema.resource.ResourceLoader; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -32,16 +32,16 @@ class Issue619Test { - private JsonSchemaFactory factory; + private SchemaRegistry factory; private JsonNode one; private JsonNode two; private JsonNode three; @BeforeEach void setup() throws Exception { - SchemaLoader schemaLoader = new SchemaLoader() { + ResourceLoader schemaLoader = new ResourceLoader() { @Override - public InputStreamSource getSchema(AbsoluteIri absoluteIri) { + public InputStreamSource getResource(AbsoluteIri absoluteIri) { String iri = absoluteIri.toString(); if (iri.startsWith("http://localhost:1234")) { return () -> { @@ -53,8 +53,8 @@ public InputStreamSource getSchema(AbsoluteIri absoluteIri) { } }; - factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V4, - builder -> builder.schemaLoaders(schemaLoaders -> schemaLoaders.add(schemaLoader))); + factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_4, + builder -> builder.resourceLoaders(resourceLoaders -> resourceLoaders.add(schemaLoader))); one = getJsonNodeFromStringContent("1"); two = getJsonNodeFromStringContent("2"); three = getJsonNodeFromStringContent("3"); @@ -62,7 +62,7 @@ public InputStreamSource getSchema(AbsoluteIri absoluteIri) { @Test void bundledSchemaLoadsAndValidatesCorrectly_Ref() { - JsonSchema referencingRootSchema = factory.getSchema("{ \"$ref\": \"resource:schema/issue619.json\" }"); + Schema referencingRootSchema = factory.getSchema("{ \"$ref\": \"resource:schema/issue619.json\" }"); assertTrue(referencingRootSchema.validate(one).isEmpty()); assertTrue(referencingRootSchema.validate(two).isEmpty()); @@ -71,7 +71,7 @@ void bundledSchemaLoadsAndValidatesCorrectly_Ref() { @Test void bundledSchemaLoadsAndValidatesCorrectly_Uri() throws Exception { - JsonSchema rootSchema = factory.getSchema(SchemaLocation.of("resource:schema/issue619.json")); + Schema rootSchema = factory.getSchema(SchemaLocation.of("resource:schema/issue619.json")); assertTrue(rootSchema.validate(one).isEmpty()); assertTrue(rootSchema.validate(two).isEmpty()); @@ -80,7 +80,7 @@ void bundledSchemaLoadsAndValidatesCorrectly_Uri() throws Exception { @Test void uriWithEmptyFragment_Ref() { - JsonSchema referencingRootSchema = factory.getSchema("{ \"$ref\": \"resource:schema/issue619.json#\" }"); + Schema referencingRootSchema = factory.getSchema("{ \"$ref\": \"resource:schema/issue619.json#\" }"); assertTrue(referencingRootSchema.validate(one).isEmpty()); assertTrue(referencingRootSchema.validate(two).isEmpty()); @@ -89,7 +89,7 @@ void uriWithEmptyFragment_Ref() { @Test void uriWithEmptyFragment_Uri() throws Exception { - JsonSchema rootSchema = factory.getSchema(SchemaLocation.of("resource:schema/issue619.json#")); + Schema rootSchema = factory.getSchema(SchemaLocation.of("resource:schema/issue619.json#")); assertTrue(rootSchema.validate(one).isEmpty()); assertTrue(rootSchema.validate(two).isEmpty()); @@ -98,7 +98,7 @@ void uriWithEmptyFragment_Uri() throws Exception { @Test void uriThatPointsToTwoShouldOnlyValidateTwo_Ref() { - JsonSchema referencingTwoSchema = factory.getSchema("{ \"$ref\": \"resource:schema/issue619.json#/definitions/two\" }"); + Schema referencingTwoSchema = factory.getSchema("{ \"$ref\": \"resource:schema/issue619.json#/definitions/two\" }"); assertFalse(referencingTwoSchema.validate(one).isEmpty()); assertTrue(referencingTwoSchema.validate(two).isEmpty()); @@ -107,7 +107,7 @@ void uriThatPointsToTwoShouldOnlyValidateTwo_Ref() { @Test void uriThatPointsToOneShouldOnlyValidateOne_Uri() throws Exception { - JsonSchema oneSchema = factory.getSchema(SchemaLocation.of("resource:schema/issue619.json#/definitions/one")); + Schema oneSchema = factory.getSchema(SchemaLocation.of("resource:schema/issue619.json#/definitions/one")); assertTrue(oneSchema.validate(one).isEmpty()); assertFalse(oneSchema.validate(two).isEmpty()); @@ -116,7 +116,7 @@ void uriThatPointsToOneShouldOnlyValidateOne_Uri() throws Exception { @Test void uriThatPointsToNodeThatInTurnReferencesOneShouldOnlyValidateOne_Ref() { - JsonSchema referencingTwoSchema = factory.getSchema("{ \"$ref\": \"resource:schema/issue619.json#/definitions/refToOne\" }"); + Schema referencingTwoSchema = factory.getSchema("{ \"$ref\": \"resource:schema/issue619.json#/definitions/refToOne\" }"); assertTrue(referencingTwoSchema.validate(one).isEmpty()); assertFalse(referencingTwoSchema.validate(two).isEmpty()); @@ -125,7 +125,7 @@ void uriThatPointsToNodeThatInTurnReferencesOneShouldOnlyValidateOne_Ref() { @Test void uriThatPointsToNodeThatInTurnReferencesOneShouldOnlyValidateOne_Uri() throws Exception { - JsonSchema oneSchema = factory.getSchema(SchemaLocation.of("resource:schema/issue619.json#/definitions/refToOne")); + Schema oneSchema = factory.getSchema(SchemaLocation.of("resource:schema/issue619.json#/definitions/refToOne")); assertTrue(oneSchema.validate(one).isEmpty()); assertFalse(oneSchema.validate(two).isEmpty()); @@ -137,7 +137,7 @@ void uriThatPointsToSchemaWithIdThatHasDifferentUri_Ref() throws Exception { JsonNode oneArray = getJsonNodeFromStringContent("[[1]]"); JsonNode textArray = getJsonNodeFromStringContent("[[\"a\"]]"); - JsonSchema schemaWithIdFromRef = factory.getSchema("{ \"$ref\": \"resource:tests/draft4/refRemote.json#/3/schema\" }"); + Schema schemaWithIdFromRef = factory.getSchema("{ \"$ref\": \"resource:tests/draft4/refRemote.json#/3/schema\" }"); assertTrue(schemaWithIdFromRef.validate(oneArray).isEmpty()); assertFalse(schemaWithIdFromRef.validate(textArray).isEmpty()); } @@ -147,28 +147,28 @@ void uriThatPointsToSchemaWithIdThatHasDifferentUri_Uri() throws Exception { JsonNode oneArray = getJsonNodeFromStringContent("[[1]]"); JsonNode textArray = getJsonNodeFromStringContent("[[\"a\"]]"); - JsonSchema schemaWithIdFromUri = factory.getSchema(SchemaLocation.of("resource:tests/draft4/refRemote.json#/3/schema")); + Schema schemaWithIdFromUri = factory.getSchema(SchemaLocation.of("resource:tests/draft4/refRemote.json#/3/schema")); assertTrue(schemaWithIdFromUri.validate(oneArray).isEmpty()); assertFalse(schemaWithIdFromUri.validate(textArray).isEmpty()); } @Test void uriThatPointsToSchemaThatDoesNotExistShouldFail_Ref() { - JsonSchema referencingNonexistentSchema = factory.getSchema("{ \"$ref\": \"resource:data/schema-that-does-not-exist.json#/definitions/something\" }"); + Schema referencingNonexistentSchema = factory.getSchema("{ \"$ref\": \"resource:data/schema-that-does-not-exist.json#/definitions/something\" }"); - assertThrows(JsonSchemaException.class, () -> referencingNonexistentSchema.validate(one)); + assertThrows(SchemaException.class, () -> referencingNonexistentSchema.validate(one)); } @Test void uriThatPointsToSchemaThatDoesNotExistShouldFail_Uri() { - assertThrows(JsonSchemaException.class, () -> factory.getSchema(SchemaLocation.of("resource:data/schema-that-does-not-exist.json#/definitions/something"))); + assertThrows(SchemaException.class, () -> factory.getSchema(SchemaLocation.of("resource:data/schema-that-does-not-exist.json#/definitions/something"))); } @Test void uriThatPointsToNodeThatDoesNotExistShouldFail_Ref() { - JsonSchema referencingNonexistentSchema = factory.getSchema("{ \"$ref\": \"resource:schema/issue619.json#/definitions/node-that-does-not-exist\" }"); + Schema referencingNonexistentSchema = factory.getSchema("{ \"$ref\": \"resource:schema/issue619.json#/definitions/node-that-does-not-exist\" }"); - assertThrows(JsonSchemaException.class, () -> referencingNonexistentSchema.validate(one)); + assertThrows(SchemaException.class, () -> referencingNonexistentSchema.validate(one)); } @Test @@ -180,6 +180,6 @@ void uriThatPointsToNodeThatDoesNotExistShouldFail_Uri() { } catch (InterruptedException e) { e.printStackTrace(); } - assertThrows(JsonSchemaException.class, () -> factory.getSchema(SchemaLocation.of("resource:schema/issue619.json#/definitions/node-that-does-not-exist"))); + assertThrows(SchemaException.class, () -> factory.getSchema(SchemaLocation.of("resource:schema/issue619.json#/definitions/node-that-does-not-exist"))); } } diff --git a/src/test/java/com/networknt/schema/Issue650Test.java b/src/test/java/com/networknt/schema/Issue650Test.java index 0d15bdb0f..fdd15a33d 100644 --- a/src/test/java/com/networknt/schema/Issue650Test.java +++ b/src/test/java/com/networknt/schema/Issue650Test.java @@ -37,7 +37,7 @@ void testBinaryNode() throws Exception { // schema with data property of type string: InputStream schemaInputStream = getClass().getResourceAsStream("/draft7/issue650.json"); - JsonSchema schema = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7).getSchema(schemaInputStream); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7).getSchema(schemaInputStream); // create model first: Issue650Test.Model model = new Issue650Test.Model(); @@ -46,7 +46,7 @@ void testBinaryNode() throws Exception { JsonNode node = mapper.valueToTree(model); // validate: - List errors = schema.validate(node); + List errors = schema.validate(node); // check result: Assertions.assertTrue(errors.isEmpty()); diff --git a/src/test/java/com/networknt/schema/Issue662Test.java b/src/test/java/com/networknt/schema/Issue662Test.java index 3e1eaba9c..5241d4378 100644 --- a/src/test/java/com/networknt/schema/Issue662Test.java +++ b/src/test/java/com/networknt/schema/Issue662Test.java @@ -13,33 +13,33 @@ class Issue662Test extends BaseJsonSchemaValidatorTest { private static final String RESOURCE_PREFIX = "issues/662/"; - private static JsonSchema schema; + private static Schema schema; @BeforeAll static void setup() { - schema = getJsonSchemaFromClasspath(resource("schema.json"), SpecVersion.VersionFlag.V7); + schema = getJsonSchemaFromClasspath(resource("schema.json"), SpecificationVersion.DRAFT_7); } @Test void testNoErrorsForEmptyObject() throws IOException { JsonNode node = getJsonNodeFromClasspath(resource("emptyObject.json")); - List errors = schema.validate(node); + List errors = schema.validate(node); assertTrue(errors.isEmpty(), "No validation errors for empty optional object"); } @Test void testNoErrorsForValidObject() throws IOException { JsonNode node = getJsonNodeFromClasspath(resource("validObject.json")); - List errors = schema.validate(node); + List errors = schema.validate(node); assertTrue(errors.isEmpty(), "No validation errors for a valid optional object"); } @Test void testCorrectErrorForInvalidValue() throws IOException { JsonNode node = getJsonNodeFromClasspath(resource("objectInvalidValue.json")); - List errors = schema.validate(node); + List errors = schema.validate(node); List errorMessages = errors.stream() - .map(v -> v.getEvaluationPath() + " = " + v.getMessage()) + .map(v -> v.getEvaluationPath() + " = " + v.toString()) .collect(toList()); // As this is from an anyOf evaluation both error messages should be present as they didn't match any @@ -48,9 +48,9 @@ void testCorrectErrorForInvalidValue() throws IOException { // Omitting the 'object found, null expected' message also provides the misleading impression that the // object is required when leaving it empty is a possible option assertTrue(errorMessages - .contains("$.properties.optionalObject.anyOf[0].type = $.optionalObject: object found, null expected")); + .contains("/properties/optionalObject/anyOf/0/type = /optionalObject: object found, null expected")); assertTrue(errorMessages.contains( - "$.properties.optionalObject.anyOf[1].properties.value.enum = $.optionalObject.value: does not have a value in the enumeration [\"one\", \"two\"]")); + "/properties/optionalObject/anyOf/1/properties/value/enum = /optionalObject/value: does not have a value in the enumeration [\"one\", \"two\"]")); } private static String resource(String name) { diff --git a/src/test/java/com/networknt/schema/Issue664Test.java b/src/test/java/com/networknt/schema/Issue664Test.java index 7056ab223..738e08665 100644 --- a/src/test/java/com/networknt/schema/Issue664Test.java +++ b/src/test/java/com/networknt/schema/Issue664Test.java @@ -13,8 +13,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; class Issue664Test { - protected JsonSchema getJsonSchemaFromStreamContentV7(InputStream schemaContent) { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7); + protected Schema getJsonSchemaFromStreamContentV7(InputStream schemaContent) { + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7); return factory.getSchema(schemaContent); } @@ -28,10 +28,10 @@ void shouldHaveFullSchemaPaths() throws Exception { String schemaPath = "/schema/issue664-v7.json"; String dataPath = "/data/issue664.json"; InputStream schemaInputStream = getClass().getResourceAsStream(schemaPath); - JsonSchema schema = getJsonSchemaFromStreamContentV7(schemaInputStream); + Schema schema = getJsonSchemaFromStreamContentV7(schemaInputStream); InputStream dataInputStream = getClass().getResourceAsStream(dataPath); JsonNode node = getJsonNodeFromStreamContent(dataInputStream); - List errorSchemaPaths = schema.validate(node).stream().map(ValidationMessage::getSchemaLocation) + List errorSchemaPaths = schema.validate(node).stream().map(Error::getSchemaLocation) .map(Object::toString).collect(Collectors.toList()); List expectedSchemaPaths = Arrays.asList( diff --git a/src/test/java/com/networknt/schema/Issue665Test.java b/src/test/java/com/networknt/schema/Issue665Test.java index d05f7bd9b..3baad8214 100644 --- a/src/test/java/com/networknt/schema/Issue665Test.java +++ b/src/test/java/com/networknt/schema/Issue665Test.java @@ -13,30 +13,30 @@ class Issue665Test extends BaseJsonSchemaValidatorTest { @Test void testUrnUriAsLocalRef() throws IOException { - JsonSchema schema = getJsonSchemaFromClasspath("draft7/urn/issue665.json", SpecVersion.VersionFlag.V7); + Schema schema = getJsonSchemaFromClasspath("draft7/urn/issue665.json", SpecificationVersion.DRAFT_7); Assertions.assertNotNull(schema); Assertions.assertDoesNotThrow(schema::initializeValidators); - List messages = schema.validate(getJsonNodeFromStringContent( + List messages = schema.validate(getJsonNodeFromStringContent( "{\"myData\": {\"value\": \"hello\"}}")); Assertions.assertTrue(messages.isEmpty()); } @Test void testUrnUriAsLocalRef_ExternalURN() { - JsonSchemaFactory factory = JsonSchemaFactory - .builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7)) - .schemaMappers(schemaMappers -> { - schemaMappers.mappings(Collections.singletonMap("urn:data", + SchemaRegistry factory = SchemaRegistry + .builder(SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7)) + .schemaIdResolvers(schemaIdResolvers -> { + schemaIdResolvers.mappings(Collections.singletonMap("urn:data", "classpath:draft7/urn/issue665_external_urn_subschema.json")); }) .build(); try (InputStream is = Thread.currentThread().getContextClassLoader() .getResourceAsStream("draft7/urn/issue665_external_urn_ref.json")) { - JsonSchema schema = factory.getSchema(is); + Schema schema = factory.getSchema(is); Assertions.assertNotNull(schema); Assertions.assertDoesNotThrow(schema::initializeValidators); - List messages = schema.validate(getJsonNodeFromStringContent( + List messages = schema.validate(getJsonNodeFromStringContent( "{\"myData\": {\"value\": \"hello\"}}")); Assertions.assertTrue(messages.isEmpty()); } catch (IOException e) { diff --git a/src/test/java/com/networknt/schema/Issue668Test.java b/src/test/java/com/networknt/schema/Issue668Test.java index bdecac7b3..040b65286 100644 --- a/src/test/java/com/networknt/schema/Issue668Test.java +++ b/src/test/java/com/networknt/schema/Issue668Test.java @@ -10,8 +10,8 @@ import java.io.InputStream; class Issue668Test { - protected JsonSchema getJsonSchemaFromStreamContent(InputStream schemaContent) throws Exception { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7); + protected Schema getJsonSchemaFromStreamContent(InputStream schemaContent) throws Exception { + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7); YAMLMapper mapper = new YAMLMapper(); JsonNode node = mapper.readTree(schemaContent); return factory.getSchema(node); @@ -27,7 +27,7 @@ void shouldHandleReferencesToYaml() throws Exception { String schemaPath = "/schema/issue668.yml"; String dataPath = "/data/issue668.json"; InputStream schemaInputStream = getClass().getResourceAsStream(schemaPath); - JsonSchema schema = getJsonSchemaFromStreamContent(schemaInputStream); + Schema schema = getJsonSchemaFromStreamContent(schemaInputStream); InputStream dataInputStream = getClass().getResourceAsStream(dataPath); JsonNode node = getJsonNodeFromStreamContent(dataInputStream); MatcherAssert.assertThat(schema.validate(node), Matchers.empty()); diff --git a/src/test/java/com/networknt/schema/Issue686Test.java b/src/test/java/com/networknt/schema/Issue686Test.java index 9fd5556ac..c0f49d187 100644 --- a/src/test/java/com/networknt/schema/Issue686Test.java +++ b/src/test/java/com/networknt/schema/Issue686Test.java @@ -18,27 +18,27 @@ class Issue686Test { @Test void testDefaults() { - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); + SchemaRegistryConfig config = SchemaRegistryConfig.builder().build(); assertEquals(DefaultMessageSource.getInstance(), config.getMessageSource()); } @Test void testValidationWithDefaultBundleAndLocale() throws JsonProcessingException { - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); + SchemaRegistryConfig config = SchemaRegistryConfig.builder().build(); ResourceBundle resourceBundle = ResourceBundle.getBundle(DefaultMessageSource.BUNDLE_BASE_NAME, Locale.getDefault()); - String expectedMessage = new MessageFormat(resourceBundle.getString("type")).format(new String[] {"/foo", "integer", "string"}); - verify(config, expectedMessage); + String expectedMessage = new MessageFormat(resourceBundle.getString("type")).format(new String[] {"integer", "string"}); + verify(config, "/foo: " + expectedMessage); } @Test void testValidationWithDefaultBundleAndCustomLocale() throws JsonProcessingException { - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().locale(Locale.ITALIAN).build(); + SchemaRegistryConfig config = SchemaRegistryConfig.builder().locale(Locale.ITALIAN).build(); verify(config, "/foo: integer trovato, string previsto"); } @Test void testValidationWithCustomBundle() throws JsonProcessingException { - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder() + SchemaRegistryConfig config = SchemaRegistryConfig.builder() .messageSource(new ResourceBundleMessageSource("issue686/translations")) .locale(Locale.FRENCH) .build(); @@ -47,21 +47,21 @@ void testValidationWithCustomBundle() throws JsonProcessingException { @Test void testLocaleSwitch() throws JsonProcessingException { - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().locale(Locale.ITALIAN).build(); + SchemaRegistryConfig config = SchemaRegistryConfig.builder().locale(Locale.ITALIAN).build(); verify(config, "/foo: integer trovato, string previsto"); - SchemaValidatorsConfig config2 = SchemaValidatorsConfig.builder().locale(Locale.FRENCH).build(); + SchemaRegistryConfig config2 = SchemaRegistryConfig.builder().locale(Locale.FRENCH).build(); verify(config2, "/foo: integer trouvé, string attendu"); } - private JsonSchema getSchema(SchemaValidatorsConfig config) { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V201909); - return factory.getSchema("{ \"$schema\": \"https://json-schema.org/draft/2019-09/schema\", \"$id\": \"https://json-schema.org/draft/2019-09/schema\", \"type\": \"object\", \"properties\": { \"foo\": { \"type\": \"string\" } } } }", config); + private Schema getSchema(SchemaRegistryConfig config) { + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2019_09, builder -> builder.schemaRegistryConfig(config)); + return factory.getSchema("{ \"$schema\": \"https://json-schema.org/draft/2019-09/schema\", \"$id\": \"https://json-schema.org/draft/2019-09/schema\", \"type\": \"object\", \"properties\": { \"foo\": { \"type\": \"string\" } } } }"); } - private void verify(SchemaValidatorsConfig config, String expectedMessage) throws JsonProcessingException { - List messages = getSchema(config).validate(new ObjectMapper().readTree(" { \"foo\": 123 } ")); + private void verify(SchemaRegistryConfig config, String expectedMessage) throws JsonProcessingException { + List messages = getSchema(config).validate(new ObjectMapper().readTree(" { \"foo\": 123 } ")); assertEquals(1, messages.size()); - assertEquals(expectedMessage, messages.iterator().next().getMessage()); + assertEquals(expectedMessage, messages.iterator().next().toString()); } } diff --git a/src/test/java/com/networknt/schema/Issue687Test.java b/src/test/java/com/networknt/schema/Issue687Test.java index 457ace08f..8995df5bd 100644 --- a/src/test/java/com/networknt/schema/Issue687Test.java +++ b/src/test/java/com/networknt/schema/Issue687Test.java @@ -2,6 +2,8 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import com.networknt.schema.path.PathType; + import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; @@ -54,7 +56,7 @@ static Stream appendIndexes() { ); } - static Stream validationMessages() { + static Stream errors() { String schemaPath = "/schema/issue687.json"; String content = "{ \"foo\": \"a\", \"b.ar\": 1, \"children\": [ { \"childFoo\": \"a\", \"c/hildBar\": 1 } ] }"; return Stream.of( @@ -68,22 +70,28 @@ static Stream validationMessages() { @ParameterizedTest @MethodSource("appendTokens") void testAppendToken(PathType pathType, String currentPath, String token, String expected) { - assertEquals(expected, pathType.append(currentPath, token)); + StringBuilder builder = new StringBuilder(); + builder.append(currentPath); + pathType.append(builder, token); + assertEquals(expected, builder.toString()); } @ParameterizedTest @MethodSource("appendIndexes") void testAppendIndex(PathType pathType, String currentPath, Integer index, String expected) { - assertEquals(expected, pathType.append(currentPath, index)); + StringBuilder builder = new StringBuilder(); + builder.append(currentPath); + pathType.append(builder, index); + assertEquals(expected, builder.toString()); } @ParameterizedTest - @MethodSource("validationMessages") - void testValidationMessage(PathType pathType, String schemaPath, String content, String[] expectedMessagePaths) throws JsonProcessingException { - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().pathType(pathType).build(); - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V201909); - JsonSchema schema = factory.getSchema(Issue687Test.class.getResourceAsStream(schemaPath), config); - List messages = schema.validate(new ObjectMapper().readTree(content)); + @MethodSource("errors") + void testError(PathType pathType, String schemaPath, String content, String[] expectedMessagePaths) throws JsonProcessingException { + SchemaRegistryConfig config = SchemaRegistryConfig.builder().pathType(pathType).build(); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2019_09, builder -> builder.schemaRegistryConfig(config)); + Schema schema = factory.getSchema(Issue687Test.class.getResourceAsStream(schemaPath)); + List messages = schema.validate(new ObjectMapper().readTree(content)); assertEquals(expectedMessagePaths.length, messages.size()); for (String expectedPath: expectedMessagePaths) { assertTrue(messages.stream().anyMatch(msg -> expectedPath.equals(msg.getInstanceLocation().toString()))); @@ -113,8 +121,8 @@ static Stream specialCharacterTests() { @MethodSource("specialCharacterTests") void testSpecialCharacters(PathType pathType, String propertyName, String expectedPath) throws JsonProcessingException { ObjectMapper mapper = new ObjectMapper(); - SchemaValidatorsConfig schemaValidatorsConfig = SchemaValidatorsConfig.builder().pathType(pathType).build(); - JsonSchema schema = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V201909) + SchemaRegistryConfig schemaValidatorsConfig = SchemaRegistryConfig.builder().pathType(pathType).build(); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2019_09, builder -> builder.schemaRegistryConfig(schemaValidatorsConfig)) .getSchema(mapper.readTree("{\n" + " \"$schema\": \"https://json-schema.org/draft/2019-09/schema\",\n" + " \"type\": \"object\",\n" + @@ -123,10 +131,10 @@ void testSpecialCharacters(PathType pathType, String propertyName, String expect " \"type\": \"boolean\"\n" + " }\n" + " }\n" + - "}"), schemaValidatorsConfig); - List validationMessages = schema.validate(mapper.readTree("{\""+propertyName+"\": 1}")); - assertEquals(1, validationMessages.size()); - assertEquals(expectedPath, validationMessages.iterator().next().getInstanceLocation().toString()); + "}")); + List errors = schema.validate(mapper.readTree("{\""+propertyName+"\": 1}")); + assertEquals(1, errors.size()); + assertEquals(expectedPath, errors.iterator().next().getInstanceLocation().toString()); } } diff --git a/src/test/java/com/networknt/schema/Issue724Test.java b/src/test/java/com/networknt/schema/Issue724Test.java index 8cdbe9cc9..13486210a 100644 --- a/src/test/java/com/networknt/schema/Issue724Test.java +++ b/src/test/java/com/networknt/schema/Issue724Test.java @@ -12,8 +12,9 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.networknt.schema.SpecVersion.VersionFlag; -import com.networknt.schema.walk.JsonSchemaWalkListener; +import com.networknt.schema.walk.WalkListener; +import com.networknt.schema.walk.KeywordWalkListenerRunner; +import com.networknt.schema.walk.WalkConfig; import com.networknt.schema.walk.WalkEvent; import com.networknt.schema.walk.WalkFlow; @@ -22,7 +23,7 @@ class Issue724Test { @Test void test() throws JsonProcessingException { StringCollector stringCollector = new StringCollector(); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().keywordWalkListener(stringCollector).build(); + KeywordWalkListenerRunner keywordWalkListenerRunner = KeywordWalkListenerRunner.builder().keywordWalkListener(stringCollector).build(); String schema = "{\n" @@ -49,15 +50,17 @@ void test() throws JsonProcessingException { + " \"credit_card\" : \"my_credit_card\",\n" + " \"billing_address\" : \"my_billing_address\"\n" + "}\n"; - - JsonSchema jsonSchema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schema, config); - jsonSchema.walk(new ObjectMapper().readTree(data), /* shouldValidateSchema= */ false); + WalkConfig walkConfig = WalkConfig.builder() + .keywordWalkListenerRunner(keywordWalkListenerRunner) + .build(); + Schema jsonSchema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12).getSchema(schema); + jsonSchema.walk(new ObjectMapper().readTree(data), /* shouldValidateSchema= */ false, executionContext -> executionContext.setWalkConfig(walkConfig)); System.out.println(stringCollector.strings); assertLinesMatch(Arrays.asList("my_credit_card", "my_billing_address"), stringCollector.strings); } - static class StringCollector implements JsonSchemaWalkListener { + static class StringCollector implements WalkListener { final List strings = new ArrayList<>(); @Override @@ -77,7 +80,7 @@ public WalkFlow onWalkStart(WalkEvent walkEvent) { } @Override - public void onWalkEnd(WalkEvent walkEvent, List validationMessages) { + public void onWalkEnd(WalkEvent walkEvent, List errors) { // nothing to do here } } diff --git a/src/test/java/com/networknt/schema/Issue769ContainsTest.java b/src/test/java/com/networknt/schema/Issue769ContainsTest.java index 5be980c83..19a551a2f 100644 --- a/src/test/java/com/networknt/schema/Issue769ContainsTest.java +++ b/src/test/java/com/networknt/schema/Issue769ContainsTest.java @@ -2,6 +2,9 @@ import org.junit.jupiter.api.Test; +import com.networknt.schema.keyword.ContainsValidator; +import com.networknt.schema.keyword.KeywordType; + /** *

Test class for issue #769

*

This test class asserts that correct messages are returned for contains, minContains et maxContains keywords

@@ -18,22 +21,22 @@ protected String getDataTestFolder() { @Test void shouldReturnMinContainsKeyword() { - assertValidatorType("min-contains.json", ValidatorTypeCode.MIN_CONTAINS); + assertValidatorType("min-contains.json", KeywordType.MIN_CONTAINS); } @Test void shouldReturnContainsKeywordForMinContainsV7() { - assertValidatorType("min-contains-v7.json", ValidatorTypeCode.CONTAINS); + assertValidatorType("min-contains-v7.json", KeywordType.CONTAINS); } @Test void shouldReturnMaxContainsKeyword() { - assertValidatorType("max-contains.json", ValidatorTypeCode.MAX_CONTAINS); + assertValidatorType("max-contains.json", KeywordType.MAX_CONTAINS); } @Test void shouldReturnContainsKeywordForMaxContainsV7() { - assertValidatorType("max-contains-v7.json", ValidatorTypeCode.CONTAINS); + assertValidatorType("max-contains-v7.json", KeywordType.CONTAINS); } } diff --git a/src/test/java/com/networknt/schema/Issue784Test.java b/src/test/java/com/networknt/schema/Issue784Test.java index dbdcff706..da483abe1 100644 --- a/src/test/java/com/networknt/schema/Issue784Test.java +++ b/src/test/java/com/networknt/schema/Issue784Test.java @@ -2,6 +2,9 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import com.networknt.schema.dialect.Dialect; +import com.networknt.schema.dialect.Dialects; +import com.networknt.schema.format.Format; import org.junit.jupiter.api.Test; @@ -26,16 +29,11 @@ public String getName() { public boolean matches(ExecutionContext executionContext, String value) { return value.equals(FOO_BAR); } - - @Override - public String getErrorMessageDescription() { - return null; - } } @Test void allowToOverrideDataTime() throws IOException { - JsonSchema jsonSchema = createSchema(true); + Schema jsonSchema = createSchema(true); // Custom validator checks for FOO_BAR assertEquals(0, validate(jsonSchema, FOO_BAR).size()); @@ -46,7 +44,7 @@ void allowToOverrideDataTime() throws IOException { @Test void useDefaultValidatorIfNotOverriden() throws IOException { - JsonSchema jsonSchema = createSchema(false); + Schema jsonSchema = createSchema(false); // Default validator fails with FOO_BAR assertEquals(1, validate(jsonSchema, FOO_BAR).size()); @@ -56,13 +54,13 @@ void useDefaultValidatorIfNotOverriden() throws IOException { } - private List validate(JsonSchema jsonSchema, String myDateTimeContent) throws JsonProcessingException { + private List validate(Schema jsonSchema, String myDateTimeContent) throws JsonProcessingException { return jsonSchema.validate(new ObjectMapper().readTree(" { \"my-date-time\": \"" + myDateTimeContent + "\" } ")); } - private JsonSchema createSchema(boolean useCustomDateFormat) { - JsonMetaSchema overrideDateTimeValidator =JsonMetaSchema - .builder(JsonMetaSchema.getV7().getIri(), JsonMetaSchema.getV7()) + private Schema createSchema(boolean useCustomDateFormat) { + Dialect overrideDateTimeValidator = Dialect + .builder(Dialects.getDraft7().getId(), Dialects.getDraft7()) .formats(formats -> { if (useCustomDateFormat) { CustomDateTimeFormat format = new CustomDateTimeFormat(); @@ -71,11 +69,7 @@ private JsonSchema createSchema(boolean useCustomDateFormat) { }) .build(); - return new JsonSchemaFactory - .Builder() - .defaultMetaSchemaIri(overrideDateTimeValidator.getIri()) - .metaSchema(overrideDateTimeValidator) - .build() + return SchemaRegistry.withDialect(overrideDateTimeValidator) .getSchema(Issue784Test.class.getResourceAsStream("/issue784/schema.json")); } } diff --git a/src/test/java/com/networknt/schema/Issue792.java b/src/test/java/com/networknt/schema/Issue792.java index 44c9a047f..b2302017c 100644 --- a/src/test/java/com/networknt/schema/Issue792.java +++ b/src/test/java/com/networknt/schema/Issue792.java @@ -12,7 +12,9 @@ class Issue792 { @Test void test() throws JsonProcessingException { - JsonSchemaFactory schemaFactory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7); + SchemaRegistryConfig config = SchemaRegistryConfig.builder().typeLoose(false).failFast(true).build(); + + SchemaRegistry schemaFactory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7, builder -> builder.schemaRegistryConfig(config)); String schemaDef = "{\n" + @@ -28,9 +30,7 @@ void test() throws JsonProcessingException { " }\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().typeLoose(false).failFast(true).build(); - - JsonSchema jsonSchema = schemaFactory.getSchema(schemaDef, config); + Schema jsonSchema = schemaFactory.getSchema(schemaDef); JsonNode jsonNode = new ObjectMapper().readTree("{\"field\": \"pattern-violation\"}"); assertEquals(1, jsonSchema.validate(jsonNode).size()); diff --git a/src/test/java/com/networknt/schema/Issue824Test.java b/src/test/java/com/networknt/schema/Issue824Test.java index cfa8ba0f2..8ad539afc 100644 --- a/src/test/java/com/networknt/schema/Issue824Test.java +++ b/src/test/java/com/networknt/schema/Issue824Test.java @@ -9,16 +9,17 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import com.networknt.schema.dialect.Dialects; class Issue824Test { @Test void validate() throws JsonProcessingException { - final JsonSchema v201909SpecSchema = JsonSchemaFactory - .builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V201909)) - .schemaMappers(schemaMappers -> { - schemaMappers.mapPrefix("https://json-schema.org", "resource:"); + final Schema v201909SpecSchema = SchemaRegistry + .builder(SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2019_09)) + .schemaIdResolvers(schemaIdResolvers -> { + schemaIdResolvers.mapPrefix("https://json-schema.org", "resource:"); }).build() - .getSchema(SchemaLocation.of(JsonMetaSchema.getV201909().getIri())); + .getSchema(SchemaLocation.of(Dialects.getDraft201909().getId())); final JsonNode invalidSchema = new ObjectMapper().readTree( "{"+ " \"$schema\": \"https://json-schema.org/draft/2019-09/schema\","+ @@ -26,8 +27,8 @@ void validate() throws JsonProcessingException { "}"); // Validate same JSON schema against v2019-09 spec schema twice - final List validationErrors1 = v201909SpecSchema.validate(invalidSchema); - final List validationErrors2 = v201909SpecSchema.validate(invalidSchema); + final List validationErrors1 = v201909SpecSchema.validate(invalidSchema); + final List validationErrors2 = v201909SpecSchema.validate(invalidSchema); // Validation errors should be the same assertEquals(validationErrors1, validationErrors2); diff --git a/src/test/java/com/networknt/schema/Issue832Test.java b/src/test/java/com/networknt/schema/Issue832Test.java index 76e5ae0d2..9065decdf 100644 --- a/src/test/java/com/networknt/schema/Issue832Test.java +++ b/src/test/java/com/networknt/schema/Issue832Test.java @@ -2,6 +2,10 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import com.networknt.schema.dialect.Dialect; +import com.networknt.schema.dialect.Dialects; +import com.networknt.schema.format.Format; + import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -23,22 +27,22 @@ public String getName() { } @Override - public String getErrorMessageDescription() { + public String getMessageKey() { return "always fail match"; } } - private JsonSchemaFactory buildV7PlusNoFormatSchemaFactory() { + private SchemaRegistry buildV7PlusNoFormatSchemaFactory() { List formats; formats = new ArrayList<>(); formats.add(new NoMatchFormat()); - JsonMetaSchema jsonMetaSchema = JsonMetaSchema.builder( - JsonMetaSchema.getV7().getIri(), - JsonMetaSchema.getV7()) + Dialect dialect = Dialect.builder( + Dialects.getDraft7().getId(), + Dialects.getDraft7()) .formats(formats) .build(); - return new JsonSchemaFactory.Builder().defaultMetaSchemaIri(jsonMetaSchema.getIri()).metaSchema(jsonMetaSchema).build(); + return SchemaRegistry.withDialect(dialect); } protected JsonNode getJsonNodeFromStreamContent(InputStream content) throws IOException { @@ -51,11 +55,11 @@ void testV7WithNonMatchingCustomFormat() throws IOException { String schemaPath = "/schema/issue832-v7.json"; String dataPath = "/data/issue832.json"; InputStream schemaInputStream = getClass().getResourceAsStream(schemaPath); - JsonSchemaFactory factory = buildV7PlusNoFormatSchemaFactory(); - JsonSchema schema = factory.getSchema(schemaInputStream); + SchemaRegistry factory = buildV7PlusNoFormatSchemaFactory(); + Schema schema = factory.getSchema(schemaInputStream); InputStream dataInputStream = getClass().getResourceAsStream(dataPath); JsonNode node = getJsonNodeFromStreamContent(dataInputStream); - List errors = schema.validate(node); + List errors = schema.validate(node); // Both the custom no_match format and the standard email format should fail. // This ensures that both the standard and custom formatters have been invoked. Assertions.assertEquals(2, errors.size()); diff --git a/src/test/java/com/networknt/schema/Issue857Test.java b/src/test/java/com/networknt/schema/Issue857Test.java index 722080918..946629d3d 100644 --- a/src/test/java/com/networknt/schema/Issue857Test.java +++ b/src/test/java/com/networknt/schema/Issue857Test.java @@ -21,8 +21,6 @@ import org.junit.jupiter.api.Test; -import com.networknt.schema.SpecVersion.VersionFlag; - class Issue857Test { @Test void test() { @@ -48,9 +46,9 @@ void test() { + " \"id\": \"4\"\r\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().failFast(true).build(); - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - List result = factory.getSchema(schema, config).validate(input, InputFormat.JSON); + SchemaRegistryConfig config = SchemaRegistryConfig.builder().failFast(true).build(); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12, builder -> builder.schemaRegistryConfig(config)); + List result = factory.getSchema(schema).validate(input, InputFormat.JSON); assertTrue(result.isEmpty()); } } diff --git a/src/test/java/com/networknt/schema/Issue877Test.java b/src/test/java/com/networknt/schema/Issue877Test.java index 899723d24..083580106 100644 --- a/src/test/java/com/networknt/schema/Issue877Test.java +++ b/src/test/java/com/networknt/schema/Issue877Test.java @@ -19,7 +19,6 @@ import org.junit.jupiter.api.Test; -import com.networknt.schema.SpecVersion.VersionFlag; import com.networknt.schema.serialization.JsonMapperFactory; class Issue877Test { @@ -30,14 +29,14 @@ void test() throws Exception { + " \"unevaluatedProperties\": false\n" + "}"; - JsonSchemaFactory jsonSchemaFactory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - JsonSchema schema = jsonSchemaFactory.getSchema(schemaData); + SchemaRegistry jsonSchemaFactory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12); + Schema schema = jsonSchemaFactory.getSchema(schemaData); String input = "{}"; - ValidationResult result = schema.walk(JsonMapperFactory.getInstance().readTree(input), true); - assertEquals(0, result.getValidationMessages().size()); + Result result = schema.walk(JsonMapperFactory.getInstance().readTree(input), true); + assertEquals(0, result.getErrors().size()); input = ""; result = schema.walk(JsonMapperFactory.getInstance().readTree(input), true); - assertEquals(1, result.getValidationMessages().size()); + assertEquals(1, result.getErrors().size()); } } diff --git a/src/test/java/com/networknt/schema/Issue898Test.java b/src/test/java/com/networknt/schema/Issue898Test.java index bbb97197a..45ee0ea23 100644 --- a/src/test/java/com/networknt/schema/Issue898Test.java +++ b/src/test/java/com/networknt/schema/Issue898Test.java @@ -13,13 +13,13 @@ class Issue898Test extends BaseJsonSchemaValidatorTest { @Test void testMessagesWithSingleQuotes() throws Exception { - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().locale(Locale.FRENCH).build(); + SchemaRegistryConfig config = SchemaRegistryConfig.builder().locale(Locale.FRENCH).build(); - JsonSchema schema = getJsonSchemaFromClasspath("schema/issue898.json", SpecVersion.VersionFlag.V202012, config); + Schema schema = getJsonSchemaFromClasspath("schema/issue898.json", SpecificationVersion.DRAFT_2020_12, config); JsonNode node = getJsonNodeFromClasspath("data/issue898.json"); List messages = schema.validate(node).stream() - .map(ValidationMessage::getMessage) + .map(Error::toString) .collect(toList()); Assertions.assertEquals(2, messages.size()); diff --git a/src/test/java/com/networknt/schema/Issue927Test.java b/src/test/java/com/networknt/schema/Issue927Test.java index 690abbe40..0d1270375 100644 --- a/src/test/java/com/networknt/schema/Issue927Test.java +++ b/src/test/java/com/networknt/schema/Issue927Test.java @@ -22,7 +22,6 @@ import org.junit.jupiter.api.Test; import com.fasterxml.jackson.core.JsonProcessingException; -import com.networknt.schema.SpecVersion.VersionFlag; import com.networknt.schema.serialization.JsonMapperFactory; /** @@ -105,7 +104,7 @@ void test() throws JsonProcessingException { + " }\r\n" + " }\r\n" + "}"; - JsonSchema jsonSchema = JsonSchemaFactory.getInstance(VersionFlag.V7) + Schema jsonSchema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7) .getSchema(SchemaLocation.of("http://www.example.org"), JsonMapperFactory.getInstance().readTree(schema)); String input = "{\r\n" @@ -127,7 +126,7 @@ void test() throws JsonProcessingException { + " ]\r\n" + " }\r\n" + "}"; - List messages = jsonSchema.validate(input, InputFormat.JSON); + List messages = jsonSchema.validate(input, InputFormat.JSON); assertEquals(0, messages.size()); } diff --git a/src/test/java/com/networknt/schema/Issue928Test.java b/src/test/java/com/networknt/schema/Issue928Test.java index 2b70f0a30..7bbe0f1e9 100644 --- a/src/test/java/com/networknt/schema/Issue928Test.java +++ b/src/test/java/com/networknt/schema/Issue928Test.java @@ -7,44 +7,44 @@ class Issue928Test { private final ObjectMapper mapper = new ObjectMapper(); - private JsonSchemaFactory factoryFor(SpecVersion.VersionFlag version) { - return JsonSchemaFactory - .builder(JsonSchemaFactory.getInstance(version)) - .schemaMappers(schemaMappers -> schemaMappers.mapPrefix("https://example.org", "classpath:")) + private SchemaRegistry factoryFor(SpecificationVersion version) { + return SchemaRegistry + .builder(SchemaRegistry.withDefaultDialect(version)) + .schemaIdResolvers(schemaIdResolvers -> schemaIdResolvers.mapPrefix("https://example.org", "classpath:")) .build(); } @Test void test_07() { - test_spec(SpecVersion.VersionFlag.V7); + test_spec(SpecificationVersion.DRAFT_7); } @Test void test_201909() { - test_spec(SpecVersion.VersionFlag.V201909); + test_spec(SpecificationVersion.DRAFT_2019_09); } @Test void test_202012() { - test_spec(SpecVersion.VersionFlag.V202012); + test_spec(SpecificationVersion.DRAFT_2020_12); } - void test_spec(SpecVersion.VersionFlag specVersion) { - JsonSchemaFactory schemaFactory = factoryFor(specVersion); + void test_spec(SpecificationVersion specVersion) { + SchemaRegistry schemaFactory = factoryFor(specVersion); - String versionId = specVersion.getId(); + String versionId = specVersion.getDialectId(); String versionStr = versionId.substring(versionId.indexOf("draft") + 6, versionId.indexOf("/schema")); String baseUrl = String.format("https://example.org/schema/issue928-v%s.json", versionStr); System.out.println("baseUrl: " + baseUrl); - JsonSchema byPointer = schemaFactory.getSchema( + Schema byPointer = schemaFactory.getSchema( SchemaLocation.of(baseUrl + "#/definitions/example")); Assertions.assertEquals(byPointer.validate(mapper.valueToTree("A")).size(), 0); Assertions.assertEquals(byPointer.validate(mapper.valueToTree("Z")).size(), 1); - JsonSchema byAnchor = schemaFactory.getSchema( + Schema byAnchor = schemaFactory.getSchema( SchemaLocation.of(baseUrl + "#example")); Assertions.assertEquals( diff --git a/src/test/java/com/networknt/schema/Issue935Test.java b/src/test/java/com/networknt/schema/Issue935Test.java index e604cf0b3..13ba128ff 100644 --- a/src/test/java/com/networknt/schema/Issue935Test.java +++ b/src/test/java/com/networknt/schema/Issue935Test.java @@ -19,13 +19,11 @@ import org.junit.jupiter.api.Test; -import com.networknt.schema.SpecVersion.VersionFlag; - class Issue935Test { @Test void shouldThrowInvalidSchemaException() { String schema = "{ \"$schema\": \"0\" }"; assertThrowsExactly(InvalidSchemaException.class, - () -> JsonSchemaFactory.getInstance(VersionFlag.V201909).getSchema(schema)); + () -> SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2019_09).getSchema(schema)); } } diff --git a/src/test/java/com/networknt/schema/Issue936Test.java b/src/test/java/com/networknt/schema/Issue936Test.java index fe8d9300f..925e6c0e3 100644 --- a/src/test/java/com/networknt/schema/Issue936Test.java +++ b/src/test/java/com/networknt/schema/Issue936Test.java @@ -20,22 +20,20 @@ import org.junit.jupiter.api.Test; -import com.networknt.schema.SpecVersion.VersionFlag; - class Issue936Test { @Test void shouldThrowInvalidSchemaException() { String schema = "{\r\n" + " \"$id\": \"0\",\r\n" + " \"$schema\": \"https://json-schema.org/draft/2020-12/schema\"\r\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder() - .schemaIdValidator(JsonSchemaIdValidator.DEFAULT) + SchemaRegistryConfig config = SchemaRegistryConfig.builder() + .schemaIdValidator(SchemaIdValidator.DEFAULT) .build(); assertThrowsExactly(InvalidSchemaException.class, - () -> JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schema, config)); + () -> SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12, builder -> builder.schemaRegistryConfig(config)).getSchema(schema)); try { - JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schema, config); + SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12, builder -> builder.schemaRegistryConfig(config)).getSchema(schema); } catch (InvalidSchemaException e) { - assertEquals("/$id: '0' is not a valid $id", e.getMessage()); + assertEquals("/$id: '0' is not a valid $id", e.getError().toString()); } } } diff --git a/src/test/java/com/networknt/schema/Issue939Test.java b/src/test/java/com/networknt/schema/Issue939Test.java index 7ca3a449d..4c75ce86f 100644 --- a/src/test/java/com/networknt/schema/Issue939Test.java +++ b/src/test/java/com/networknt/schema/Issue939Test.java @@ -22,8 +22,6 @@ import org.junit.jupiter.api.Test; -import com.networknt.schema.SpecVersion.VersionFlag; - class Issue939Test { @Test void shouldNotThrowException() { @@ -48,9 +46,9 @@ void shouldNotThrowException() { + " }\r\n" + " }\r\n" + " }"; - JsonSchema jsonSchema = JsonSchemaFactory.getInstance(VersionFlag.V7).getSchema(schema); + Schema jsonSchema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7).getSchema(schema); assertDoesNotThrow(() -> jsonSchema.initializeValidators()); - List assertions = jsonSchema + List assertions = jsonSchema .validate("{\"someUuid\":\"invalid\"}", InputFormat.JSON); assertEquals(2, assertions.size()); } diff --git a/src/test/java/com/networknt/schema/Issue940Test.java b/src/test/java/com/networknt/schema/Issue940Test.java index 75b19a7a7..8dbd10233 100644 --- a/src/test/java/com/networknt/schema/Issue940Test.java +++ b/src/test/java/com/networknt/schema/Issue940Test.java @@ -19,8 +19,6 @@ import org.junit.jupiter.api.Test; -import com.networknt.schema.SpecVersion.VersionFlag; - class Issue940Test { @Test void shouldNotThrowException() { @@ -31,7 +29,7 @@ void shouldNotThrowException() { + " \"greeting\": {}\r\n" + " }\r\n" + "}"; - JsonSchema jsonSchema = JsonSchemaFactory.getInstance(VersionFlag.V7).getSchema(schema); + Schema jsonSchema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7).getSchema(schema); assertDoesNotThrow(() -> jsonSchema.initializeValidators()); } } diff --git a/src/test/java/com/networknt/schema/Issue943Test.java b/src/test/java/com/networknt/schema/Issue943Test.java index d90bcbd7d..3e85907d7 100644 --- a/src/test/java/com/networknt/schema/Issue943Test.java +++ b/src/test/java/com/networknt/schema/Issue943Test.java @@ -23,8 +23,6 @@ import org.junit.jupiter.api.Test; -import com.networknt.schema.SpecVersion.VersionFlag; - class Issue943Test { @Test void test() { @@ -67,10 +65,9 @@ void test() { + " \"type\": \"Point\",\r\n" + " \"coordinates\": [1, 1]\r\n" + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012, - builder -> builder.schemaLoaders(schemaLoaders -> schemaLoaders.schemas(external))); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema schema = factory.getSchema(schemaData, config); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12, + builder -> builder.resourceLoaders(resourceLoaders -> resourceLoaders.resources(external))); + Schema schema = factory.getSchema(schemaData); assertTrue(schema.validate(inputData, InputFormat.JSON).isEmpty()); String badData = "{\r\n" diff --git a/src/test/java/com/networknt/schema/Issue994Test.java b/src/test/java/com/networknt/schema/Issue994Test.java index ae3e4eee6..f1c4156fe 100644 --- a/src/test/java/com/networknt/schema/Issue994Test.java +++ b/src/test/java/com/networknt/schema/Issue994Test.java @@ -22,8 +22,10 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; -import com.networknt.schema.SpecVersion.VersionFlag; +import com.networknt.schema.dialect.Dialect; +import com.networknt.schema.dialect.Dialects; import com.networknt.schema.serialization.JsonMapperFactory; +import com.networknt.schema.vocabulary.Vocabulary; class Issue994Test { @Test @@ -41,12 +43,12 @@ void test() throws JsonProcessingException { + " }\r\n" + " }\r\n" + "}"; - JsonMetaSchema metaSchema = JsonMetaSchema.builder(JsonMetaSchema.getV202012()).vocabularies(vocabularies -> { - vocabularies.remove(Vocabulary.V202012_VALIDATION.getIri()); + Dialect dialect = Dialect.builder(Dialects.getDraft202012()).vocabularies(vocabularies -> { + vocabularies.remove(Vocabulary.DRAFT_2020_12_VALIDATION.getId()); }).build(); JsonNode schemaNode = JsonMapperFactory.getInstance().readTree(schemaData); - JsonSchema schema = JsonSchemaFactory - .getInstance(VersionFlag.V202012, builder -> builder.metaSchema(metaSchema)).getSchema(schemaNode); + Schema schema = SchemaRegistry + .withDialect(dialect).getSchema(schemaNode); String inputData = "{\r\n" + " \"textValue\": \"hello\"\r\n" + "}"; diff --git a/src/test/java/com/networknt/schema/ItemsLegacyValidatorTest.java b/src/test/java/com/networknt/schema/ItemsLegacyValidatorTest.java new file mode 100644 index 000000000..4c90f6ddb --- /dev/null +++ b/src/test/java/com/networknt/schema/ItemsLegacyValidatorTest.java @@ -0,0 +1,358 @@ +/* + * Copyright (c) 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.networknt.schema; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.jupiter.api.Test; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.serialization.JsonMapperFactory; +import com.networknt.schema.walk.ApplyDefaultsStrategy; +import com.networknt.schema.walk.ItemWalkListenerRunner; +import com.networknt.schema.walk.WalkListener; +import com.networknt.schema.walk.WalkConfig; +import com.networknt.schema.walk.WalkEvent; +import com.networknt.schema.walk.WalkFlow; + +/** + * ItemsLegacyValidatorTest. + */ +class ItemsLegacyValidatorTest { + /** + * Tests that the message contains the correct values when there are invalid + * items. + */ + @Test + void messageInvalid() { + String schemaData = "{\r\n" + + " \"$id\": \"https://www.example.org/schema\",\r\n" + + " \"items\": {\"type\": \"integer\"}" + + "}"; + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2019_09); + Schema schema = factory.getSchema(schemaData); + String inputData = "[1, \"x\"]"; + List messages = schema.validate(inputData, InputFormat.JSON); + assertFalse(messages.isEmpty()); + Error message = messages.iterator().next(); + assertEquals("/items/type", message.getEvaluationPath().toString()); + assertEquals("https://www.example.org/schema#/items/type", message.getSchemaLocation().toString()); + assertEquals("/1", message.getInstanceLocation().toString()); + assertEquals("\"integer\"", message.getSchemaNode().toString()); + assertEquals("\"x\"", message.getInstanceNode().toString()); + assertEquals("/1: string found, integer expected", message.toString()); + assertNull(message.getProperty()); + } + + /** + * Tests that the message contains the correct values when there are invalid + * items. + */ + @Test + void messageAdditionalItemsInvalid() { + String schemaData = "{\r\n" + + " \"$id\": \"https://www.example.org/schema\",\r\n" + + " \"items\": [{}]," + + " \"additionalItems\": {\"type\": \"integer\"}" + + "}"; + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2019_09); + Schema schema = factory.getSchema(schemaData); + String inputData = "[ null, 2, 3, \"foo\" ]"; + List messages = schema.validate(inputData, InputFormat.JSON); + assertFalse(messages.isEmpty()); + Error message = messages.iterator().next(); + assertEquals("/additionalItems/type", message.getEvaluationPath().toString()); + assertEquals("https://www.example.org/schema#/additionalItems/type", message.getSchemaLocation().toString()); + assertEquals("/3", message.getInstanceLocation().toString()); + assertEquals("\"integer\"", message.getSchemaNode().toString()); + assertEquals("\"foo\"", message.getInstanceNode().toString()); + assertEquals("/3: string found, integer expected", message.toString()); + assertNull(message.getProperty()); + } + + /** + * Tests that the message contains the correct values when there are invalid + * items. + */ + @Test + void messageAdditionalItemsFalseInvalid() { + String schemaData = "{\r\n" + + " \"$id\": \"https://www.example.org/schema\",\r\n" + + " \"items\": [{}]," + + " \"additionalItems\": false" + + "}"; + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2019_09); + Schema schema = factory.getSchema(schemaData); + String inputData = "[ null, 2, 3, \"foo\" ]"; + List messages = schema.validate(inputData, InputFormat.JSON); + assertFalse(messages.isEmpty()); + Error message = messages.iterator().next(); + assertEquals("/additionalItems", message.getEvaluationPath().toString()); + assertEquals("https://www.example.org/schema#/additionalItems", message.getSchemaLocation().toString()); + assertEquals("", message.getInstanceLocation().toString()); + assertEquals("false", message.getSchemaNode().toString()); + assertEquals("[null,2,3,\"foo\"]", message.getInstanceNode().toString()); + assertEquals(": index '1' is not defined in the schema and the schema does not allow additional items", message.toString()); + assertNull(message.getProperty()); + } + + @Test + void walk() { + String schemaData = "{\r\n" + + " \"items\": {\r\n" + + " \"type\": \"string\"\r\n" + + " }\r\n" + + "}"; + ItemWalkListenerRunner itemWalkListenerRunner = ItemWalkListenerRunner.builder() + .itemWalkListener(new WalkListener() { + @Override + public WalkFlow onWalkStart(WalkEvent walkEvent) { + return WalkFlow.CONTINUE; + } + + @Override + public void onWalkEnd(WalkEvent walkEvent, List errors) { + @SuppressWarnings("unchecked") + List items = (List) walkEvent.getExecutionContext() + .getCollectorContext() + .getData() + .computeIfAbsent("items", key -> new ArrayList()); + items.add(walkEvent); + } + }).build(); + WalkConfig walkConfig = WalkConfig.builder().itemWalkListenerRunner(itemWalkListenerRunner).build(); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2019_09); + Schema schema = factory.getSchema(schemaData); + Result result = schema.walk("[\"the\",\"quick\",\"brown\"]", InputFormat.JSON, true, executionContext -> executionContext.setWalkConfig(walkConfig)); + assertTrue(result.getErrors().isEmpty()); + + @SuppressWarnings("unchecked") + List items = (List) result.getExecutionContext().getCollectorContext().get("items"); + assertEquals(3, items.size()); + assertEquals("/0", items.get(0).getInstanceLocation().toString()); + assertEquals("/1", items.get(1).getInstanceLocation().toString()); + assertEquals("/2", items.get(2).getInstanceLocation().toString()); + } + + @Test + void walkNull() { + String schemaData = "{\r\n" + + " \"items\": {\r\n" + + " \"type\": \"string\"\r\n" + + " }\r\n" + + "}"; + ItemWalkListenerRunner itemWalkListenerRunner = ItemWalkListenerRunner.builder() + .itemWalkListener(new WalkListener() { + @Override + public WalkFlow onWalkStart(WalkEvent walkEvent) { + return WalkFlow.CONTINUE; + } + + @Override + public void onWalkEnd(WalkEvent walkEvent, List errors) { + @SuppressWarnings("unchecked") + List items = (List) walkEvent.getExecutionContext() + .getCollectorContext() + .getData() + .computeIfAbsent("items", key -> new ArrayList()); + items.add(walkEvent); + } + }).build(); + WalkConfig walkConfig = WalkConfig.builder().itemWalkListenerRunner(itemWalkListenerRunner).build(); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2019_09); + Schema schema = factory.getSchema(schemaData); + Result result = schema.walk(null, true, executionContext -> executionContext.setWalkConfig(walkConfig)); + assertTrue(result.getErrors().isEmpty()); + + @SuppressWarnings("unchecked") + List items = (List) result.getExecutionContext().getCollectorContext().get("items"); + assertEquals(1, items.size()); + assertEquals("/0", items.get(0).getInstanceLocation().toString()); + } + + @Test + void walkNullTupleItemsAdditional() { + String schemaData = "{\r\n" + + " \"items\": [\r\n" + + " {\r\n" + + " \"type\": \"string\"\r\n" + + " }\r\n," + + " {\r\n" + + " \"type\": \"integer\"\r\n" + + " }\r\n" + + " ],\r\n" + + " \"additionalItems\": {\r\n" + + " \"type\": \"string\"\r\n" + + " }\r\n" + + "}"; + ItemWalkListenerRunner itemWalkListenerRunner = ItemWalkListenerRunner.builder() + .itemWalkListener(new WalkListener() { + @Override + public WalkFlow onWalkStart(WalkEvent walkEvent) { + return WalkFlow.CONTINUE; + } + + @Override + public void onWalkEnd(WalkEvent walkEvent, List errors) { + @SuppressWarnings("unchecked") + List items = (List) walkEvent.getExecutionContext() + .getCollectorContext() + .getData() + .computeIfAbsent("items", key -> new ArrayList()); + items.add(walkEvent); + } + }).build(); + WalkConfig walkConfig = WalkConfig.builder().itemWalkListenerRunner(itemWalkListenerRunner).build(); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2019_09); + Schema schema = factory.getSchema(schemaData); + Result result = schema.walk(null, true, executionContext -> executionContext.setWalkConfig(walkConfig)); + assertTrue(result.getErrors().isEmpty()); + + @SuppressWarnings("unchecked") + List items = (List) result.getExecutionContext().getCollectorContext().get("items"); + assertEquals(3, items.size()); + assertEquals("/0", items.get(0).getInstanceLocation().toString()); + assertEquals("items", items.get(0).getKeyword()); + assertNull(items.get(0).getInstanceNode()); + assertEquals("/1", items.get(1).getInstanceLocation().toString()); + assertEquals("items", items.get(1).getKeyword()); + assertNull(items.get(1).getInstanceNode()); + assertEquals("/2", items.get(2).getInstanceLocation().toString()); + assertEquals("additionalItems", items.get(2).getKeyword()); + assertNull(items.get(2).getInstanceNode()); + } + + @Test + void walkTupleItemsAdditional() throws JsonProcessingException { + String schemaData = "{\r\n" + + " \"items\": [\r\n" + + " {\r\n" + + " \"type\": \"string\"\r\n" + + " }\r\n," + + " {\r\n" + + " \"type\": \"integer\"\r\n" + + " }\r\n" + + " ],\r\n" + + " \"additionalItems\": {\r\n" + + " \"type\": \"string\"\r\n" + + " }\r\n" + + "}"; + ItemWalkListenerRunner itemWalkListenerRunner = ItemWalkListenerRunner.builder() + .itemWalkListener(new WalkListener() { + @Override + public WalkFlow onWalkStart(WalkEvent walkEvent) { + return WalkFlow.CONTINUE; + } + + @Override + public void onWalkEnd(WalkEvent walkEvent, List errors) { + @SuppressWarnings("unchecked") + List items = (List) walkEvent.getExecutionContext() + .getCollectorContext() + .getData() + .computeIfAbsent("items", key -> new ArrayList()); + items.add(walkEvent); + } + }).build(); + WalkConfig walkConfig = WalkConfig.builder().itemWalkListenerRunner(itemWalkListenerRunner) + .build(); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2019_09); + Schema schema = factory.getSchema(schemaData); + JsonNode input = JsonMapperFactory.getInstance().readTree("[\"hello\"]"); + Result result = schema.walk(input, true, executionContext -> executionContext.setWalkConfig(walkConfig)); + assertTrue(result.getErrors().isEmpty()); + + @SuppressWarnings("unchecked") + List items = (List) result.getExecutionContext().getCollectorContext().get("items"); + assertEquals(3, items.size()); + assertEquals("/0", items.get(0).getInstanceLocation().toString()); + assertEquals("items", items.get(0).getKeyword()); + assertEquals("hello", items.get(0).getInstanceNode().textValue()); + assertEquals("/1", items.get(1).getInstanceLocation().toString()); + assertEquals("items", items.get(1).getKeyword()); + assertNull(items.get(1).getInstanceNode()); + assertEquals("/2", items.get(2).getInstanceLocation().toString()); + assertEquals("additionalItems", items.get(2).getKeyword()); + assertNull(items.get(2).getInstanceNode()); + } + + @Test + void walkTupleItemsAdditionalDefaults() throws JsonProcessingException { + String schemaData = "{\r\n" + + " \"items\": [\r\n" + + " {\r\n" + + " \"type\": \"string\",\r\n" + + " \"default\": \"1\"\r\n" + + " },\r\n" + + " {\r\n" + + " \"type\": \"integer\",\r\n" + + " \"default\": 2\r\n" + + " }\r\n" + + " ],\r\n" + + " \"additionalItems\": {\r\n" + + " \"type\": \"string\",\r\n" + + " \"default\": \"additional\"\r\n" + + " }\r\n" + + "}"; + + ItemWalkListenerRunner itemWalkListenerRunner = ItemWalkListenerRunner.builder() + .itemWalkListener(new WalkListener() { + @Override + public WalkFlow onWalkStart(WalkEvent walkEvent) { + return WalkFlow.CONTINUE; + } + + @Override + public void onWalkEnd(WalkEvent walkEvent, List errors) { + @SuppressWarnings("unchecked") + List items = (List) walkEvent.getExecutionContext().getCollectorContext() + .getData().computeIfAbsent("items", key -> new ArrayList()); + items.add(walkEvent); + } + }).build(); + WalkConfig walkConfig = WalkConfig.builder().itemWalkListenerRunner(itemWalkListenerRunner) + .applyDefaultsStrategy(new ApplyDefaultsStrategy(true, true, true)).build(); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2019_09); + Schema schema = factory.getSchema(schemaData); + JsonNode input = JsonMapperFactory.getInstance().readTree("[null, null, null, null]"); + Result result = schema.walk(input, true, executionContext -> executionContext.setWalkConfig(walkConfig)); + assertTrue(result.getErrors().isEmpty()); + + @SuppressWarnings("unchecked") + List items = (List) result.getExecutionContext().getCollectorContext().get("items"); + assertEquals(4, items.size()); + assertEquals("/0", items.get(0).getInstanceLocation().toString()); + assertEquals("items", items.get(0).getKeyword()); + assertEquals("1", items.get(0).getInstanceNode().textValue()); + assertEquals("/1", items.get(1).getInstanceLocation().toString()); + assertEquals("items", items.get(1).getKeyword()); + assertEquals(2, items.get(1).getInstanceNode().intValue()); + assertEquals("/2", items.get(2).getInstanceLocation().toString()); + assertEquals("additionalItems", items.get(2).getKeyword()); + assertEquals("additional", items.get(2).getInstanceNode().asText()); + assertEquals("/3", items.get(3).getInstanceLocation().toString()); + assertEquals("additionalItems", items.get(3).getKeyword()); + assertEquals("additional", items.get(3).getInstanceNode().asText()); + } +} diff --git a/src/test/java/com/networknt/schema/ItemsValidator202012Test.java b/src/test/java/com/networknt/schema/ItemsValidator202012Test.java deleted file mode 100644 index f6f6fccb1..000000000 --- a/src/test/java/com/networknt/schema/ItemsValidator202012Test.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (c) 2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.networknt.schema; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.util.ArrayList; -import java.util.List; - -import org.junit.jupiter.api.Test; - -import com.networknt.schema.SpecVersion.VersionFlag; -import com.networknt.schema.walk.JsonSchemaWalkListener; -import com.networknt.schema.walk.WalkEvent; -import com.networknt.schema.walk.WalkFlow; - -/** - * ItemsValidatorTest. - */ -class ItemsValidator202012Test { - /** - * Tests that the message contains the correct values when there are invalid - * items. - */ - @Test - void messageInvalid() { - String schemaData = "{\r\n" - + " \"$id\": \"https://www.example.org/schema\",\r\n" - + " \"items\": {\"type\": \"integer\"}" - + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema schema = factory.getSchema(schemaData, config); - String inputData = "[1, \"x\"]"; - List messages = schema.validate(inputData, InputFormat.JSON); - assertFalse(messages.isEmpty()); - ValidationMessage message = messages.iterator().next(); - assertEquals("/items/type", message.getEvaluationPath().toString()); - assertEquals("https://www.example.org/schema#/items/type", message.getSchemaLocation().toString()); - assertEquals("/1", message.getInstanceLocation().toString()); - assertEquals("\"integer\"", message.getSchemaNode().toString()); - assertEquals("\"x\"", message.getInstanceNode().toString()); - assertEquals("/1: string found, integer expected", message.getMessage()); - assertNull(message.getProperty()); - } - - @Test - void walkNull() { - String schemaData = "{\r\n" - + " \"items\": {\r\n" - + " \"type\": \"string\"\r\n" - + " }\r\n" - + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().itemWalkListener(new JsonSchemaWalkListener() { - @Override - public WalkFlow onWalkStart(WalkEvent walkEvent) { - return WalkFlow.CONTINUE; - } - - @Override - public void onWalkEnd(WalkEvent walkEvent, List validationMessages) { - @SuppressWarnings("unchecked") - List items = (List) walkEvent.getExecutionContext() - .getCollectorContext() - .getCollectorMap() - .computeIfAbsent("items", key -> new ArrayList()); - items.add(walkEvent); - } - }).build(); - JsonSchema schema = factory.getSchema(schemaData, config); - ValidationResult result = schema.walk(null, true); - assertTrue(result.getValidationMessages().isEmpty()); - - @SuppressWarnings("unchecked") - List items = (List) result.getExecutionContext().getCollectorContext().get("items"); - assertEquals(1, items.size()); - assertEquals("/0", items.get(0).getInstanceLocation().toString()); - } - - @Test - void walkNullPrefixItems() { - String schemaData = "{\r\n" - + " \"prefixItems\": [\r\n" - + " {\r\n" - + " \"type\": \"integer\"\r\n" - + " }\r\n" - + " ],\r\n" - + " \"items\": {\r\n" - + " \"type\": \"string\"\r\n" - + " }\r\n" - + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().itemWalkListener(new JsonSchemaWalkListener() { - @Override - public WalkFlow onWalkStart(WalkEvent walkEvent) { - return WalkFlow.CONTINUE; - } - - @Override - public void onWalkEnd(WalkEvent walkEvent, List validationMessages) { - @SuppressWarnings("unchecked") - List items = (List) walkEvent.getExecutionContext() - .getCollectorContext() - .getCollectorMap() - .computeIfAbsent("items", key -> new ArrayList()); - items.add(walkEvent); - } - }).build(); - JsonSchema schema = factory.getSchema(schemaData, config); - ValidationResult result = schema.walk(null, true); - assertTrue(result.getValidationMessages().isEmpty()); - - @SuppressWarnings("unchecked") - List items = (List) result.getExecutionContext().getCollectorContext().get("items"); - assertEquals(2, items.size()); - assertEquals("/0", items.get(0).getInstanceLocation().toString()); - assertEquals("prefixItems", items.get(0).getKeyword()); - assertEquals("/1", items.get(1).getInstanceLocation().toString()); - assertEquals("items", items.get(1).getKeyword()); - } -} diff --git a/src/test/java/com/networknt/schema/ItemsValidatorTest.java b/src/test/java/com/networknt/schema/ItemsValidatorTest.java index 78c37ff28..75d1bed58 100644 --- a/src/test/java/com/networknt/schema/ItemsValidatorTest.java +++ b/src/test/java/com/networknt/schema/ItemsValidatorTest.java @@ -25,11 +25,10 @@ import org.junit.jupiter.api.Test; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.networknt.schema.SpecVersion.VersionFlag; -import com.networknt.schema.serialization.JsonMapperFactory; -import com.networknt.schema.walk.JsonSchemaWalkListener; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.walk.ItemWalkListenerRunner; +import com.networknt.schema.walk.WalkListener; +import com.networknt.schema.walk.WalkConfig; import com.networknt.schema.walk.WalkEvent; import com.networknt.schema.walk.WalkFlow; @@ -47,112 +46,21 @@ void messageInvalid() { + " \"$id\": \"https://www.example.org/schema\",\r\n" + " \"items\": {\"type\": \"integer\"}" + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V201909); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema schema = factory.getSchema(schemaData, config); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12); + Schema schema = factory.getSchema(schemaData); String inputData = "[1, \"x\"]"; - List messages = schema.validate(inputData, InputFormat.JSON); + List messages = schema.validate(inputData, InputFormat.JSON); assertFalse(messages.isEmpty()); - ValidationMessage message = messages.iterator().next(); + Error message = messages.iterator().next(); assertEquals("/items/type", message.getEvaluationPath().toString()); assertEquals("https://www.example.org/schema#/items/type", message.getSchemaLocation().toString()); assertEquals("/1", message.getInstanceLocation().toString()); assertEquals("\"integer\"", message.getSchemaNode().toString()); assertEquals("\"x\"", message.getInstanceNode().toString()); - assertEquals("/1: string found, integer expected", message.getMessage()); + assertEquals("/1: string found, integer expected", message.toString()); assertNull(message.getProperty()); } - /** - * Tests that the message contains the correct values when there are invalid - * items. - */ - @Test - void messageAdditionalItemsInvalid() { - String schemaData = "{\r\n" - + " \"$id\": \"https://www.example.org/schema\",\r\n" - + " \"items\": [{}]," - + " \"additionalItems\": {\"type\": \"integer\"}" - + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V201909); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema schema = factory.getSchema(schemaData, config); - String inputData = "[ null, 2, 3, \"foo\" ]"; - List messages = schema.validate(inputData, InputFormat.JSON); - assertFalse(messages.isEmpty()); - ValidationMessage message = messages.iterator().next(); - assertEquals("/additionalItems/type", message.getEvaluationPath().toString()); - assertEquals("https://www.example.org/schema#/additionalItems/type", message.getSchemaLocation().toString()); - assertEquals("/3", message.getInstanceLocation().toString()); - assertEquals("\"integer\"", message.getSchemaNode().toString()); - assertEquals("\"foo\"", message.getInstanceNode().toString()); - assertEquals("/3: string found, integer expected", message.getMessage()); - assertNull(message.getProperty()); - } - - /** - * Tests that the message contains the correct values when there are invalid - * items. - */ - @Test - void messageAdditionalItemsFalseInvalid() { - String schemaData = "{\r\n" - + " \"$id\": \"https://www.example.org/schema\",\r\n" - + " \"items\": [{}]," - + " \"additionalItems\": false" - + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V201909); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema schema = factory.getSchema(schemaData, config); - String inputData = "[ null, 2, 3, \"foo\" ]"; - List messages = schema.validate(inputData, InputFormat.JSON); - assertFalse(messages.isEmpty()); - ValidationMessage message = messages.iterator().next(); - assertEquals("/additionalItems", message.getEvaluationPath().toString()); - assertEquals("https://www.example.org/schema#/additionalItems", message.getSchemaLocation().toString()); - assertEquals("", message.getInstanceLocation().toString()); - assertEquals("false", message.getSchemaNode().toString()); - assertEquals("[null,2,3,\"foo\"]", message.getInstanceNode().toString()); - assertEquals(": index '1' is not defined in the schema and the schema does not allow additional items", message.getMessage()); - assertNull(message.getProperty()); - } - - @Test - void walk() { - String schemaData = "{\r\n" - + " \"items\": {\r\n" - + " \"type\": \"string\"\r\n" - + " }\r\n" - + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V201909); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().itemWalkListener(new JsonSchemaWalkListener() { - @Override - public WalkFlow onWalkStart(WalkEvent walkEvent) { - return WalkFlow.CONTINUE; - } - - @Override - public void onWalkEnd(WalkEvent walkEvent, List validationMessages) { - @SuppressWarnings("unchecked") - List items = (List) walkEvent.getExecutionContext() - .getCollectorContext() - .getCollectorMap() - .computeIfAbsent("items", key -> new ArrayList()); - items.add(walkEvent); - } - }).build(); - JsonSchema schema = factory.getSchema(schemaData, config); - ValidationResult result = schema.walk("[\"the\",\"quick\",\"brown\"]", InputFormat.JSON, true); - assertTrue(result.getValidationMessages().isEmpty()); - - @SuppressWarnings("unchecked") - List items = (List) result.getExecutionContext().getCollectorContext().get("items"); - assertEquals(3, items.size()); - assertEquals("/0", items.get(0).getInstanceLocation().toString()); - assertEquals("/1", items.get(1).getInstanceLocation().toString()); - assertEquals("/2", items.get(2).getInstanceLocation().toString()); - } - @Test void walkNull() { String schemaData = "{\r\n" @@ -160,26 +68,29 @@ void walkNull() { + " \"type\": \"string\"\r\n" + " }\r\n" + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V201909); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().itemWalkListener(new JsonSchemaWalkListener() { + ItemWalkListenerRunner itemWalkListenerRunner = ItemWalkListenerRunner.builder().itemWalkListener(new WalkListener() { @Override public WalkFlow onWalkStart(WalkEvent walkEvent) { return WalkFlow.CONTINUE; } @Override - public void onWalkEnd(WalkEvent walkEvent, List validationMessages) { + public void onWalkEnd(WalkEvent walkEvent, List errors) { @SuppressWarnings("unchecked") List items = (List) walkEvent.getExecutionContext() .getCollectorContext() - .getCollectorMap() - .computeIfAbsent("items", key -> new ArrayList()); + .getData() + .computeIfAbsent("items", key -> new ArrayList()); items.add(walkEvent); } }).build(); - JsonSchema schema = factory.getSchema(schemaData, config); - ValidationResult result = schema.walk(null, true); - assertTrue(result.getValidationMessages().isEmpty()); + WalkConfig walkConfig = WalkConfig.builder() + .itemWalkListenerRunner(itemWalkListenerRunner) + .build(); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12); + Schema schema = factory.getSchema(schemaData); + Result result = schema.walk(null, true, executionContext -> executionContext.setWalkConfig(walkConfig)); + assertTrue(result.getErrors().isEmpty()); @SuppressWarnings("unchecked") List items = (List) result.getExecutionContext().getCollectorContext().get("items"); @@ -188,164 +99,47 @@ public void onWalkEnd(WalkEvent walkEvent, List validationMes } @Test - void walkNullTupleItemsAdditional() { + void walkNullPrefixItems() { String schemaData = "{\r\n" - + " \"items\": [\r\n" - + " {\r\n" - + " \"type\": \"string\"\r\n" - + " }\r\n," + + " \"prefixItems\": [\r\n" + " {\r\n" + " \"type\": \"integer\"\r\n" + " }\r\n" + " ],\r\n" - + " \"additionalItems\": {\r\n" - + " \"type\": \"string\"\r\n" - + " }\r\n" - + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V201909); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().itemWalkListener(new JsonSchemaWalkListener() { - @Override - public WalkFlow onWalkStart(WalkEvent walkEvent) { - return WalkFlow.CONTINUE; - } - - @Override - public void onWalkEnd(WalkEvent walkEvent, List validationMessages) { - @SuppressWarnings("unchecked") - List items = (List) walkEvent.getExecutionContext() - .getCollectorContext() - .getCollectorMap() - .computeIfAbsent("items", key -> new ArrayList()); - items.add(walkEvent); - } - }).build(); - JsonSchema schema = factory.getSchema(schemaData, config); - ValidationResult result = schema.walk(null, true); - assertTrue(result.getValidationMessages().isEmpty()); - - @SuppressWarnings("unchecked") - List items = (List) result.getExecutionContext().getCollectorContext().get("items"); - assertEquals(3, items.size()); - assertEquals("/0", items.get(0).getInstanceLocation().toString()); - assertEquals("items", items.get(0).getKeyword()); - assertNull(items.get(0).getInstanceNode()); - assertEquals("/1", items.get(1).getInstanceLocation().toString()); - assertEquals("items", items.get(1).getKeyword()); - assertNull(items.get(1).getInstanceNode()); - assertEquals("/2", items.get(2).getInstanceLocation().toString()); - assertEquals("additionalItems", items.get(2).getKeyword()); - assertNull(items.get(2).getInstanceNode()); - } - - @Test - void walkTupleItemsAdditional() throws JsonProcessingException { - String schemaData = "{\r\n" - + " \"items\": [\r\n" - + " {\r\n" - + " \"type\": \"string\"\r\n" - + " }\r\n," - + " {\r\n" - + " \"type\": \"integer\"\r\n" - + " }\r\n" - + " ],\r\n" - + " \"additionalItems\": {\r\n" + + " \"items\": {\r\n" + " \"type\": \"string\"\r\n" + " }\r\n" + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V201909); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().itemWalkListener(new JsonSchemaWalkListener() { + ItemWalkListenerRunner itemWalkListenerRunner = ItemWalkListenerRunner.builder().itemWalkListener(new WalkListener() { @Override public WalkFlow onWalkStart(WalkEvent walkEvent) { return WalkFlow.CONTINUE; } @Override - public void onWalkEnd(WalkEvent walkEvent, List validationMessages) { + public void onWalkEnd(WalkEvent walkEvent, List errors) { @SuppressWarnings("unchecked") List items = (List) walkEvent.getExecutionContext() .getCollectorContext() - .getCollectorMap() - .computeIfAbsent("items", key -> new ArrayList()); + .getData() + .computeIfAbsent("items", key -> new ArrayList()); items.add(walkEvent); } }).build(); - JsonSchema schema = factory.getSchema(schemaData, config); - JsonNode input = JsonMapperFactory.getInstance().readTree("[\"hello\"]"); - ValidationResult result = schema.walk(input, true); - assertTrue(result.getValidationMessages().isEmpty()); - - @SuppressWarnings("unchecked") - List items = (List) result.getExecutionContext().getCollectorContext().get("items"); - assertEquals(3, items.size()); - assertEquals("/0", items.get(0).getInstanceLocation().toString()); - assertEquals("items", items.get(0).getKeyword()); - assertEquals("hello", items.get(0).getInstanceNode().textValue()); - assertEquals("/1", items.get(1).getInstanceLocation().toString()); - assertEquals("items", items.get(1).getKeyword()); - assertNull(items.get(1).getInstanceNode()); - assertEquals("/2", items.get(2).getInstanceLocation().toString()); - assertEquals("additionalItems", items.get(2).getKeyword()); - assertNull(items.get(2).getInstanceNode()); - } - - @Test - void walkTupleItemsAdditionalDefaults() throws JsonProcessingException { - String schemaData = "{\r\n" - + " \"items\": [\r\n" - + " {\r\n" - + " \"type\": \"string\",\r\n" - + " \"default\": \"1\"\r\n" - + " },\r\n" - + " {\r\n" - + " \"type\": \"integer\",\r\n" - + " \"default\": 2\r\n" - + " }\r\n" - + " ],\r\n" - + " \"additionalItems\": {\r\n" - + " \"type\": \"string\",\r\n" - + " \"default\": \"additional\"\r\n" - + " }\r\n" - + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V201909); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder() - .applyDefaultsStrategy(new ApplyDefaultsStrategy(true, true, true)) - .itemWalkListener(new JsonSchemaWalkListener() { - - @Override - public WalkFlow onWalkStart(WalkEvent walkEvent) { - return WalkFlow.CONTINUE; - } - - @Override - public void onWalkEnd(WalkEvent walkEvent, List validationMessages) { - @SuppressWarnings("unchecked") - List items = (List) walkEvent.getExecutionContext() - .getCollectorContext() - .getCollectorMap() - .computeIfAbsent("items", key -> new ArrayList()); - items.add(walkEvent); - } - }) + WalkConfig walkConfig = WalkConfig.builder() + .itemWalkListenerRunner(itemWalkListenerRunner) .build(); - JsonSchema schema = factory.getSchema(schemaData, config); - JsonNode input = JsonMapperFactory.getInstance().readTree("[null, null, null, null]"); - ValidationResult result = schema.walk(input, true); - assertTrue(result.getValidationMessages().isEmpty()); - + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12); + Schema schema = factory.getSchema(schemaData); + Result result = schema.walk(null, true, executionContext -> executionContext.setWalkConfig(walkConfig)); + assertTrue(result.getErrors().isEmpty()); + @SuppressWarnings("unchecked") List items = (List) result.getExecutionContext().getCollectorContext().get("items"); - assertEquals(4, items.size()); + assertEquals(2, items.size()); assertEquals("/0", items.get(0).getInstanceLocation().toString()); - assertEquals("items", items.get(0).getKeyword()); - assertEquals("1", items.get(0).getInstanceNode().textValue()); + assertEquals("prefixItems", items.get(0).getKeyword()); assertEquals("/1", items.get(1).getInstanceLocation().toString()); assertEquals("items", items.get(1).getKeyword()); - assertEquals(2, items.get(1).getInstanceNode().intValue()); - assertEquals("/2", items.get(2).getInstanceLocation().toString()); - assertEquals("additionalItems", items.get(2).getKeyword()); - assertEquals("additional", items.get(2).getInstanceNode().asText()); - assertEquals("/3", items.get(3).getInstanceLocation().toString()); - assertEquals("additionalItems", items.get(3).getKeyword()); - assertEquals("additional", items.get(3).getInstanceNode().asText()); } } diff --git a/src/test/java/com/networknt/schema/JsonSchemaFactoryUriCacheTest.java b/src/test/java/com/networknt/schema/JsonSchemaFactoryUriCacheTest.java index 7297fde18..99fd3a603 100644 --- a/src/test/java/com/networknt/schema/JsonSchemaFactoryUriCacheTest.java +++ b/src/test/java/com/networknt/schema/JsonSchemaFactoryUriCacheTest.java @@ -2,8 +2,10 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import com.networknt.schema.dialect.BasicDialectRegistry; +import com.networknt.schema.dialect.Dialects; import com.networknt.schema.resource.InputStreamSource; -import com.networknt.schema.resource.SchemaLoader; +import com.networknt.schema.resource.ResourceLoader; import org.junit.jupiter.api.Test; @@ -31,27 +33,27 @@ void cacheDisabled() throws JsonProcessingException { private void runCacheTest(boolean enableCache) throws JsonProcessingException { CustomURIFetcher fetcher = new CustomURIFetcher(); - JsonSchemaFactory factory = buildJsonSchemaFactory(fetcher, enableCache); + SchemaRegistry factory = buildJsonSchemaFactory(fetcher, enableCache); SchemaLocation schemaUri = SchemaLocation.of("cache:uri_mapping/schema1.json"); String schema = "{ \"$schema\": \"https://json-schema.org/draft/2020-12/schema\", \"title\": \"json-object-with-schema\", \"type\": \"string\" }"; fetcher.addResource(schemaUri.getAbsoluteIri(), schema); - assertEquals(objectMapper.readTree(schema), factory.getSchema(schemaUri, SchemaValidatorsConfig.builder().build()).schemaNode); + assertEquals(objectMapper.readTree(schema), factory.getSchema(schemaUri).schemaNode); String modifiedSchema = "{ \"$schema\": \"https://json-schema.org/draft/2020-12/schema\", \"title\": \"json-object-with-schema\", \"type\": \"object\" }"; fetcher.addResource(schemaUri.getAbsoluteIri(), modifiedSchema); - assertEquals(objectMapper.readTree(enableCache ? schema : modifiedSchema), factory.getSchema(schemaUri, SchemaValidatorsConfig.builder().build()).schemaNode); + assertEquals(objectMapper.readTree(enableCache ? schema : modifiedSchema), factory.getSchema(schemaUri).schemaNode); } - private JsonSchemaFactory buildJsonSchemaFactory(CustomURIFetcher uriFetcher, boolean enableSchemaCache) { - return JsonSchemaFactory.builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V202012)) - .enableSchemaCache(enableSchemaCache) - .schemaLoaders(schemaLoaders -> schemaLoaders.add(uriFetcher)) - .metaSchema(JsonMetaSchema.getV202012()) + private SchemaRegistry buildJsonSchemaFactory(CustomURIFetcher uriFetcher, boolean enableSchemaCache) { + return SchemaRegistry.builder(SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12)) + .schemaCacheEnabled(enableSchemaCache) + .resourceLoaders(resourceLoaders -> resourceLoaders.add(uriFetcher)) + .dialectRegistry(new BasicDialectRegistry(Dialects.getDraft202012())) .build(); } - private class CustomURIFetcher implements SchemaLoader { + private class CustomURIFetcher implements ResourceLoader { private final Map uriToResource = new HashMap<>(); @@ -64,7 +66,7 @@ void addResource(AbsoluteIri uri, InputStream is) { } @Override - public InputStreamSource getSchema(AbsoluteIri absoluteIri) { + public InputStreamSource getResource(AbsoluteIri absoluteIri) { return () -> uriToResource.get(absoluteIri); } } diff --git a/src/test/java/com/networknt/schema/JsonSchemaPreloadTest.java b/src/test/java/com/networknt/schema/JsonSchemaPreloadTest.java index 23b900b31..5bb119753 100644 --- a/src/test/java/com/networknt/schema/JsonSchemaPreloadTest.java +++ b/src/test/java/com/networknt/schema/JsonSchemaPreloadTest.java @@ -18,25 +18,23 @@ import org.junit.jupiter.api.Test; -import com.networknt.schema.SpecVersion.VersionFlag; - /** * Test to control preloading of schemas. */ class JsonSchemaPreloadTest { @Test void cacheRefsFalse() { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V7); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().cacheRefs(false).build(); - factory.getSchema(SchemaLocation.of("classpath:/issues/1016/schema.json"), config); + SchemaRegistryConfig config = SchemaRegistryConfig.builder().cacheRefs(false).build(); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7, builder -> builder.schemaRegistryConfig(config)); + factory.getSchema(SchemaLocation.of("classpath:/issues/1016/schema.json")); } @Test void preloadSchemaRefMaxNestingDepth() { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V7); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder() - .preloadJsonSchemaRefMaxNestingDepth(20) + SchemaRegistryConfig config = SchemaRegistryConfig.builder() + .preloadSchemaRefMaxNestingDepth(20) .build(); - factory.getSchema(SchemaLocation.of("classpath:/issues/1016/schema.json"), config); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7, builder -> builder.schemaRegistryConfig(config)); + factory.getSchema(SchemaLocation.of("classpath:/issues/1016/schema.json")); } } diff --git a/src/test/java/com/networknt/schema/JsonSchemaTestSuiteExtrasTest.java b/src/test/java/com/networknt/schema/JsonSchemaTestSuiteExtrasTest.java index f3f380007..7242260f9 100644 --- a/src/test/java/com/networknt/schema/JsonSchemaTestSuiteExtrasTest.java +++ b/src/test/java/com/networknt/schema/JsonSchemaTestSuiteExtrasTest.java @@ -1,7 +1,5 @@ package com.networknt.schema; -import com.networknt.schema.SpecVersion.VersionFlag; - import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.DynamicNode; import org.junit.jupiter.api.TestFactory; @@ -18,31 +16,31 @@ class JsonSchemaTestSuiteExtrasTest extends AbstractJsonSchemaTestSuite { @TestFactory @DisplayName("Draft 2020-12") Stream draft2022012() { - return createTests(VersionFlag.V202012, "src/test/resources/draft2020-12"); + return createTests(SpecificationVersion.DRAFT_2020_12, "src/test/resources/draft2020-12"); } @TestFactory @DisplayName("Draft 2019-09") Stream draft201909() { - return createTests(VersionFlag.V201909, "src/test/resources/draft2019-09"); + return createTests(SpecificationVersion.DRAFT_2019_09, "src/test/resources/draft2019-09"); } @TestFactory @DisplayName("Draft 7") Stream draft7() { - return createTests(VersionFlag.V7, "src/test/resources/draft7"); + return createTests(SpecificationVersion.DRAFT_7, "src/test/resources/draft7"); } @TestFactory @DisplayName("Draft 6") Stream draft6() { - return createTests(VersionFlag.V6, "src/test/resources/draft6"); + return createTests(SpecificationVersion.DRAFT_6, "src/test/resources/draft6"); } @TestFactory @DisplayName("Draft 4") Stream draft4() { - return createTests(VersionFlag.V4, "src/test/resources/draft4"); + return createTests(SpecificationVersion.DRAFT_4, "src/test/resources/draft4"); } @Override diff --git a/src/test/java/com/networknt/schema/JsonSchemaTestSuiteTest.java b/src/test/java/com/networknt/schema/JsonSchemaTestSuiteTest.java index 880c8e647..5ff37905a 100644 --- a/src/test/java/com/networknt/schema/JsonSchemaTestSuiteTest.java +++ b/src/test/java/com/networknt/schema/JsonSchemaTestSuiteTest.java @@ -10,8 +10,6 @@ import org.junit.jupiter.api.DynamicNode; import org.junit.jupiter.api.TestFactory; -import com.networknt.schema.SpecVersion.VersionFlag; - @DisplayName("JSON Schema Test Suite") class JsonSchemaTestSuiteTest extends AbstractJsonSchemaTestSuite { @@ -30,31 +28,31 @@ class JsonSchemaTestSuiteTest extends AbstractJsonSchemaTestSuite { @TestFactory @DisplayName("Draft 2020-12") Stream draft2022012() { - return createTests(VersionFlag.V202012, "src/test/suite/tests/draft2020-12"); + return createTests(SpecificationVersion.DRAFT_2020_12, "src/test/suite/tests/draft2020-12"); } @TestFactory @DisplayName("Draft 2019-09") Stream draft201909() { - return createTests(VersionFlag.V201909, "src/test/suite/tests/draft2019-09"); + return createTests(SpecificationVersion.DRAFT_2019_09, "src/test/suite/tests/draft2019-09"); } @TestFactory @DisplayName("Draft 7") Stream draft7() { - return createTests(VersionFlag.V7, "src/test/suite/tests/draft7"); + return createTests(SpecificationVersion.DRAFT_7, "src/test/suite/tests/draft7"); } @TestFactory @DisplayName("Draft 6") Stream draft6() { - return createTests(VersionFlag.V6, "src/test/suite/tests/draft6"); + return createTests(SpecificationVersion.DRAFT_6, "src/test/suite/tests/draft6"); } @TestFactory @DisplayName("Draft 4") Stream draft4() { - return createTests(VersionFlag.V4, "src/test/suite/tests/draft4"); + return createTests(SpecificationVersion.DRAFT_4, "src/test/suite/tests/draft4"); } @Override diff --git a/src/test/java/com/networknt/schema/JsonWalkApplyDefaultsTest.java b/src/test/java/com/networknt/schema/JsonWalkApplyDefaultsTest.java index 5ca6fb561..12d67548b 100644 --- a/src/test/java/com/networknt/schema/JsonWalkApplyDefaultsTest.java +++ b/src/test/java/com/networknt/schema/JsonWalkApplyDefaultsTest.java @@ -6,6 +6,9 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import com.networknt.schema.walk.ApplyDefaultsStrategy; +import com.networknt.schema.walk.WalkConfig; + import java.io.IOException; import java.util.List; import java.util.stream.Collectors; @@ -21,15 +24,17 @@ class JsonWalkApplyDefaultsTest { void testApplyDefaults3(boolean shouldValidateSchema) throws IOException { ObjectMapper objectMapper = new ObjectMapper(); JsonNode inputNode = objectMapper.readTree(getClass().getClassLoader().getResourceAsStream("data/walk-data-default.json")); - JsonSchema jsonSchema = createSchema(new ApplyDefaultsStrategy(true, true, true)); - ValidationResult result = jsonSchema.walk(inputNode, shouldValidateSchema); + Schema jsonSchema = createSchema(); + WalkConfig walkConfig = WalkConfig.builder() + .applyDefaultsStrategy(new ApplyDefaultsStrategy(true, true, true)).build(); + Result result = jsonSchema.walk(inputNode, shouldValidateSchema, executionContext -> executionContext.setWalkConfig(walkConfig)); if (shouldValidateSchema) { - assertThat(result.getValidationMessages().stream().map(ValidationMessage::getMessage).collect(Collectors.toList()), + assertThat(result.getErrors().stream().map(Error::toString).collect(Collectors.toList()), Matchers.containsInAnyOrder("/outer/mixedObject/intValue_missingButError: string found, integer expected", "/outer/badArray/1: integer found, string expected", "/outer/reference/stringValue_missing_with_default_null: null found, string expected")); } else { - assertThat(result.getValidationMessages(), Matchers.empty()); + assertThat(result.getErrors(), Matchers.empty()); } // TODO: In Java 14 use text blocks assertEquals( @@ -42,9 +47,11 @@ void testApplyDefaults3(boolean shouldValidateSchema) throws IOException { void testApplyDefaults2() throws IOException { ObjectMapper objectMapper = new ObjectMapper(); JsonNode inputNode = objectMapper.readTree(getClass().getClassLoader().getResourceAsStream("data/walk-data-default.json")); - JsonSchema jsonSchema = createSchema(new ApplyDefaultsStrategy(true, true, false)); - ValidationResult result = jsonSchema.walk(inputNode, true); - assertThat(result.getValidationMessages().stream().map(ValidationMessage::getMessage).collect(Collectors.toList()), + Schema jsonSchema = createSchema(); + WalkConfig walkConfig = WalkConfig.builder() + .applyDefaultsStrategy(new ApplyDefaultsStrategy(true, true, false)).build(); + Result result = jsonSchema.walk(inputNode, true, executionContext -> executionContext.setWalkConfig(walkConfig)); + assertThat(result.getErrors().stream().map(Error::toString).collect(Collectors.toList()), Matchers.containsInAnyOrder("/outer/mixedObject/intValue_missingButError: string found, integer expected", "/outer/goodArray/1: null found, string expected", "/outer/badArray/1: null found, string expected", @@ -59,9 +66,11 @@ void testApplyDefaults2() throws IOException { void testApplyDefaults1() throws IOException { ObjectMapper objectMapper = new ObjectMapper(); JsonNode inputNode = objectMapper.readTree(getClass().getClassLoader().getResourceAsStream("data/walk-data-default.json")); - JsonSchema jsonSchema = createSchema(new ApplyDefaultsStrategy(true, false, false)); - ValidationResult result = jsonSchema.walk(inputNode, true); - assertThat(result.getValidationMessages().stream().map(ValidationMessage::getMessage).collect(Collectors.toList()), + Schema jsonSchema = createSchema(); + WalkConfig walkConfig = WalkConfig.builder() + .applyDefaultsStrategy(new ApplyDefaultsStrategy(true, false, false)).build(); + Result result = jsonSchema.walk(inputNode, true, executionContext -> executionContext.setWalkConfig(walkConfig)); + assertThat(result.getErrors().stream().map(Error::toString).collect(Collectors.toList()), Matchers.containsInAnyOrder("/outer/mixedObject/intValue_null: null found, integer expected", "/outer/mixedObject/intValue_missingButError: string found, integer expected", "/outer/goodArray/1: null found, string expected", @@ -79,28 +88,34 @@ void testApplyDefaults0(String method) throws IOException { ObjectMapper objectMapper = new ObjectMapper(); JsonNode inputNode = objectMapper.readTree(getClass().getClassLoader().getResourceAsStream("data/walk-data-default.json")); JsonNode inputNodeOriginal = objectMapper.readTree(getClass().getClassLoader().getResourceAsStream("data/walk-data-default.json")); - List validationMessages; + List errors; switch (method) { case "walkWithEmptyStrategy": { - JsonSchema jsonSchema = createSchema(new ApplyDefaultsStrategy(false, false, false)); - validationMessages = jsonSchema.walk(inputNode, true).getValidationMessages(); + WalkConfig walkConfig = WalkConfig.builder() + .applyDefaultsStrategy(new ApplyDefaultsStrategy(false, false, false)).build(); + Schema jsonSchema = createSchema(); + errors = jsonSchema.walk(inputNode, true, executionContext -> executionContext.setWalkConfig(walkConfig)).getErrors(); break; } case "walkWithNoDefaults": { // same empty strategy, but tests for NullPointerException - JsonSchema jsonSchema = createSchema(null); - validationMessages = jsonSchema.walk(inputNode, true).getValidationMessages(); + WalkConfig walkConfig = WalkConfig.builder() + .applyDefaultsStrategy(null).build(); + Schema jsonSchema = createSchema(); + errors = jsonSchema.walk(inputNode, true, executionContext -> executionContext.setWalkConfig(walkConfig)).getErrors(); break; } case "validateWithApplyAllDefaults": { - JsonSchema jsonSchema = createSchema(new ApplyDefaultsStrategy(true, true, true)); - validationMessages = jsonSchema.validate(inputNode); + WalkConfig walkConfig = WalkConfig.builder() + .applyDefaultsStrategy(new ApplyDefaultsStrategy(true, true, true)).build(); + Schema jsonSchema = createSchema(); + errors = jsonSchema.validate(inputNode, executionContext -> executionContext.setWalkConfig(walkConfig)); break; } default: throw new UnsupportedOperationException(); } - assertThat(validationMessages.stream().map(ValidationMessage::getMessage).collect(Collectors.toList()), + assertThat(errors.stream().map(Error::toString).collect(Collectors.toList()), Matchers.containsInAnyOrder("/outer/mixedObject: required property 'intValue_missing' not found", "/outer/mixedObject: required property 'intValue_missingButError' not found", "/outer/mixedObject/intValue_null: null found, integer expected", @@ -119,9 +134,9 @@ void testIllegalArgumentException() { } } - private JsonSchema createSchema(ApplyDefaultsStrategy applyDefaultsStrategy) { - JsonSchemaFactory schemaFactory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V4); - SchemaValidatorsConfig schemaValidatorsConfig = SchemaValidatorsConfig.builder().applyDefaultsStrategy(applyDefaultsStrategy).build(); - return schemaFactory.getSchema(getClass().getClassLoader().getResourceAsStream("schema/walk-schema-default.json"), schemaValidatorsConfig); + private Schema createSchema() { + SchemaRegistry schemaFactory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_4); + return schemaFactory + .getSchema(getClass().getClassLoader().getResourceAsStream("schema/walk-schema-default.json")); } } diff --git a/src/test/java/com/networknt/schema/JsonWalkTest.java b/src/test/java/com/networknt/schema/JsonWalkTest.java index 573cdb096..87329f64e 100644 --- a/src/test/java/com/networknt/schema/JsonWalkTest.java +++ b/src/test/java/com/networknt/schema/JsonWalkTest.java @@ -4,7 +4,16 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.MissingNode; import com.fasterxml.jackson.databind.node.ObjectNode; -import com.networknt.schema.walk.JsonSchemaWalkListener; +import com.networknt.schema.dialect.Dialect; +import com.networknt.schema.dialect.Dialects; +import com.networknt.schema.keyword.AbstractKeywordValidator; +import com.networknt.schema.keyword.Keyword; +import com.networknt.schema.keyword.KeywordValidator; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.keyword.KeywordType; +import com.networknt.schema.walk.WalkListener; +import com.networknt.schema.walk.KeywordWalkListenerRunner; +import com.networknt.schema.walk.WalkConfig; import com.networknt.schema.walk.WalkEvent; import com.networknt.schema.walk.WalkFlow; @@ -20,50 +29,58 @@ class JsonWalkTest { - private JsonSchema jsonSchema; + private Schema jsonSchema; - private JsonSchema jsonSchema1; + private Schema jsonSchema1; private static final String SAMPLE_WALK_COLLECTOR_TYPE = "sampleWalkCollectorType"; private static final String CUSTOM_KEYWORD = "custom-keyword"; + private WalkConfig walkConfig; + + private WalkConfig walkConfig1; + @BeforeEach void setup() { setupSchema(); } private void setupSchema() { - final JsonMetaSchema metaSchema = getJsonMetaSchema(); + final Dialect dialect = getDialect(); // Create Schema. - SchemaValidatorsConfig.Builder schemaValidatorsConfigBuilder = SchemaValidatorsConfig.builder(); - schemaValidatorsConfigBuilder.keywordWalkListener(new AllKeywordListener()); - schemaValidatorsConfigBuilder.keywordWalkListener(ValidatorTypeCode.REF.getValue(), new RefKeywordListener()); - schemaValidatorsConfigBuilder.keywordWalkListener(ValidatorTypeCode.PROPERTIES.getValue(), + KeywordWalkListenerRunner.Builder keywordWalkListenerRunnerBuilder = KeywordWalkListenerRunner.builder(); + + keywordWalkListenerRunnerBuilder.keywordWalkListener(new AllKeywordListener()); + keywordWalkListenerRunnerBuilder.keywordWalkListener(KeywordType.REF.getValue(), new RefKeywordListener()); + keywordWalkListenerRunnerBuilder.keywordWalkListener(KeywordType.PROPERTIES.getValue(), new PropertiesKeywordListener()); - final JsonSchemaFactory schemaFactory = JsonSchemaFactory - .builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V201909)).metaSchema(metaSchema) - .build(); - this.jsonSchema = schemaFactory.getSchema(getSchema(), schemaValidatorsConfigBuilder.build()); + SchemaRegistry schemaFactory = SchemaRegistry.withDialect(dialect); + this.jsonSchema = schemaFactory.getSchema(getSchema()); + this.walkConfig = WalkConfig.builder().keywordWalkListenerRunner(keywordWalkListenerRunnerBuilder.build()).build(); + // Create another Schema. - SchemaValidatorsConfig.Builder schemaValidatorsConfig1Builder = SchemaValidatorsConfig.builder(); - schemaValidatorsConfig1Builder.keywordWalkListener(ValidatorTypeCode.REF.getValue(), new RefKeywordListener()); - schemaValidatorsConfig1Builder.keywordWalkListener(ValidatorTypeCode.PROPERTIES.getValue(), + KeywordWalkListenerRunner.Builder keywordWalkListenerRunner1Builder = KeywordWalkListenerRunner.builder(); + keywordWalkListenerRunner1Builder.keywordWalkListener(KeywordType.REF.getValue(), new RefKeywordListener()); + keywordWalkListenerRunner1Builder.keywordWalkListener(KeywordType.PROPERTIES.getValue(), new PropertiesKeywordListener()); - this.jsonSchema1 = schemaFactory.getSchema(getSchema(), schemaValidatorsConfig1Builder.build()); + schemaFactory = SchemaRegistry.withDialect(dialect); + this.jsonSchema1 = schemaFactory.getSchema(getSchema()); + this.walkConfig1 = WalkConfig.builder().keywordWalkListenerRunner(keywordWalkListenerRunner1Builder.build()).build(); } - private JsonMetaSchema getJsonMetaSchema() { - return JsonMetaSchema.builder( - "https://github.com/networknt/json-schema-validator/tests/schemas/example01", JsonMetaSchema.getV201909()) + private Dialect getDialect() { + return Dialect.builder( + "https://github.com/networknt/json-schema-validator/tests/schemas/example01", Dialects.getDraft201909()) .keyword(new CustomKeyword()).build(); } @Test void testWalk() throws IOException { ObjectMapper objectMapper = new ObjectMapper(); - ValidationResult result = jsonSchema.walk( - objectMapper.readTree(getClass().getClassLoader().getResourceAsStream("data/walk-data.json")), false); + Result result = jsonSchema.walk( + objectMapper.readTree(getClass().getClassLoader().getResourceAsStream("data/walk-data.json")), false, + executionContext -> executionContext.setWalkConfig(walkConfig)); JsonNode collectedNode = (JsonNode) result.getCollectorContext().get(SAMPLE_WALK_COLLECTOR_TYPE); assertEquals(collectedNode, (objectMapper.readTree("{" + " \"PROPERTY1\": \"sample1\"," @@ -82,8 +99,9 @@ void testWalk() throws IOException { void testWalkWithDifferentListeners() throws IOException { ObjectMapper objectMapper = new ObjectMapper(); // This instance of schema contains all listeners. - ValidationResult result = jsonSchema.walk( - objectMapper.readTree(getClass().getClassLoader().getResourceAsStream("data/walk-data.json")), false); + Result result = jsonSchema.walk( + objectMapper.readTree(getClass().getClassLoader().getResourceAsStream("data/walk-data.json")), false, + executionContext -> executionContext.setWalkConfig(walkConfig)); JsonNode collectedNode = (JsonNode) result.getCollectorContext().get(SAMPLE_WALK_COLLECTOR_TYPE); assertEquals(collectedNode, (objectMapper.readTree("{" + " \"PROPERTY1\": \"sample1\"," @@ -97,7 +115,9 @@ void testWalkWithDifferentListeners() throws IOException { + " }" + "}"))); // This instance of schema contains one listener removed. - result = jsonSchema1.walk(objectMapper.readTree(getClass().getClassLoader().getResourceAsStream("data/walk-data.json")), false); + result = jsonSchema1.walk( + objectMapper.readTree(getClass().getClassLoader().getResourceAsStream("data/walk-data.json")), false, + executionContext -> executionContext.setWalkConfig(walkConfig1)); collectedNode = (JsonNode) result.getExecutionContext().getCollectorContext().get(SAMPLE_WALK_COLLECTOR_TYPE); assertEquals(collectedNode, (objectMapper.readTree("{" + " \"property3\": {" @@ -125,8 +145,8 @@ void testWalkMissingNodeWithPropertiesSchemaShouldNotThrow() { + " }\n" + " }"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7); - JsonSchema schema = factory.getSchema(schemaContents); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7); + Schema schema = factory.getSchema(schemaContents); JsonNode missingNode = MissingNode.getInstance(); assertDoesNotThrow(() -> schema.walk(missingNode, true)); } @@ -145,8 +165,8 @@ public String getValue() { } @Override - public JsonValidator newValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, - JsonSchema parentSchema, ValidationContext validationContext) throws JsonSchemaException { + public KeywordValidator newValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, + Schema parentSchema, SchemaContext schemaContext) throws SchemaException { if (schemaNode != null && schemaNode.isArray()) { return new CustomValidator(schemaLocation, evaluationPath, schemaNode); } @@ -159,26 +179,26 @@ public JsonValidator newValidator(SchemaLocation schemaLocation, JsonNodePath ev * This will be helpful in cases where we don't want to revisit the entire JSON * document again just for gathering this kind of information. */ - private static class CustomValidator extends AbstractJsonValidator { + private static class CustomValidator extends AbstractKeywordValidator { - CustomValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode) { - super(schemaLocation, evaluationPath, new CustomKeyword(), schemaNode); + CustomValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode) { + super(new CustomKeyword(), schemaNode, schemaLocation, evaluationPath); } @Override - public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, JsonNodePath instanceLocation) { + public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, NodePath instanceLocation) { return; } @Override public void walk(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, - JsonNodePath instanceLocation, boolean shouldValidateSchema) { + NodePath instanceLocation, boolean shouldValidateSchema) { return; } } } - private static class AllKeywordListener implements JsonSchemaWalkListener { + private static class AllKeywordListener implements WalkListener { @Override public WalkFlow onWalkStart(WalkEvent keywordWalkEvent) { ObjectMapper mapper = new ObjectMapper(); @@ -186,7 +206,7 @@ public WalkFlow onWalkStart(WalkEvent keywordWalkEvent) { JsonNode schemaNode = keywordWalkEvent.getSchema().getSchemaNode(); CollectorContext collectorContext = keywordWalkEvent.getExecutionContext().getCollectorContext(); if (collectorContext.get(SAMPLE_WALK_COLLECTOR_TYPE) == null) { - collectorContext.add(SAMPLE_WALK_COLLECTOR_TYPE, mapper.createObjectNode()); + collectorContext.put(SAMPLE_WALK_COLLECTOR_TYPE, mapper.createObjectNode()); } if (keyWordName.equals(CUSTOM_KEYWORD) && schemaNode.get(CUSTOM_KEYWORD).isArray()) { ObjectNode objectNode = (ObjectNode) collectorContext.get(SAMPLE_WALK_COLLECTOR_TYPE); @@ -197,19 +217,19 @@ public WalkFlow onWalkStart(WalkEvent keywordWalkEvent) { } @Override - public void onWalkEnd(WalkEvent keywordWalkEvent, List validationMessages) { + public void onWalkEnd(WalkEvent keywordWalkEvent, List errors) { } } - private static class RefKeywordListener implements JsonSchemaWalkListener { + private static class RefKeywordListener implements WalkListener { @Override public WalkFlow onWalkStart(WalkEvent keywordWalkEvent) { ObjectMapper mapper = new ObjectMapper(); CollectorContext collectorContext = keywordWalkEvent.getExecutionContext().getCollectorContext(); if (collectorContext.get(SAMPLE_WALK_COLLECTOR_TYPE) == null) { - collectorContext.add(SAMPLE_WALK_COLLECTOR_TYPE, mapper.createObjectNode()); + collectorContext.put(SAMPLE_WALK_COLLECTOR_TYPE, mapper.createObjectNode()); } ObjectNode objectNode = (ObjectNode) collectorContext.get(SAMPLE_WALK_COLLECTOR_TYPE); objectNode.set(keywordWalkEvent.getSchema().getSchemaNode().get("title").textValue().toLowerCase(), @@ -218,12 +238,12 @@ public WalkFlow onWalkStart(WalkEvent keywordWalkEvent) { } @Override - public void onWalkEnd(WalkEvent keywordWalkEvent, List validationMessages) { + public void onWalkEnd(WalkEvent keywordWalkEvent, List errors) { } } - private static class PropertiesKeywordListener implements JsonSchemaWalkListener { + private static class PropertiesKeywordListener implements WalkListener { @Override public WalkFlow onWalkStart(WalkEvent keywordWalkEvent) { @@ -235,7 +255,7 @@ public WalkFlow onWalkStart(WalkEvent keywordWalkEvent) { } @Override - public void onWalkEnd(WalkEvent keywordWalkEvent, List validationMessages) { + public void onWalkEnd(WalkEvent keywordWalkEvent, List errors) { } } diff --git a/src/test/java/com/networknt/schema/ValidatorTypeCodeTest.java b/src/test/java/com/networknt/schema/KeywordsTest.java similarity index 63% rename from src/test/java/com/networknt/schema/ValidatorTypeCodeTest.java rename to src/test/java/com/networknt/schema/KeywordsTest.java index 8484378c0..844449cb4 100644 --- a/src/test/java/com/networknt/schema/ValidatorTypeCodeTest.java +++ b/src/test/java/com/networknt/schema/KeywordsTest.java @@ -19,32 +19,34 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import com.networknt.schema.keyword.KeywordType; + import java.util.List; import static org.junit.jupiter.api.Assertions.assertEquals; -class ValidatorTypeCodeTest { +class KeywordsTest { @Test void testFromValueString() { - assertEquals(ValidatorTypeCode.ADDITIONAL_PROPERTIES, ValidatorTypeCode.fromValue("additionalProperties")); + assertEquals(KeywordType.ADDITIONAL_PROPERTIES, KeywordType.fromValue("additionalProperties")); } @Test void testFromValueMissing() { - Assertions.assertThrows(IllegalArgumentException.class, () -> assertEquals(ValidatorTypeCode.ADDITIONAL_PROPERTIES, ValidatorTypeCode.fromValue("missing"))); + Assertions.assertThrows(IllegalArgumentException.class, () -> assertEquals(KeywordType.ADDITIONAL_PROPERTIES, KeywordType.fromValue("missing"))); } @Test void testIfThenElseNotInV4() { - List list = ValidatorTypeCode.getKeywords(SpecVersion.VersionFlag.V4); - Assertions.assertFalse(list.contains(ValidatorTypeCode.fromValue("if"))); + List list = KeywordType.getKeywords(SpecificationVersion.DRAFT_4); + Assertions.assertFalse(list.contains(KeywordType.fromValue("if"))); } @Test void testExclusiveMaximumNotInV4() { - List list = ValidatorTypeCode.getKeywords(SpecVersion.VersionFlag.V4); - Assertions.assertFalse(list.contains(ValidatorTypeCode.fromValue("exclusiveMaximum"))); + List list = KeywordType.getKeywords(SpecificationVersion.DRAFT_4); + Assertions.assertFalse(list.contains(KeywordType.fromValue("exclusiveMaximum"))); } } diff --git a/src/test/java/com/networknt/schema/LocaleTest.java b/src/test/java/com/networknt/schema/LocaleTest.java index e4bd7f8be..c28cf5c1c 100644 --- a/src/test/java/com/networknt/schema/LocaleTest.java +++ b/src/test/java/com/networknt/schema/LocaleTest.java @@ -28,16 +28,15 @@ import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.networknt.schema.SpecVersion.VersionFlag; import com.networknt.schema.i18n.Locales; import com.networknt.schema.serialization.JsonMapperFactory; class LocaleTest { - private JsonSchema getSchema(SchemaValidatorsConfig config) { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V201909); + private Schema getSchema(SchemaRegistryConfig config) { + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2019_09, builder -> builder.schemaRegistryConfig(config)); return factory.getSchema( - "{ \"$schema\": \"https://json-schema.org/draft/2019-09/schema\", \"$id\": \"https://json-schema.org/draft/2019-09/schema\", \"type\": \"object\", \"properties\": { \"foo\": { \"type\": \"string\" } } } }", - config); + "{ \"$schema\": \"https://json-schema.org/draft/2019-09/schema\", \"$id\": \"https://json-schema.org/draft/2019-09/schema\", \"type\": \"object\", \"properties\": { \"foo\": { \"type\": \"string\" } } } }" + ); } /** @@ -50,26 +49,24 @@ private JsonSchema getSchema(SchemaValidatorsConfig config) { @Test void executionContextLocale() throws JsonMappingException, JsonProcessingException { JsonNode rootNode = new ObjectMapper().readTree(" { \"foo\": 123 } "); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema jsonSchema = getSchema(config); + SchemaRegistryConfig config = SchemaRegistryConfig.builder().build(); + Schema jsonSchema = getSchema(config); Locale locale = Locales.findSupported("it;q=0.9,fr;q=1.0"); // fr ExecutionContext executionContext = jsonSchema.createExecutionContext(); assertEquals(config.getLocale(), executionContext.getExecutionConfig().getLocale()); - executionContext.getExecutionConfig().setLocale(locale); - jsonSchema.validate(executionContext, rootNode); - List messages = executionContext.getErrors(); + executionContext.executionConfig(executionConfig -> executionConfig.locale(locale)); + List messages = jsonSchema.validate(executionContext, rootNode, OutputFormat.DEFAULT); assertEquals(1, messages.size()); - assertEquals("/foo: integer trouvé, string attendu", messages.iterator().next().getMessage()); + assertEquals("/foo: integer trouvé, string attendu", messages.iterator().next().toString()); - locale = Locales.findSupported("it;q=1.0,fr;q=0.9"); // it + Locale locale2 = Locales.findSupported("it;q=1.0,fr;q=0.9"); // it executionContext = jsonSchema.createExecutionContext(); assertEquals(config.getLocale(), executionContext.getExecutionConfig().getLocale()); - executionContext.getExecutionConfig().setLocale(locale); - jsonSchema.validate(executionContext, rootNode); - messages = executionContext.getErrors(); + executionContext.executionConfig(executionConfig -> executionConfig.locale(locale2)); + messages = jsonSchema.validate(executionContext, rootNode, OutputFormat.DEFAULT); assertEquals(1, messages.size()); - assertEquals("/foo: integer trovato, string previsto", messages.iterator().next().getMessage()); + assertEquals("/foo: integer trovato, string previsto", messages.iterator().next().toString()); } /** @@ -90,16 +87,16 @@ void englishLocale() throws JsonMappingException, JsonProcessingException { + " \"$id\": \"https://www.example.com\",\r\n" + " \"type\": \"object\"\r\n" + "}"; - JsonSchema jsonSchema = JsonSchemaFactory.getInstance(VersionFlag.V7) + Schema jsonSchema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7) .getSchema(JsonMapperFactory.getInstance().readTree(schema)); String input = "1"; - List messages = jsonSchema.validate(input, InputFormat.JSON); + List messages = jsonSchema.validate(input, InputFormat.JSON); assertEquals(1, messages.size()); - assertEquals("$: integer gefunden, object erwartet", messages.iterator().next().toString()); + assertEquals(": integer gefunden, object erwartet", messages.iterator().next().toString()); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().locale(Locale.ENGLISH).build(); - jsonSchema = JsonSchemaFactory.getInstance(VersionFlag.V7) - .getSchema(JsonMapperFactory.getInstance().readTree(schema), config); + SchemaRegistryConfig config = SchemaRegistryConfig.builder().locale(Locale.ENGLISH).build(); + jsonSchema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7, builder -> builder.schemaRegistryConfig(config)) + .getSchema(JsonMapperFactory.getInstance().readTree(schema)); messages = jsonSchema.validate(input, InputFormat.JSON); assertEquals(1, messages.size()); assertEquals(": integer found, object expected", messages.iterator().next().toString()); @@ -117,50 +114,50 @@ void englishLocale() throws JsonMappingException, JsonProcessingException { @Test void encoding() { Map expected = new HashMap<>(); - expected.put("ar","$: يجب أن يكون طوله 5 حرÙًا على الأكثر"); - expected.put("cs","$: musí mít maximálnÄ› 5 znaků"); - expected.put("da","$: mÃ¥ højst være pÃ¥ 5 tegn"); - expected.put("de","$: darf höchstens 5 Zeichen lang sein"); - expected.put("es","$: debe tener como máximo 5 caracteres"); - expected.put("fa","$: باید حداکثر 5 کاراکتر باشد"); - expected.put("fi","$: saa olla enintään 5 merkkiä pitkä"); - expected.put("fr","$: doit contenir au plus 5 caractères"); - expected.put("iw","$: חייב להיות ב×ורך של 5 ×ª×•×•×™× ×œ×›×œ היותר"); - expected.put("he","$: חייב להיות ב×ורך של 5 ×ª×•×•×™× ×œ×›×œ היותר"); - expected.put("hr","$: mora imati najviÅ¡e 5 znakova"); - expected.put("hu","$: legfeljebb 5 karakter hosszúságú lehet"); - expected.put("it","$: deve contenere al massimo 5 caratteri"); - expected.put("ja","$: é•·ã•ã¯æœ€å¤§ 5 文字ã§ãªã‘れã°ãªã‚Šã¾ã›ã‚“"); - expected.put("ko","$: 길ì´ëŠ” 최대 5ìžì—¬ì•¼ 합니다."); - expected.put("nb","$: mÃ¥ bestÃ¥ av maksimalt 5 tegn"); - expected.put("nl","$: mag maximaal 5 tekens lang zijn"); - expected.put("pl","$: musi mieć maksymalnie 5 znaków"); - expected.put("pt","$: deve ter no máximo 5 caracteres"); - expected.put("ro","$: trebuie să aibă cel mult 5 caractere"); - expected.put("ru","$: длина должна быть не более 5 Ñимволов."); - expected.put("sk","$: musí maÅ¥ maximálne 5 znakov"); - expected.put("sv","$: fÃ¥r vara högst 5 tecken lÃ¥ng"); - expected.put("th","$: ต้องมีความยาวสูงสุด 5 อัà¸à¸‚ระ"); - expected.put("tr","$: en fazla 5 karakter uzunluÄŸunda olmalıdır"); - expected.put("uk","$: не більше ніж 5 Ñимволів"); - expected.put("vi","$: phải dài tối Ä‘a 5 ký tá»±"); - expected.put("zh_CN","$: 长度ä¸å¾—超过 5 个字符"); - expected.put("zh_TW","$: 長度ä¸å¾—è¶…éŽ 5 個字元"); + expected.put("ar",": يجب أن يكون طوله 5 حرÙًا على الأكثر"); + expected.put("cs",": musí mít maximálnÄ› 5 znaků"); + expected.put("da",": mÃ¥ højst være pÃ¥ 5 tegn"); + expected.put("de",": darf höchstens 5 Zeichen lang sein"); + expected.put("es",": debe tener como máximo 5 caracteres"); + expected.put("fa",": باید حداکثر 5 کاراکتر باشد"); + expected.put("fi",": saa olla enintään 5 merkkiä pitkä"); + expected.put("fr",": doit contenir au plus 5 caractères"); + expected.put("iw",": חייב להיות ב×ורך של 5 ×ª×•×•×™× ×œ×›×œ היותר"); + expected.put("he",": חייב להיות ב×ורך של 5 ×ª×•×•×™× ×œ×›×œ היותר"); + expected.put("hr",": mora imati najviÅ¡e 5 znakova"); + expected.put("hu",": legfeljebb 5 karakter hosszúságú lehet"); + expected.put("it",": deve contenere al massimo 5 caratteri"); + expected.put("ja",": é•·ã•ã¯æœ€å¤§ 5 文字ã§ãªã‘れã°ãªã‚Šã¾ã›ã‚“"); + expected.put("ko",": 길ì´ëŠ” 최대 5ìžì—¬ì•¼ 합니다."); + expected.put("nb",": mÃ¥ bestÃ¥ av maksimalt 5 tegn"); + expected.put("nl",": mag maximaal 5 tekens lang zijn"); + expected.put("pl",": musi mieć maksymalnie 5 znaków"); + expected.put("pt",": deve ter no máximo 5 caracteres"); + expected.put("ro",": trebuie să aibă cel mult 5 caractere"); + expected.put("ru",": длина должна быть не более 5 Ñимволов."); + expected.put("sk",": musí maÅ¥ maximálne 5 znakov"); + expected.put("sv",": fÃ¥r vara högst 5 tecken lÃ¥ng"); + expected.put("th",": ต้องมีความยาวสูงสุด 5 อัà¸à¸‚ระ"); + expected.put("tr",": en fazla 5 karakter uzunluÄŸunda olmalıdır"); + expected.put("uk",": не більше ніж 5 Ñимволів"); + expected.put("vi",": phải dài tối Ä‘a 5 ký tá»±"); + expected.put("zh_CN",": 长度ä¸å¾—超过 5 个字符"); + expected.put("zh_TW",": 長度ä¸å¾—è¶…éŽ 5 個字元"); // In later JDK versions the numbers will be formatted Map expectedAlternate = new HashMap<>(); - expectedAlternate.put("ar","$: يجب أن يكون طوله Ù¥ حرÙًا على الأكثر"); - expectedAlternate.put("fa","$: باید حداکثر Ûµ کاراکتر باشد"); + expectedAlternate.put("ar",": يجب أن يكون طوله Ù¥ حرÙًا على الأكثر"); + expectedAlternate.put("fa",": باید حداکثر Ûµ کاراکتر باشد"); String schemaData = "{\r\n" + " \"type\": \"string\",\r\n" + " \"maxLength\": 5\r\n" + "}"; - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V7).getSchema(schemaData); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7).getSchema(schemaData); List locales = Locales.getSupportedLocales(); for (Locale locale : locales) { - List messages = schema.validate("\"aaaaaa\"", InputFormat.JSON, executionContext -> { - executionContext.getExecutionConfig().setLocale(locale); + List messages = schema.validate("\"aaaaaa\"", InputFormat.JSON, executionContext -> { + executionContext.executionConfig(executionConfig -> executionConfig.locale(locale)); }); String msg = messages.iterator().next().toString(); String expectedMsg = expected.get(locale.toString()); diff --git a/src/test/java/com/networknt/schema/MaximumValidatorTest.java b/src/test/java/com/networknt/schema/MaximumValidatorTest.java index 27c34beb2..634945fca 100644 --- a/src/test/java/com/networknt/schema/MaximumValidatorTest.java +++ b/src/test/java/com/networknt/schema/MaximumValidatorTest.java @@ -34,7 +34,7 @@ class MaximumValidatorTest extends BaseJsonSchemaValidatorTest { private static final String NUMBER = "{ \"$schema\":\"http://json-schema.org/draft-04/schema#\", \"type\": \"number\", \"maximum\": %s }"; private static final String EXCLUSIVE_INTEGER = "{ \"$schema\":\"http://json-schema.org/draft-04/schema#\", \"type\": \"integer\", \"maximum\": %s, \"exclusiveMaximum\": true}"; - private static final JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V4); + private static final SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_4); private static final ObjectMapper mapper = new ObjectMapper(); // due to a jackson bug, a float number which is larger than Double.POSITIVE_INFINITY cannot be convert to BigDecimal correctly @@ -181,21 +181,24 @@ void negativeDoubleOverflowTest() throws IOException { {"1.000000000000000000000001E+400", "\"1.0000000000000000000000011E+400\""}, }; + SchemaRegistryConfig config = SchemaRegistryConfig.builder().typeLoose(true).build(); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_4, builder -> builder.schemaRegistryConfig(config)); + for (String[] aTestCycle : values) { String maximum = aTestCycle[0]; String value = aTestCycle[1]; String schema = format(NUMBER, maximum); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().typeLoose(true).build(); + // Schema and document parsed with just double - JsonSchema v = factory.getSchema(mapper.readTree(schema), config); + Schema v = factory.getSchema(mapper.readTree(schema)); JsonNode doc = mapper.readTree(value); - List messages = v.validate(doc); + List messages = v.validate(doc); assertTrue(messages.isEmpty(), format("Maximum %s and value %s are interpreted as Infinity, thus no schema violation should be reported", maximum, value)); // document parsed with BigDecimal doc = bigDecimalMapper.readTree(value); - List messages2 = v.validate(doc); + List messages2 = v.validate(doc); if (Double.valueOf(maximum).equals(Double.POSITIVE_INFINITY)) { assertTrue(messages2.isEmpty(), format("Maximum %s and value %s are equal, thus no schema violation should be reported", maximum, value)); } else { @@ -204,8 +207,8 @@ void negativeDoubleOverflowTest() throws IOException { // schema and document parsed with BigDecimal - v = factory.getSchema(bigDecimalMapper.readTree(schema), config); - List messages3 = v.validate(doc); + v = factory.getSchema(bigDecimalMapper.readTree(schema)); + List messages3 = v.validate(doc); //when the schema and value are both using BigDecimal, the value should be parsed in same mechanism. String theValue = value.toLowerCase().replace("\"", ""); if (maximum.toLowerCase().equals(theValue)) { @@ -226,9 +229,9 @@ void doubleValueCoarsing() throws IOException { String content = "1.7976931348623158e+308"; JsonNode doc = mapper.readTree(content); - JsonSchema v = factory.getSchema(mapper.readTree(schema)); + Schema v = factory.getSchema(mapper.readTree(schema)); - List messages = v.validate(doc); + List messages = v.validate(doc); assertTrue(messages.isEmpty(), "Validation should succeed as by default double values are used by mapper"); doc = bigDecimalMapper.readTree(content); @@ -258,9 +261,9 @@ void doubleValueCoarsingExceedRange() throws IOException { String content = "1.7976931348623160e+308"; JsonNode doc = mapper.readTree(content); - JsonSchema v = factory.getSchema(mapper.readTree(schema)); + Schema v = factory.getSchema(mapper.readTree(schema)); - List messages = v.validate(doc); + List messages = v.validate(doc); assertTrue(messages.isEmpty(), "Validation should succeed as by default double values are used by mapper"); doc = bigDecimalMapper.readTree(content); @@ -294,12 +297,12 @@ private static void expectNoMessages(String[][] values, String schemaTemplate, O String maximum = aTestCycle[0]; String value = aTestCycle[1]; String schema = format(schemaTemplate, maximum); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().typeLoose(true).build(); - - JsonSchema v = factory.getSchema(mapper.readTree(schema), config); + SchemaRegistryConfig config = SchemaRegistryConfig.builder().typeLoose(true).build(); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_4, builder -> builder.schemaRegistryConfig(config)); + Schema v = factory.getSchema(mapper.readTree(schema)); JsonNode doc = mapper.readTree(value); - List messages = v.validate(doc); + List messages = v.validate(doc); assertTrue(messages.isEmpty(), format(MaximumValidatorTest.POSITIVE_TEST_CASE_TEMPLATE, maximum, value)); } } @@ -316,10 +319,10 @@ private static void expectSomeMessages(String[][] values, String schemaTemplate, String value = aTestCycle[1]; String schema = format(schemaTemplate, maximum); - JsonSchema v = factory.getSchema(mapper.readTree(schema)); + Schema v = factory.getSchema(mapper.readTree(schema)); JsonNode doc = mapper2.readTree(value); - List messages = v.validate(doc); + List messages = v.validate(doc); assertFalse(messages.isEmpty(), format(MaximumValidatorTest.NEGATIVE_TEST_CASE_TEMPLATE, value, maximum)); } } diff --git a/src/test/java/com/networknt/schema/MessageTest.java b/src/test/java/com/networknt/schema/MessageTest.java index 424322867..3e2a08f70 100644 --- a/src/test/java/com/networknt/schema/MessageTest.java +++ b/src/test/java/com/networknt/schema/MessageTest.java @@ -22,29 +22,32 @@ import org.junit.jupiter.api.Test; import com.fasterxml.jackson.databind.JsonNode; -import com.networknt.schema.SpecVersion.VersionFlag; +import com.networknt.schema.dialect.Dialect; +import com.networknt.schema.dialect.Dialects; +import com.networknt.schema.keyword.BaseKeywordValidator; +import com.networknt.schema.keyword.Keyword; +import com.networknt.schema.keyword.KeywordValidator; +import com.networknt.schema.path.NodePath; /** * Test for messages. */ class MessageTest { - static class EqualsValidator extends BaseJsonValidator { - private static final ErrorMessageType ERROR_MESSAGE_TYPE = () -> "equals"; - + static class EqualsValidator extends BaseKeywordValidator { private final String value; - EqualsValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, JsonNode schemaNode, - JsonSchema parentSchema, Keyword keyword, - ValidationContext validationContext) { - super(schemaLocation, evaluationPath, schemaNode, parentSchema, ERROR_MESSAGE_TYPE, keyword, validationContext); + EqualsValidator(SchemaLocation schemaLocation, NodePath evaluationPath, JsonNode schemaNode, + Schema parentSchema, Keyword keyword, + SchemaContext schemaContext) { + super(keyword, schemaNode, schemaLocation, parentSchema, schemaContext, evaluationPath); this.value = schemaNode.textValue(); } @Override public void validate(ExecutionContext executionContext, JsonNode node, JsonNode rootNode, - JsonNodePath instanceLocation) { + NodePath instanceLocation) { if (!node.asText().equals(value)) { - executionContext.addError(message().message("{0}: must be equal to ''{1}''") + executionContext.addError(error().message("must be equal to ''{0}''") .arguments(value) .instanceLocation(instanceLocation).instanceNode(node).build()); } @@ -59,26 +62,26 @@ public String getValue() { } @Override - public JsonValidator newValidator(SchemaLocation schemaLocation, JsonNodePath evaluationPath, - JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) - throws JsonSchemaException, Exception { - return new EqualsValidator(schemaLocation, evaluationPath, schemaNode, parentSchema, this, validationContext); + public KeywordValidator newValidator(SchemaLocation schemaLocation, NodePath evaluationPath, + JsonNode schemaNode, Schema parentSchema, SchemaContext schemaContext) + throws SchemaException, Exception { + return new EqualsValidator(schemaLocation, evaluationPath, schemaNode, parentSchema, this, schemaContext); } } @Test void message() { - JsonMetaSchema metaSchema = JsonMetaSchema.builder(JsonMetaSchema.getV202012().getIri(), JsonMetaSchema.getV202012()) + Dialect dialect = Dialect.builder(Dialects.getDraft202012().getId(), Dialects.getDraft202012()) .keyword(new EqualsKeyword()).build(); - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012, builder -> builder.metaSchema(metaSchema)); + SchemaRegistry factory = SchemaRegistry.withDialect(dialect); String schemaData = "{\r\n" + " \"type\": \"string\",\r\n" + " \"equals\": \"helloworld\"\r\n" + "}"; - JsonSchema schema = factory.getSchema(schemaData); - List messages = schema.validate("\"helloworlda\"", InputFormat.JSON); + Schema schema = factory.getSchema(schemaData); + List messages = schema.validate("\"helloworlda\"", InputFormat.JSON); assertEquals(1, messages.size()); - assertEquals("$: must be equal to 'helloworld'", messages.iterator().next().getMessage()); + assertEquals(": must be equal to 'helloworld'", messages.iterator().next().toString()); messages = schema.validate("\"helloworld\"", InputFormat.JSON); assertEquals(0, messages.size()); diff --git a/src/test/java/com/networknt/schema/MetaSchemaValidationTest.java b/src/test/java/com/networknt/schema/MetaSchemaValidationTest.java index 4cb345774..f7443d6c0 100644 --- a/src/test/java/com/networknt/schema/MetaSchemaValidationTest.java +++ b/src/test/java/com/networknt/schema/MetaSchemaValidationTest.java @@ -24,7 +24,6 @@ import org.junit.jupiter.api.Test; import com.fasterxml.jackson.databind.JsonNode; -import com.networknt.schema.SpecVersion.VersionFlag; import com.networknt.schema.serialization.JsonMapperFactory; /** @@ -40,13 +39,13 @@ class MetaSchemaValidationTest { void oas31() throws IOException { try (InputStream input = MetaSchemaValidationTest.class.getResourceAsStream("/schema/oas/3.1/petstore.json")) { JsonNode inputData = JsonMapperFactory.getInstance().readTree(input); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema schema = JsonSchemaFactory - .getInstance(VersionFlag.V202012, - builder -> builder.schemaMappers(schemaMappers -> schemaMappers + SchemaRegistryConfig config = SchemaRegistryConfig.builder().build(); + Schema schema = SchemaRegistry + .withDefaultDialect(SpecificationVersion.DRAFT_2020_12, + builder -> builder.schemaRegistryConfig(config).schemaIdResolvers(schemaIdResolvers -> schemaIdResolvers .mapPrefix("https://spec.openapis.org/oas/3.1", "classpath:oas/3.1"))) - .getSchema(SchemaLocation.of("https://spec.openapis.org/oas/3.1/schema-base/2022-10-07"), config); - List messages = schema.validate(inputData); + .getSchema(SchemaLocation.of("https://spec.openapis.org/oas/3.1/schema-base/2022-10-07")); + List messages = schema.validate(inputData); assertEquals(0, messages.size()); } } diff --git a/src/test/java/com/networknt/schema/MinimumValidatorTest.java b/src/test/java/com/networknt/schema/MinimumValidatorTest.java index 5a23b0aa8..b4888358c 100644 --- a/src/test/java/com/networknt/schema/MinimumValidatorTest.java +++ b/src/test/java/com/networknt/schema/MinimumValidatorTest.java @@ -38,7 +38,7 @@ class MinimumValidatorTest { private static final String INTEGER = "{ \"$schema\":\"http://json-schema.org/draft-04/schema#\", \"type\": \"integer\", \"minimum\": %s }"; private static final String NEGATIVE_MESSAGE_TEMPLATE = "Expecting validation errors, value %s is smaller than minimum %s"; private static final String POSITIVT_MESSAGE_TEMPLATE = "Expecting no validation errors, value %s is greater than minimum %s"; - private static final JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V4); + private static final SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_4); private static ObjectMapper mapper; private static ObjectMapper bigDecimalMapper; @@ -172,17 +172,18 @@ void negativeDoubleOverflowTest() throws IOException { String minimum = aTestCycle[0]; String value = aTestCycle[1]; String schema = format(NUMBER, minimum); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().typeLoose(true).build(); + SchemaRegistryConfig config = SchemaRegistryConfig.builder().typeLoose(true).build(); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_4, builder -> builder.schemaRegistryConfig(config)); // Schema and document parsed with just double - JsonSchema v = factory.getSchema(mapper.readTree(schema), config); + Schema v = factory.getSchema(mapper.readTree(schema)); JsonNode doc = mapper.readTree(value); - List messages = v.validate(doc); + List messages = v.validate(doc); assertTrue(messages.isEmpty(), format("Minimum %s and value %s are interpreted as Infinity, thus no schema violation should be reported", minimum, value)); // document parsed with BigDecimal doc = bigDecimalMapper.readTree(value); - List messages2 = v.validate(doc); + List messages2 = v.validate(doc); //when the schema and value are both using BigDecimal, the value should be parsed in same mechanism. if (Double.valueOf(minimum).equals(Double.NEGATIVE_INFINITY)) { @@ -196,8 +197,9 @@ void negativeDoubleOverflowTest() throws IOException { } // schema and document parsed with BigDecimal - v = factory.getSchema(bigDecimalMapper.readTree(schema), config); - List messages3 = v.validate(doc); + + v = factory.getSchema(bigDecimalMapper.readTree(schema)); + List messages3 = v.validate(doc); //when the schema and value are both using BigDecimal, the value should be parsed in same mechanism. String theValue = value.toLowerCase().replace("\"", ""); if (minimum.toLowerCase().equals(theValue)) { @@ -218,9 +220,9 @@ void doubleValueCoarsing() throws IOException { String content = "-1.7976931348623158e+308"; JsonNode doc = mapper.readTree(content); - JsonSchema v = factory.getSchema(mapper.readTree(schema)); + Schema v = factory.getSchema(mapper.readTree(schema)); - List messages = v.validate(doc); + List messages = v.validate(doc); assertTrue(messages.isEmpty(), "Validation should succeed as by default double values are used by mapper"); doc = bigDecimalMapper.readTree(content); @@ -248,9 +250,9 @@ void doubleValueCoarsingExceedRange() throws IOException { String content = "-1.7976931348623160e+308"; JsonNode doc = mapper.readTree(content); - JsonSchema v = factory.getSchema(mapper.readTree(schema)); + Schema v = factory.getSchema(mapper.readTree(schema)); - List messages = v.validate(doc); + List messages = v.validate(doc); assertTrue(messages.isEmpty(), "Validation should succeed as by default double values are used by mapper"); doc = bigDecimalMapper.readTree(content); @@ -270,10 +272,10 @@ private void expectSomeMessages(String[][] values, String number, ObjectMapper m String value = aTestCycle[1]; String schema = format(number, minimum); - JsonSchema v = factory.getSchema(mapper.readTree(schema)); + Schema v = factory.getSchema(mapper.readTree(schema)); JsonNode doc = mapper2.readTree(value); - List messages = v.validate(doc); + List messages = v.validate(doc); assertFalse(messages.isEmpty(), format(MinimumValidatorTest.NEGATIVE_MESSAGE_TEMPLATE, value, minimum)); } } @@ -287,12 +289,12 @@ private void expectNoMessages(String[][] values, String integer, ObjectMapper ma String minimum = aTestCycle[0]; String value = aTestCycle[1]; String schema = format(integer, minimum); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().typeLoose(true).build(); - - JsonSchema v = factory.getSchema(mapper.readTree(schema), config); + SchemaRegistryConfig config = SchemaRegistryConfig.builder().typeLoose(true).build(); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_4, builder -> builder.schemaRegistryConfig(config)); + Schema v = factory.getSchema(mapper.readTree(schema)); JsonNode doc = bigIntegerMapper.readTree(value); - List messages = v.validate(doc); + List messages = v.validate(doc); assertTrue(messages.isEmpty(), format(MinimumValidatorTest.POSITIVT_MESSAGE_TEMPLATE, value, minimum)); } } diff --git a/src/test/java/com/networknt/schema/MultipleOfValidatorTest.java b/src/test/java/com/networknt/schema/MultipleOfValidatorTest.java index cc50aeb30..99825a826 100644 --- a/src/test/java/com/networknt/schema/MultipleOfValidatorTest.java +++ b/src/test/java/com/networknt/schema/MultipleOfValidatorTest.java @@ -21,8 +21,6 @@ import org.junit.jupiter.api.Test; -import com.networknt.schema.SpecVersion.VersionFlag; - /** * Test MultipleOfValidator validator. */ @@ -47,14 +45,14 @@ class MultipleOfValidatorTest { @Test void test() { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - JsonSchema schema = factory.getSchema(schemaData); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12); + Schema schema = factory.getSchema(schemaData); String inputData = "{\"value1\":123.892,\"value2\":123456.2934,\"value3\":123.123}"; String validData = "{\"value1\":123.89,\"value2\":123456,\"value3\":123.010}"; - List messages = schema.validate(inputData, InputFormat.JSON); + List messages = schema.validate(inputData, InputFormat.JSON); assertEquals(3, messages.size()); - assertEquals(3, messages.stream().filter(m -> "multipleOf".equals(m.getType())).count()); + assertEquals(3, messages.stream().filter(m -> "multipleOf".equals(m.getKeyword())).count()); messages = schema.validate(validData, InputFormat.JSON); assertEquals(0, messages.size()); @@ -62,29 +60,30 @@ void test() { @Test void testTypeLoose() { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - JsonSchema schema = factory.getSchema(schemaData); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12); + Schema schema = factory.getSchema(schemaData); String inputData = "{\"value1\":\"123.892\",\"value2\":\"123456.2934\",\"value3\":123.123}"; String validTypeLooseInputData = "{\"value1\":\"123.89\",\"value2\":\"123456.29\",\"value3\":123.12}"; // Without type loose this has 2 type and 1 multipleOf errors - List messages = schema.validate(inputData, InputFormat.JSON); + List messages = schema.validate(inputData, InputFormat.JSON); assertEquals(3, messages.size()); - assertEquals(2, messages.stream().filter(m -> "type".equals(m.getType())).count()); - assertEquals(1, messages.stream().filter(m -> "multipleOf".equals(m.getType())).count()); + assertEquals(2, messages.stream().filter(m -> "type".equals(m.getKeyword())).count()); + assertEquals(1, messages.stream().filter(m -> "multipleOf".equals(m.getKeyword())).count()); // 2 type errors messages = schema.validate(validTypeLooseInputData, InputFormat.JSON); assertEquals(2, messages.size()); - assertEquals(2, messages.stream().filter(m -> "type".equals(m.getType())).count()); + assertEquals(2, messages.stream().filter(m -> "type".equals(m.getKeyword())).count()); // With type loose this has 3 multipleOf errors - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().typeLoose(true).build(); - JsonSchema typeLoose = factory.getSchema(schemaData, config); + SchemaRegistryConfig config = SchemaRegistryConfig.builder().typeLoose(true).build(); + factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12, builder -> builder.schemaRegistryConfig(config)); + Schema typeLoose = factory.getSchema(schemaData); messages = typeLoose.validate(inputData, InputFormat.JSON); assertEquals(3, messages.size()); - assertEquals(3, messages.stream().filter(m -> "multipleOf".equals(m.getType())).count()); + assertEquals(3, messages.stream().filter(m -> "multipleOf".equals(m.getKeyword())).count()); // No errors messages = typeLoose.validate(validTypeLooseInputData, InputFormat.JSON); diff --git a/src/test/java/com/networknt/schema/JsonNodePathTest.java b/src/test/java/com/networknt/schema/NodePathTest.java similarity index 66% rename from src/test/java/com/networknt/schema/JsonNodePathTest.java rename to src/test/java/com/networknt/schema/NodePathTest.java index 9f91ca91f..ffc9e82ce 100644 --- a/src/test/java/com/networknt/schema/JsonNodePathTest.java +++ b/src/test/java/com/networknt/schema/NodePathTest.java @@ -24,19 +24,22 @@ import org.junit.jupiter.api.Test; -class JsonNodePathTest { +import com.networknt.schema.path.NodePath; +import com.networknt.schema.path.PathType; + +class NodePathTest { @Test void getNameCount() { - JsonNodePath root = new JsonNodePath(PathType.JSON_POINTER); - JsonNodePath path = root.append("hello").append("world"); + NodePath root = new NodePath(PathType.JSON_POINTER); + NodePath path = root.append("hello").append("world"); assertEquals(2, path.getNameCount()); } @Test void getName() { - JsonNodePath root = new JsonNodePath(PathType.JSON_POINTER); - JsonNodePath path = root.append("hello").append("world"); + NodePath root = new NodePath(PathType.JSON_POINTER); + NodePath path = root.append("hello").append("world"); assertEquals("hello", path.getName(0)); assertEquals("world", path.getName(1)); assertEquals("world", path.getName(-1)); @@ -45,19 +48,19 @@ void getName() { @Test void compareTo() { - JsonNodePath root = new JsonNodePath(PathType.JSON_POINTER); - JsonNodePath a = root.append("a"); - JsonNodePath aa = a.append("a"); + NodePath root = new NodePath(PathType.JSON_POINTER); + NodePath a = root.append("a"); + NodePath aa = a.append("a"); - JsonNodePath b = root.append("b"); - JsonNodePath bb = b.append("b"); - JsonNodePath b1 = b.append(1); - JsonNodePath bbb = bb.append("b"); + NodePath b = root.append("b"); + NodePath bb = b.append("b"); + NodePath b1 = b.append(1); + NodePath bbb = bb.append("b"); - JsonNodePath c = root.append("c"); - JsonNodePath cc = c.append("c"); + NodePath c = root.append("c"); + NodePath cc = c.append("c"); - List paths = new ArrayList<>(); + List paths = new ArrayList<>(); paths.add(cc); paths.add(aa); paths.add(bb); @@ -79,30 +82,30 @@ void compareTo() { @Test void equalsEquals() { - JsonNodePath root = new JsonNodePath(PathType.JSON_POINTER); - JsonNodePath a1 = root.append("a"); - JsonNodePath a2 = root.append("a"); + NodePath root = new NodePath(PathType.JSON_POINTER); + NodePath a1 = root.append("a"); + NodePath a2 = root.append("a"); assertEquals(a1, a2); } @Test void hashCodeEquals() { - JsonNodePath root = new JsonNodePath(PathType.JSON_POINTER); - JsonNodePath a1 = root.append("a"); - JsonNodePath a2 = root.append("a"); + NodePath root = new NodePath(PathType.JSON_POINTER); + NodePath a1 = root.append("a"); + NodePath a2 = root.append("a"); assertEquals(a1.hashCode(), a2.hashCode()); } @Test void getPathType() { - JsonNodePath root = new JsonNodePath(PathType.JSON_POINTER); + NodePath root = new NodePath(PathType.JSON_POINTER); assertEquals(PathType.JSON_POINTER, root.getPathType()); } @Test void getElement() { - JsonNodePath root = new JsonNodePath(PathType.JSON_PATH); - JsonNodePath path = root.append("hello").append(1).append("world"); + NodePath root = new NodePath(PathType.JSON_PATH); + NodePath path = root.append("hello").append(1).append("world"); assertEquals("hello", path.getElement(0)); assertEquals(Integer.valueOf(1), path.getElement(1)); assertEquals("world", path.getElement(2)); @@ -113,9 +116,9 @@ void getElement() { @Test void startsWith() { - JsonNodePath root = new JsonNodePath(PathType.JSON_PATH); - JsonNodePath path = root.append("items"); - JsonNodePath other = root.append("unevaluatedItems"); + NodePath root = new NodePath(PathType.JSON_PATH); + NodePath path = root.append("items"); + NodePath other = root.append("unevaluatedItems"); assertTrue(path.startsWith(other.getParent())); path = root.append("allOf").append(0).append("items"); diff --git a/src/test/java/com/networknt/schema/NotAllowedValidatorTest.java b/src/test/java/com/networknt/schema/NotAllowedValidatorTest.java index a849be063..8147e6b4f 100644 --- a/src/test/java/com/networknt/schema/NotAllowedValidatorTest.java +++ b/src/test/java/com/networknt/schema/NotAllowedValidatorTest.java @@ -2,6 +2,9 @@ import org.junit.jupiter.api.Test; +import com.networknt.schema.keyword.NotAllowedValidator; +import com.networknt.schema.keyword.KeywordType; + /** * This class test {@link NotAllowedValidator}, @@ -20,6 +23,6 @@ protected String getDataTestFolder() { */ @Test void testNotAllowedValidatorWorks() { - assertValidatorType("notAllowedJson.json", ValidatorTypeCode.NOT_ALLOWED); + assertValidatorType("notAllowedJson.json", KeywordType.NOT_ALLOWED); } } diff --git a/src/test/java/com/networknt/schema/NotValidatorTest.java b/src/test/java/com/networknt/schema/NotValidatorTest.java index 50607fe2b..454924745 100644 --- a/src/test/java/com/networknt/schema/NotValidatorTest.java +++ b/src/test/java/com/networknt/schema/NotValidatorTest.java @@ -36,9 +36,9 @@ void walkValidationWithNullNodeShouldNotValidate() { String jsonContents = "{}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7); - JsonSchema schema = factory.getSchema(schemaContents); - ValidationResult result = schema.walk(jsonContents, InputFormat.JSON, true); - assertEquals(true, result.getValidationMessages().isEmpty()); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7); + Schema schema = factory.getSchema(schemaContents); + Result result = schema.walk(jsonContents, InputFormat.JSON, true); + assertEquals(true, result.getErrors().isEmpty()); } } diff --git a/src/test/java/com/networknt/schema/OneOfValidatorTest.java b/src/test/java/com/networknt/schema/OneOfValidatorTest.java index 774d35f2e..83b25637c 100644 --- a/src/test/java/com/networknt/schema/OneOfValidatorTest.java +++ b/src/test/java/com/networknt/schema/OneOfValidatorTest.java @@ -27,7 +27,8 @@ import org.junit.jupiter.api.Test; -import com.networknt.schema.SpecVersion.VersionFlag; +import com.networknt.schema.dialect.Dialects; +import com.networknt.schema.path.PathType; /** * OneOfValidatorTest. @@ -64,15 +65,16 @@ void oneOfMultiple() { + " \"fox\" : \"test\",\r\n" + " \"world\" : \"test\"\r\n" + "}"; - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData); - List messages = schema.validate(inputData, InputFormat.JSON); + SchemaRegistryConfig config = SchemaRegistryConfig.builder().pathType(PathType.LEGACY).build(); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12, builder -> builder.schemaRegistryConfig(config)).getSchema(schemaData); + List messages = schema.validate(inputData, InputFormat.JSON); assertEquals(3, messages.size()); // even if more than 1 matches the mismatch errors are still reported - List assertions = messages.stream().collect(Collectors.toList()); - assertEquals("oneOf", assertions.get(0).getType()); + List assertions = messages.stream().collect(Collectors.toList()); + assertEquals("oneOf", assertions.get(0).getKeyword()); assertEquals("$", assertions.get(0).getInstanceLocation().toString()); assertEquals("$.oneOf", assertions.get(0).getEvaluationPath().toString()); assertEquals("$: must be valid to one and only one schema, but 2 are valid with indexes '1, 2'", - assertions.get(0).getMessage()); + assertions.get(0).toString()); } @Test @@ -105,24 +107,25 @@ void oneOfZero() { String inputData = "{\r\n" + " \"test\" : 1\r\n" + "}"; - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData); - List messages = schema.validate(inputData, InputFormat.JSON); + SchemaRegistryConfig config = SchemaRegistryConfig.builder().pathType(PathType.LEGACY).build(); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12, builder -> builder.schemaRegistryConfig(config)).getSchema(schemaData); + List messages = schema.validate(inputData, InputFormat.JSON); assertEquals(4, messages.size()); - List assertions = messages.stream().collect(Collectors.toList()); - assertEquals("oneOf", assertions.get(0).getType()); + List assertions = messages.stream().collect(Collectors.toList()); + assertEquals("oneOf", assertions.get(0).getKeyword()); assertEquals("$", assertions.get(0).getInstanceLocation().toString()); assertEquals("$.oneOf", assertions.get(0).getEvaluationPath().toString()); - assertEquals("$: must be valid to one and only one schema, but 0 are valid", assertions.get(0).getMessage()); + assertEquals("$: must be valid to one and only one schema, but 0 are valid", assertions.get(0).toString()); - assertEquals("additionalProperties", assertions.get(1).getType()); + assertEquals("additionalProperties", assertions.get(1).getKeyword()); assertEquals("$", assertions.get(1).getInstanceLocation().toString()); assertEquals("$.oneOf[0].additionalProperties", assertions.get(1).getEvaluationPath().toString()); - assertEquals("type", assertions.get(2).getType()); + assertEquals("type", assertions.get(2).getKeyword()); assertEquals("$.test", assertions.get(2).getInstanceLocation().toString()); assertEquals("$.oneOf[1].additionalProperties.type", assertions.get(2).getEvaluationPath().toString()); - assertEquals("type", assertions.get(3).getType()); + assertEquals("type", assertions.get(3).getKeyword()); assertEquals("$.test", assertions.get(3).getInstanceLocation().toString()); assertEquals("$.oneOf[2].additionalProperties.type", assertions.get(3).getEvaluationPath().toString()); } @@ -137,8 +140,8 @@ void invalidTypeShouldThrowJsonSchemaException() { + " \"$ref\": \"#/defs/User\"\r\n" + " }\r\n" + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - JsonSchemaException ex = assertThrows(JsonSchemaException.class, () -> factory.getSchema(schemaData)); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12); + SchemaException ex = assertThrows(SchemaException.class, () -> factory.getSchema(schemaData)); assertEquals("type", ex.getError().getMessageKey()); } @@ -184,10 +187,10 @@ void invalidSwaggerIoExample() { + " age:\r\n" + " type: integer"; - JsonSchema schema = JsonSchemaFactory - .getInstance(VersionFlag.V202012, - builder -> builder.schemaLoaders(schemaLoaders -> schemaLoaders - .schemas(Collections.singletonMap("http://example.org/example.yaml", document)))) + Schema schema = SchemaRegistry + .withDefaultDialect(SpecificationVersion.DRAFT_2020_12, + builder -> builder.resourceLoaders(resourceLoaders -> resourceLoaders + .resources(Collections.singletonMap("http://example.org/example.yaml", document)))) .getSchema(SchemaLocation.of( "http://example.org/example.yaml#/paths/~1pets/patch/requestBody/content/application~1json/schema")); @@ -258,10 +261,10 @@ void fixedSwaggerIoExample() { + " - hunts\r\n" + " - age"; - JsonSchema schema = JsonSchemaFactory - .getInstance(VersionFlag.V202012, - builder -> builder.schemaLoaders(schemaLoaders -> schemaLoaders - .schemas(Collections.singletonMap("http://example.org/example.yaml", document)))) + Schema schema = SchemaRegistry + .withDefaultDialect(SpecificationVersion.DRAFT_2020_12, + builder -> builder.resourceLoaders(resourceLoaders -> resourceLoaders + .resources(Collections.singletonMap("http://example.org/example.yaml", document)))) .getSchema(SchemaLocation.of( "http://example.org/example.yaml#/paths/~1pets/patch/requestBody/content/application~1json/schema")); @@ -301,10 +304,9 @@ void oneOfDiscriminatorEnabled() { + " }\r\n" + " ]\r\n" + "}"; - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, - SchemaValidatorsConfig.builder().discriminatorKeywordEnabled(true).build()); + Schema schema = SchemaRegistry.withDialect(Dialects.getOpenApi31()).getSchema(schemaData); String inputData = "{}"; - List messages = schema.validate(inputData, InputFormat.JSON); + List messages = schema.validate(inputData, InputFormat.JSON); assertEquals(3, messages.size()); } @@ -355,14 +357,13 @@ void oneOfDiscriminatorEnabledWithDiscriminator() { + " }\r\n" + " }\r\n" + "}"; - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, - SchemaValidatorsConfig.builder().discriminatorKeywordEnabled(true).build()); + Schema schema = SchemaRegistry.withDialect(Dialects.getOpenApi31()).getSchema(schemaData); // Valid String inputData = "{\r\n" + " \"type\": \"number\",\r\n" + " \"value\": 1\r\n" + "}"; - List messages = schema.validate(inputData, InputFormat.JSON); + List messages = schema.validate(inputData, InputFormat.JSON); assertEquals(0, messages.size()); // Invalid only 1 message returned for number @@ -370,13 +371,12 @@ void oneOfDiscriminatorEnabledWithDiscriminator() { + " \"type\": \"number\",\r\n" + " \"value\": {}\r\n" + "}"; - List messages2 = schema.validate(inputData2, InputFormat.JSON); + List messages2 = schema.validate(inputData2, InputFormat.JSON); assertEquals(2, messages2.size()); // Invalid both messages for string and object returned - JsonSchema schema2 = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, - SchemaValidatorsConfig.builder().discriminatorKeywordEnabled(false).build()); - List messages3 = schema2.validate(inputData2, InputFormat.JSON); + Schema schema2 = SchemaRegistry.withDialect(Dialects.getDraft202012()).getSchema(schemaData); + List messages3 = schema2.validate(inputData2, InputFormat.JSON); assertEquals(3, messages3.size()); } @@ -443,14 +443,13 @@ void oneOfDiscriminatorEnabledWithDiscriminatorInSubclass() { + " }\r\n" + " }\r\n" + "}"; - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, - SchemaValidatorsConfig.builder().discriminatorKeywordEnabled(true).build()); + Schema schema = SchemaRegistry.withDialect(Dialects.getOpenApi31()).getSchema(schemaData); // Valid String inputData = "{\r\n" + " \"type\": \"number\",\r\n" + " \"value\": 1\r\n" + "}"; - List messages = schema.validate(inputData, InputFormat.JSON); + List messages = schema.validate(inputData, InputFormat.JSON); assertEquals(0, messages.size()); // Invalid only 1 message returned for number @@ -458,13 +457,12 @@ void oneOfDiscriminatorEnabledWithDiscriminatorInSubclass() { + " \"type\": \"number\",\r\n" + " \"value\": {}\r\n" + "}"; - List messages2 = schema.validate(inputData2, InputFormat.JSON); + List messages2 = schema.validate(inputData2, InputFormat.JSON); assertEquals(2, messages2.size()); // Invalid both messages for string and object returned - JsonSchema schema2 = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, - SchemaValidatorsConfig.builder().discriminatorKeywordEnabled(false).build()); - List messages3 = schema2.validate(inputData2, InputFormat.JSON); + Schema schema2 = SchemaRegistry.withDialect(Dialects.getDraft202012()).getSchema(schemaData); + List messages3 = schema2.validate(inputData2, InputFormat.JSON); assertEquals(3, messages3.size()); } @@ -489,11 +487,11 @@ void walkValidationWithNullNodeShouldNotValidate() { String jsonContents = "{}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7); - JsonSchema schema = factory.getSchema(schemaContents); - ValidationResult result = schema.walk(jsonContents, InputFormat.JSON, true); - result.getValidationMessages().forEach(m -> System.out.println(m)); - assertEquals(true, result.getValidationMessages().isEmpty()); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7); + Schema schema = factory.getSchema(schemaContents); + Result result = schema.walk(jsonContents, InputFormat.JSON, true); + result.getErrors().forEach(m -> System.out.println(m)); + assertEquals(true, result.getErrors().isEmpty()); } } diff --git a/src/test/java/com/networknt/schema/OpenAPI30JsonSchemaTest.java b/src/test/java/com/networknt/schema/OpenAPI30JsonSchemaTest.java index 98606325c..09075e756 100644 --- a/src/test/java/com/networknt/schema/OpenAPI30JsonSchemaTest.java +++ b/src/test/java/com/networknt/schema/OpenAPI30JsonSchemaTest.java @@ -7,6 +7,8 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; +import com.networknt.schema.dialect.Dialects; + import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -14,8 +16,6 @@ class OpenAPI30JsonSchemaTest { protected ObjectMapper mapper = new ObjectMapper(); - protected JsonSchemaFactory validatorFactory = JsonSchemaFactory - .builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V4)).build(); OpenAPI30JsonSchemaTest() { } @@ -29,46 +29,51 @@ private void runTestFile(String testCaseFile) throws Exception { for (int j = 0; j < testCases.size(); j++) { try { JsonNode testCase = testCases.get(j); - + System.out.println("Test Case ["+(j+1)+"]: "+testCase.get("description")); + //System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(testCase.get("schema"))); ArrayNode testNodes = (ArrayNode) testCase.get("tests"); for (int i = 0; i < testNodes.size(); i++) { JsonNode test = testNodes.get(i); - System.out.println("=== " + test.get("description")); + System.out.println("> Test Data ["+(i+1)+"]: "+test); JsonNode node = test.get("data"); JsonNode typeLooseNode = test.get("isTypeLoose"); // Configure the schemaValidator to set typeLoose's value based on the test file, // if test file do not contains typeLoose flag, use default value: true. - SchemaValidatorsConfig.Builder configBuilder = SchemaValidatorsConfig.builder(); + SchemaRegistryConfig.Builder configBuilder = SchemaRegistryConfig.builder(); configBuilder.typeLoose(typeLooseNode != null && typeLooseNode.asBoolean()); - configBuilder.discriminatorKeywordEnabled(true); - JsonSchema schema = validatorFactory.getSchema(testCaseFileUri, testCase.get("schema"), configBuilder.build()); + SchemaRegistry validatorFactory = SchemaRegistry.withDialect(Dialects.getOpenApi30(), + builder -> builder.schemaRegistryConfig(configBuilder.build())); + + Schema schema = validatorFactory.getSchema(testCaseFileUri, testCase.get("schema")); - List errors = new ArrayList(schema.validate(node)); + List errors = new ArrayList(schema.validate(node)); if (test.get("valid").asBoolean()) { if (!errors.isEmpty()) { - System.out.println("---- test case failed ----"); - System.out.println("schema: " + schema); - System.out.println("data: " + test.get("data")); - System.out.println("errors:"); - for (ValidationMessage error : errors) { + System.out.println("---- Test Data ["+(i+1)+"] FAILED [Unexpected Errors] ----"); + System.out.println("> Schema: " + schema); + System.out.println("> Data : " + test.get("data")); + System.out.println("> Errors:"); + for (Error error : errors) { System.out.println(error); } } assertEquals(0, errors.size()); } else { +// System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(testCase.get("schema"))); if (errors.isEmpty()) { - System.out.println("---- test case failed ----"); - System.out.println("schema: " + schema); - System.out.println("data: " + test.get("data")); + System.out.println("---- Test Data ["+(i+1)+"] FAILED [Unexpected Success] ----"); + System.out.println("> Schema: " + schema); + System.out.println("> Data : " + test.get("data")); } else { JsonNode errorCount = test.get("errorCount"); if (errorCount != null && errorCount.isInt() && errors.size() != errorCount.asInt()) { - System.out.println("---- test case failed ----"); - System.out.println("schema: " + schema); - System.out.println("data: " + test.get("data")); - System.out.println("errors: " + errors); - for (ValidationMessage error : errors) { + System.out.println("---- Test Data [" + (i + 1) + "] FAILED [Expected " + + errorCount.asInt() + " Errors but was " + errors.size() + "] ----"); + System.out.println("> Schema: " + schema); + System.out.println("> Data : " + test.get("data")); + System.out.println("> Errors: " + errors); + for (Error error : errors) { System.out.println(error); } assertEquals(errorCount.asInt(), errors.size(), "expected error count"); @@ -77,7 +82,7 @@ private void runTestFile(String testCaseFile) throws Exception { assertFalse(errors.isEmpty()); } } - } catch (JsonSchemaException e) { + } catch (SchemaException e) { throw new IllegalStateException(String.format("Current schema should not be invalid: %s", testCaseFile), e); } } diff --git a/src/test/java/com/networknt/schema/OutputFormatTest.java b/src/test/java/com/networknt/schema/OutputFormatTest.java index 84a87169c..4f144f0c6 100644 --- a/src/test/java/com/networknt/schema/OutputFormatTest.java +++ b/src/test/java/com/networknt/schema/OutputFormatTest.java @@ -17,12 +17,11 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.networknt.schema.SpecVersion.VersionFlag; import com.networknt.schema.utils.CachingSupplier; class OutputFormatTest { - private static final JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V202012); + private static final SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12); private static final String schemaPath1 = "/schema/output-format-schema.json"; private JsonNode getJsonNodeFromJsonData(String jsonFilePath) throws Exception { @@ -35,14 +34,13 @@ private JsonNode getJsonNodeFromJsonData(String jsonFilePath) throws Exception { @DisplayName("Test Validation Messages") void testInvalidJson() throws Exception { InputStream schemaInputStream = OutputFormatTest.class.getResourceAsStream(schemaPath1); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema schema = factory.getSchema(schemaInputStream, config); + Schema schema = factory.getSchema(schemaInputStream); JsonNode node = getJsonNodeFromJsonData("/data/output-format-input.json"); - List errors = schema.validate(node); + List errors = schema.validate(node); Assertions.assertEquals(3, errors.size()); Set messages = errors.stream().map(m -> new String[] { m.getEvaluationPath().toString(), - m.getSchemaLocation().toString(), m.getInstanceLocation().toString(), m.getMessage() }) + m.getSchemaLocation().toString(), m.getInstanceLocation().toString(), m.toString() }) .collect(Collectors.toSet()); assertThat(messages, @@ -53,8 +51,8 @@ void testInvalidJson() throws Exception { new String[] { "/items/$ref/required", "https://example.com/polygon#/$defs/point/required", "/1", "/1: required property 'y' not found"})); } - public static class Detailed implements OutputFormat> { - private ValidationMessage format(ValidationMessage message) { + public static class Detailed implements OutputFormat> { + private Error format(Error message) { Supplier messageSupplier = () -> { StringBuilder builder = new StringBuilder(); builder.append("["); @@ -68,11 +66,11 @@ private ValidationMessage format(ValidationMessage message) { builder.append("'"); builder.append(" "); } - builder.append(message.getError()); + builder.append(message.getMessage()); return builder.toString(); }; - return ValidationMessage.builder() + return Error.builder() .messageSupplier(new CachingSupplier<>(messageSupplier)) .evaluationPath(message.getEvaluationPath()) .instanceLocation(message.getInstanceLocation()) @@ -84,13 +82,13 @@ private ValidationMessage format(ValidationMessage message) { } @Override - public java.util.List format(JsonSchema jsonSchema, - ExecutionContext executionContext, ValidationContext validationContext) { + public java.util.List format(Schema jsonSchema, + ExecutionContext executionContext, SchemaContext schemaContext) { return executionContext.getErrors().stream().map(this::format).collect(Collectors.toCollection(ArrayList::new)); } } - public static final OutputFormat> DETAILED = new Detailed(); + public static final OutputFormat> DETAILED = new Detailed(); @Test void customFormat() { @@ -107,13 +105,13 @@ void customFormat() { + " }\n" + " }\n" + "}"; - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012) - .getSchema(schemaData, InputFormat.JSON, SchemaValidatorsConfig.builder().build()); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12) + .getSchema(schemaData, InputFormat.JSON); String inputData = "{\n" + " \"type\": \"cat\",\n" + " \"id\": 1\n" + "}"; - List messages = schema.validate(inputData, InputFormat.JSON, DETAILED).stream().collect(Collectors.toList()); + List messages = schema.validate(inputData, InputFormat.JSON, DETAILED).stream().collect(Collectors.toList()); assertEquals("[/type] with value 'cat' does not have a value in the enumeration [\"book\", \"author\"]", messages.get(0).getMessage()); assertEquals("[/id] with value '1' integer found, string expected", messages.get(1).getMessage()); } diff --git a/src/test/java/com/networknt/schema/OutputUnitTest.java b/src/test/java/com/networknt/schema/OutputUnitTest.java index 2f0f7a12c..b10e5a58b 100644 --- a/src/test/java/com/networknt/schema/OutputUnitTest.java +++ b/src/test/java/com/networknt/schema/OutputUnitTest.java @@ -29,7 +29,6 @@ import org.junit.jupiter.params.provider.EnumSource; import com.fasterxml.jackson.core.JsonProcessingException; -import com.networknt.schema.SpecVersion.VersionFlag; import com.networknt.schema.output.OutputUnit; import com.networknt.schema.serialization.JsonMapperFactory; @@ -95,16 +94,15 @@ class OutputUnitTest { + "}"; @Test void annotationCollectionList() throws JsonProcessingException { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema schema = factory.getSchema(schemaData, config); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12); + Schema schema = factory.getSchema(schemaData); String inputData = inputData1; OutputUnit outputUnit = schema.validate(inputData, InputFormat.JSON, OutputFormat.LIST, executionConfiguration -> { - executionConfiguration.getExecutionConfig().setAnnotationCollectionEnabled(true); - executionConfiguration.getExecutionConfig().setAnnotationCollectionFilter(keyword -> true); - }); + executionConfiguration.executionConfig(executionConfig -> executionConfig + .annotationCollectionEnabled(true).annotationCollectionFilter(keyword -> true)); + }); String output = JsonMapperFactory.getInstance().writeValueAsString(outputUnit); String expected = "{\"valid\":false,\"details\":[{\"valid\":false,\"evaluationPath\":\"/properties/foo/allOf/0\",\"schemaLocation\":\"https://json-schema.org/schemas/example#/properties/foo/allOf/0\",\"instanceLocation\":\"/foo\",\"errors\":{\"required\":\"required property 'unspecified-prop' not found\"}},{\"valid\":false,\"evaluationPath\":\"/properties/foo/allOf/1/properties/foo-prop\",\"schemaLocation\":\"https://json-schema.org/schemas/example#/properties/foo/allOf/1/properties/foo-prop\",\"instanceLocation\":\"/foo/foo-prop\",\"errors\":{\"const\":\"must be the constant value '1'\"},\"droppedAnnotations\":{\"title\":\"foo-prop-title\"}},{\"valid\":false,\"evaluationPath\":\"/properties/bar/$ref/properties/bar-prop\",\"schemaLocation\":\"https://json-schema.org/schemas/example#/$defs/bar/properties/bar-prop\",\"instanceLocation\":\"/bar/bar-prop\",\"errors\":{\"minimum\":\"must have a minimum value of 10\"},\"droppedAnnotations\":{\"title\":\"bar-prop-title\"}},{\"valid\":false,\"evaluationPath\":\"/properties/foo/allOf/1\",\"schemaLocation\":\"https://json-schema.org/schemas/example#/properties/foo/allOf/1\",\"instanceLocation\":\"/foo\",\"droppedAnnotations\":{\"properties\":[\"foo-prop\"],\"title\":\"foo-title\",\"additionalProperties\":[\"foo-prop\",\"other-prop\"]}},{\"valid\":false,\"evaluationPath\":\"/properties/bar/$ref\",\"schemaLocation\":\"https://json-schema.org/schemas/example#/$defs/bar\",\"instanceLocation\":\"/bar\",\"droppedAnnotations\":{\"properties\":[\"bar-prop\"],\"title\":\"bar-title\"}},{\"valid\":false,\"evaluationPath\":\"\",\"schemaLocation\":\"https://json-schema.org/schemas/example#\",\"instanceLocation\":\"\",\"droppedAnnotations\":{\"properties\":[\"foo\",\"bar\"],\"title\":\"root\"}}]}"; assertEquals(expected, output); @@ -112,16 +110,15 @@ void annotationCollectionList() throws JsonProcessingException { @Test void annotationCollectionHierarchical() throws JsonProcessingException { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema schema = factory.getSchema(schemaData, config); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12); + Schema schema = factory.getSchema(schemaData); String inputData = inputData1; OutputUnit outputUnit = schema.validate(inputData, InputFormat.JSON, OutputFormat.HIERARCHICAL, executionConfiguration -> { - executionConfiguration.getExecutionConfig().setAnnotationCollectionEnabled(true); - executionConfiguration.getExecutionConfig().setAnnotationCollectionFilter(keyword -> true); - }); + executionConfiguration.executionConfig(executionConfig -> executionConfig + .annotationCollectionEnabled(true).annotationCollectionFilter(keyword -> true)); + }); String output = JsonMapperFactory.getInstance().writeValueAsString(outputUnit); String expected = "{\"valid\":false,\"evaluationPath\":\"\",\"schemaLocation\":\"https://json-schema.org/schemas/example#\",\"instanceLocation\":\"\",\"droppedAnnotations\":{\"properties\":[\"foo\",\"bar\"],\"title\":\"root\"},\"details\":[{\"valid\":false,\"evaluationPath\":\"/properties/foo/allOf/0\",\"schemaLocation\":\"https://json-schema.org/schemas/example#/properties/foo/allOf/0\",\"instanceLocation\":\"/foo\",\"errors\":{\"required\":\"required property 'unspecified-prop' not found\"}},{\"valid\":false,\"evaluationPath\":\"/properties/foo/allOf/1\",\"schemaLocation\":\"https://json-schema.org/schemas/example#/properties/foo/allOf/1\",\"instanceLocation\":\"/foo\",\"droppedAnnotations\":{\"properties\":[\"foo-prop\"],\"title\":\"foo-title\",\"additionalProperties\":[\"foo-prop\",\"other-prop\"]},\"details\":[{\"valid\":false,\"evaluationPath\":\"/properties/foo/allOf/1/properties/foo-prop\",\"schemaLocation\":\"https://json-schema.org/schemas/example#/properties/foo/allOf/1/properties/foo-prop\",\"instanceLocation\":\"/foo/foo-prop\",\"errors\":{\"const\":\"must be the constant value '1'\"},\"droppedAnnotations\":{\"title\":\"foo-prop-title\"}}]},{\"valid\":false,\"evaluationPath\":\"/properties/bar/$ref\",\"schemaLocation\":\"https://json-schema.org/schemas/example#/$defs/bar\",\"instanceLocation\":\"/bar\",\"droppedAnnotations\":{\"properties\":[\"bar-prop\"],\"title\":\"bar-title\"},\"details\":[{\"valid\":false,\"evaluationPath\":\"/properties/bar/$ref/properties/bar-prop\",\"schemaLocation\":\"https://json-schema.org/schemas/example#/$defs/bar/properties/bar-prop\",\"instanceLocation\":\"/bar/bar-prop\",\"errors\":{\"minimum\":\"must have a minimum value of 10\"},\"droppedAnnotations\":{\"title\":\"bar-prop-title\"}}]}]}"; assertEquals(expected, output); @@ -129,16 +126,15 @@ void annotationCollectionHierarchical() throws JsonProcessingException { @Test void annotationCollectionHierarchical2() throws JsonProcessingException { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema schema = factory.getSchema(schemaData, config); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12); + Schema schema = factory.getSchema(schemaData); String inputData = inputData2; OutputUnit outputUnit = schema.validate(inputData, InputFormat.JSON, OutputFormat.HIERARCHICAL, executionConfiguration -> { - executionConfiguration.getExecutionConfig().setAnnotationCollectionEnabled(true); - executionConfiguration.getExecutionConfig().setAnnotationCollectionFilter(keyword -> true); - }); + executionConfiguration.executionConfig(executionConfig -> executionConfig + .annotationCollectionEnabled(true).annotationCollectionFilter(keyword -> true)); + }); String output = JsonMapperFactory.getInstance().writeValueAsString(outputUnit); String expected = "{\"valid\":true,\"evaluationPath\":\"\",\"schemaLocation\":\"https://json-schema.org/schemas/example#\",\"instanceLocation\":\"\",\"annotations\":{\"properties\":[\"foo\",\"bar\"],\"title\":\"root\"},\"details\":[{\"valid\":true,\"evaluationPath\":\"/properties/foo/allOf/1\",\"schemaLocation\":\"https://json-schema.org/schemas/example#/properties/foo/allOf/1\",\"instanceLocation\":\"/foo\",\"annotations\":{\"properties\":[\"foo-prop\"],\"title\":\"foo-title\",\"additionalProperties\":[\"foo-prop\",\"unspecified-prop\"]},\"details\":[{\"valid\":true,\"evaluationPath\":\"/properties/foo/allOf/1/properties/foo-prop\",\"schemaLocation\":\"https://json-schema.org/schemas/example#/properties/foo/allOf/1/properties/foo-prop\",\"instanceLocation\":\"/foo/foo-prop\",\"annotations\":{\"title\":\"foo-prop-title\"}}]},{\"valid\":true,\"evaluationPath\":\"/properties/bar/$ref\",\"schemaLocation\":\"https://json-schema.org/schemas/example#/$defs/bar\",\"instanceLocation\":\"/bar\",\"annotations\":{\"properties\":[\"bar-prop\"],\"title\":\"bar-title\"},\"details\":[{\"valid\":true,\"evaluationPath\":\"/properties/bar/$ref/properties/bar-prop\",\"schemaLocation\":\"https://json-schema.org/schemas/example#/$defs/bar/properties/bar-prop\",\"instanceLocation\":\"/bar/bar-prop\",\"annotations\":{\"title\":\"bar-prop-title\"}}]}]}"; assertEquals(expected, output); @@ -178,13 +174,12 @@ void formatAnnotation(FormatInput formatInput) { + " \"type\": \"string\",\r\n" + " \"format\": \""+formatInput.format+"\"\r\n" + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema schema = factory.getSchema(formatSchema, config); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12); + Schema schema = factory.getSchema(formatSchema); OutputUnit outputUnit = schema.validate("\"inval!i:d^(abc]\"", InputFormat.JSON, OutputFormat.LIST, executionConfiguration -> { - executionConfiguration.getExecutionConfig().setAnnotationCollectionEnabled(true); - executionConfiguration.getExecutionConfig().setAnnotationCollectionFilter(keyword -> true); - }); + executionConfiguration.executionConfig(executionConfig -> executionConfig + .annotationCollectionEnabled(true).annotationCollectionFilter(keyword -> true)); + }); assertTrue(outputUnit.isValid()); OutputUnit details = outputUnit.getDetails().get(0); assertEquals(formatInput.format, details.getAnnotations().get("format")); @@ -197,14 +192,13 @@ void formatAssertion(FormatInput formatInput) { + " \"type\": \"string\",\r\n" + " \"format\": \""+formatInput.format+"\"\r\n" + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema schema = factory.getSchema(formatSchema, config); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12); + Schema schema = factory.getSchema(formatSchema); OutputUnit outputUnit = schema.validate("\"inval!i:d^(abc]\"", InputFormat.JSON, OutputFormat.LIST, executionConfiguration -> { - executionConfiguration.getExecutionConfig().setAnnotationCollectionEnabled(true); - executionConfiguration.getExecutionConfig().setAnnotationCollectionFilter(keyword -> true); - executionConfiguration.getExecutionConfig().setFormatAssertionsEnabled(true); - }); + executionConfiguration.executionConfig(executionConfig -> executionConfig + .annotationCollectionEnabled(true).annotationCollectionFilter(keyword -> true) + .formatAssertionsEnabled(true)); + }); assertFalse(outputUnit.isValid()); OutputUnit details = outputUnit.getDetails().get(0); assertEquals(formatInput.format, details.getDroppedAnnotations().get("format")); @@ -216,13 +210,12 @@ void typeUnion() { String typeSchema = "{\r\n" + " \"type\": [\"string\",\"array\"]\r\n" + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema schema = factory.getSchema(typeSchema, config); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12); + Schema schema = factory.getSchema(typeSchema); OutputUnit outputUnit = schema.validate("1", InputFormat.JSON, OutputFormat.LIST, executionConfiguration -> { - executionConfiguration.getExecutionConfig().setAnnotationCollectionEnabled(true); - executionConfiguration.getExecutionConfig().setAnnotationCollectionFilter(keyword -> true); - }); + executionConfiguration.executionConfig(executionConfig -> executionConfig + .annotationCollectionEnabled(true).annotationCollectionFilter(keyword -> true)); + }); assertFalse(outputUnit.isValid()); OutputUnit details = outputUnit.getDetails().get(0); assertNotNull(details.getErrors().get("type")); @@ -265,10 +258,9 @@ void unevaluatedProperties() throws JsonProcessingException { + " \"unevaluatedProperties\": false\r\n" + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012, - builder -> builder.schemaLoaders(schemaLoaders -> schemaLoaders.schemas(external))); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema schema = factory.getSchema(schemaData, config); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12, + builder -> builder.resourceLoaders(resourceLoaders -> resourceLoaders.resources(external))); + Schema schema = factory.getSchema(schemaData); // The following checks if the heirarchical output format is correct with multiple unevaluated properties String inputData = "{\r\n" @@ -278,8 +270,8 @@ void unevaluatedProperties() throws JsonProcessingException { + " \"coordinates\": [1, 1]\r\n" + "}"; OutputUnit outputUnit = schema.validate(inputData, InputFormat.JSON, OutputFormat.HIERARCHICAL, - executionContext -> executionContext.getExecutionConfig() - .setAnnotationCollectionFilter(keyword -> true)); + executionContext -> executionContext.executionConfig(executionConfig -> executionConfig + .annotationCollectionFilter(keyword -> true))); String output = JsonMapperFactory.getInstance().writeValueAsString(outputUnit); String expected = "{\"valid\":false,\"evaluationPath\":\"\",\"schemaLocation\":\"#\",\"instanceLocation\":\"\",\"errors\":{\"unevaluatedProperties\":[\"property 'hello' is not evaluated and the schema does not allow unevaluated properties\",\"property 'world' is not evaluated and the schema does not allow unevaluated properties\"]},\"droppedAnnotations\":{\"unevaluatedProperties\":[\"hello\",\"world\"]},\"details\":[{\"valid\":false,\"evaluationPath\":\"/$ref\",\"schemaLocation\":\"https://www.example.org/point.json#\",\"instanceLocation\":\"\",\"droppedAnnotations\":{\"properties\":[\"type\",\"coordinates\"]}}]}"; assertEquals(expected, output); @@ -315,18 +307,17 @@ void anyOf() throws JsonProcessingException { + " ]\r\n" + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema schema = factory.getSchema(schemaData, config); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12); + Schema schema = factory.getSchema(schemaData); String inputData = "{\r\n" + " \"foo\": \"hello\",\r\n" + " \"bar\": 1\r\n" + "}"; OutputUnit outputUnit = schema.validate(inputData, InputFormat.JSON, OutputFormat.HIERARCHICAL, executionContext -> { - executionContext.getExecutionConfig().setAnnotationCollectionEnabled(true); - executionContext.getExecutionConfig().setAnnotationCollectionFilter(keyword -> true); - }); + executionContext.executionConfig(executionConfig -> executionConfig + .annotationCollectionEnabled(true).annotationCollectionFilter(keyword -> true)); + }); String output = JsonMapperFactory.getInstance().writeValueAsString(outputUnit); String expected = "{\"valid\":true,\"evaluationPath\":\"\",\"schemaLocation\":\"#\",\"instanceLocation\":\"\",\"details\":[{\"valid\":true,\"evaluationPath\":\"/anyOf/0\",\"schemaLocation\":\"#/anyOf/0\",\"instanceLocation\":\"\",\"annotations\":{\"properties\":[\"foo\"]}},{\"valid\":true,\"evaluationPath\":\"/anyOf/1\",\"schemaLocation\":\"#/anyOf/1\",\"instanceLocation\":\"\",\"annotations\":{\"properties\":[\"bar\"]}}]}"; assertEquals(expected, output); @@ -337,14 +328,13 @@ void listAssertionMapper() { String formatSchema = "{\r\n" + " \"type\": \"string\"\r\n" + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema schema = factory.getSchema(formatSchema, config); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12); + Schema schema = factory.getSchema(formatSchema); OutputUnit outputUnit = schema.validate("1234", InputFormat.JSON, new OutputFormat.List(a -> a)); assertFalse(outputUnit.isValid()); OutputUnit details = outputUnit.getDetails().get(0); Object assertion = details.getErrors().get("type"); - assertInstanceOf(ValidationMessage.class, assertion); + assertInstanceOf(Error.class, assertion); } @Test @@ -352,12 +342,11 @@ void hierarchicalAssertionMapper() { String formatSchema = "{\r\n" + " \"type\": \"string\"\r\n" + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema schema = factory.getSchema(formatSchema, config); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12); + Schema schema = factory.getSchema(formatSchema); OutputUnit outputUnit = schema.validate("1234", InputFormat.JSON, new OutputFormat.Hierarchical(a -> a)); assertFalse(outputUnit.isValid()); Object assertion = outputUnit.getErrors().get("type"); - assertInstanceOf(ValidationMessage.class, assertion); + assertInstanceOf(Error.class, assertion); } } diff --git a/src/test/java/com/networknt/schema/OverrideValidatorTest.java b/src/test/java/com/networknt/schema/OverrideValidatorTest.java index 9f12297ac..786beab44 100644 --- a/src/test/java/com/networknt/schema/OverrideValidatorTest.java +++ b/src/test/java/com/networknt/schema/OverrideValidatorTest.java @@ -19,6 +19,8 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import com.networknt.schema.dialect.Dialect; +import com.networknt.schema.dialect.Dialects; import com.networknt.schema.format.PatternFormat; import org.junit.jupiter.api.Test; @@ -49,15 +51,15 @@ void overrideDefaultValidator() throws JsonProcessingException, IOException { " \"timestamp\": \"bad\"\n" + "}"); // Use Default EmailValidator - final JsonMetaSchema validatorMetaSchema = JsonMetaSchema - .builder(URI, JsonMetaSchema.getV201909()) + final Dialect validatorMetaSchema = Dialect + .builder(URI, Dialects.getDraft201909()) .build(); - final JsonSchemaFactory validatorFactory = JsonSchemaFactory.builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V201909)).metaSchema(validatorMetaSchema).build(); - final JsonSchema validatorSchema = validatorFactory.getSchema(schema); + final SchemaRegistry validatorFactory = SchemaRegistry.withDialect(validatorMetaSchema); + final Schema validatorSchema = validatorFactory.getSchema(schema); - List messages = validatorSchema.validate(targetNode, OutputFormat.DEFAULT, (executionContext, validationContext) -> { - executionContext.getExecutionConfig().setFormatAssertionsEnabled(true); + List messages = validatorSchema.validate(targetNode, OutputFormat.DEFAULT, (executionContext, schemaContext) -> { + executionContext.executionConfig(executionConfig -> executionConfig.formatAssertionsEnabled(true)); }); assertEquals(2, messages.size(), Arrays.toString(messages.toArray())); @@ -65,16 +67,16 @@ void overrideDefaultValidator() throws JsonProcessingException, IOException { assertTrue(messages.stream().anyMatch(it -> it.getInstanceLocation().getName(-1).equals("timestamp"))); // Override EmailValidator - final JsonMetaSchema overrideValidatorMetaSchema = JsonMetaSchema - .builder(URI, JsonMetaSchema.getV201909()) + final Dialect overrideValidatorMetaSchema = Dialect + .builder(URI, Dialects.getDraft201909()) .format(PatternFormat.of("email", "^[a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\\.[a-zA-Z0-9-]+)*$", "format.email")) .build(); - final JsonSchemaFactory overrideValidatorFactory = JsonSchemaFactory.builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V201909)).metaSchema(overrideValidatorMetaSchema).build(); - final JsonSchema overrideValidatorSchema = overrideValidatorFactory.getSchema(schema); + final SchemaRegistry overrideValidatorFactory = SchemaRegistry.withDialect(overrideValidatorMetaSchema); + final Schema overrideValidatorSchema = overrideValidatorFactory.getSchema(schema); messages = overrideValidatorSchema.validate(targetNode, executionContext -> { - executionContext.getExecutionConfig().setFormatAssertionsEnabled(true); + executionContext.executionConfig(executionConfig -> executionConfig.formatAssertionsEnabled(true)); }); assertTrue(messages.stream().anyMatch(it -> it.getInstanceLocation().getName(-1).equals("timestamp"))); assertEquals(1, messages.size()); diff --git a/src/test/java/com/networknt/schema/OverwritingCustomMessageBugTest.java b/src/test/java/com/networknt/schema/OverwritingCustomMessageBugTest.java index 3018a8eef..3b14f3032 100644 --- a/src/test/java/com/networknt/schema/OverwritingCustomMessageBugTest.java +++ b/src/test/java/com/networknt/schema/OverwritingCustomMessageBugTest.java @@ -2,7 +2,9 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.networknt.schema.SpecVersion.VersionFlag; +import com.networknt.schema.path.PathType; +import com.networknt.schema.regex.JDKRegularExpressionFactory; + import java.io.InputStream; import java.util.HashMap; import java.util.List; @@ -11,8 +13,11 @@ import org.junit.jupiter.api.Test; class OverwritingCustomMessageBugTest { - private JsonSchema getJsonSchemaFromStreamContentV7(InputStream schemaContent) { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V7); + private Schema getJsonSchemaFromStreamContentV7(InputStream schemaContent) { + SchemaRegistryConfig config = SchemaRegistryConfig.builder().pathType(PathType.LEGACY) + .errorMessageKeyword("message") + .regularExpressionFactory(JDKRegularExpressionFactory.getInstance()).build(); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7, builder -> builder.schemaRegistryConfig(config)); return factory.getSchema(schemaContent); } @@ -23,7 +28,7 @@ private JsonNode getJsonNodeFromStreamContent(InputStream content) throws Except @Test void customMessageIsNotOverwritten() throws Exception { - List errors = validate(); + List errors = validate(); Map errorMsgMap = transferErrorMsg(errors); Assertions.assertTrue(errorMsgMap.containsKey("$.toplevel[1].foos"), "error message must contains key: $.foos"); Assertions.assertTrue(errorMsgMap.containsKey("$.toplevel[1].bars"), "error message must contains key: $.bars"); @@ -32,20 +37,20 @@ void customMessageIsNotOverwritten() throws Exception { } - private List validate() throws Exception { + private List validate() throws Exception { String schemaPath = "/schema/OverwritingCustomMessageBug.json"; String dataPath = "/data/OverwritingCustomMessageBug.json"; InputStream schemaInputStream = OverwritingCustomMessageBugTest.class.getResourceAsStream(schemaPath); - JsonSchema schema = getJsonSchemaFromStreamContentV7(schemaInputStream); + Schema schema = getJsonSchemaFromStreamContentV7(schemaInputStream); InputStream dataInputStream = OverwritingCustomMessageBugTest.class.getResourceAsStream(dataPath); JsonNode node = getJsonNodeFromStreamContent(dataInputStream); return schema.validate(node); } - private Map transferErrorMsg(List validationMessages) { + private Map transferErrorMsg(List errors) { Map pathToMessage = new HashMap<>(); - validationMessages.forEach(msg -> { - pathToMessage.put(msg.getInstanceLocation().toString(), msg.getMessage()); + errors.forEach(msg -> { + pathToMessage.put(msg.getInstanceLocation().toString(), msg.toString()); }); return pathToMessage; } diff --git a/src/test/java/com/networknt/schema/PatternPropertiesValidatorTest.java b/src/test/java/com/networknt/schema/PatternPropertiesValidatorTest.java index de7d298a9..452e97afd 100644 --- a/src/test/java/com/networknt/schema/PatternPropertiesValidatorTest.java +++ b/src/test/java/com/networknt/schema/PatternPropertiesValidatorTest.java @@ -17,7 +17,6 @@ package com.networknt.schema; import com.fasterxml.jackson.databind.JsonNode; -import com.networknt.schema.SpecVersion.VersionFlag; import com.networknt.schema.output.OutputUnit; import com.networknt.schema.regex.JoniRegularExpressionFactory; @@ -40,27 +39,27 @@ class PatternPropertiesValidatorTest extends BaseJsonSchemaValidatorTest { @Test void testInvalidPatternPropertiesValidator() throws Exception { - Assertions.assertThrows(JsonSchemaException.class, () -> { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V4); - JsonSchema schema = factory.getSchema("{\"patternProperties\":6}"); + Assertions.assertThrows(SchemaException.class, () -> { + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_4); + Schema schema = factory.getSchema("{\"patternProperties\":6}"); JsonNode node = getJsonNodeFromStringContent(""); - List errors = schema.validate(node); + List errors = schema.validate(node); Assertions.assertEquals(errors.size(), 0); }); } @Test void testInvalidPatternPropertiesValidatorECMA262() throws Exception { - Assertions.assertThrows(JsonSchemaException.class, () -> { - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder() + Assertions.assertThrows(SchemaException.class, () -> { + SchemaRegistryConfig config = SchemaRegistryConfig.builder() .regularExpressionFactory(JoniRegularExpressionFactory.getInstance()) .build(); - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V4); - JsonSchema schema = factory.getSchema("{\"patternProperties\":6}", config); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_4, builder -> builder.schemaRegistryConfig(config)); + Schema schema = factory.getSchema("{\"patternProperties\":6}"); JsonNode node = getJsonNodeFromStringContent(""); - List errors = schema.validate(node); + List errors = schema.validate(node); Assertions.assertEquals(errors.size(), 0); }); } @@ -79,23 +78,22 @@ void message() { + " }\n" + " }\n" + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema schema = factory.getSchema(schemaData, config); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12); + Schema schema = factory.getSchema(schemaData); String inputData = "{\n" + " \"valid_array\": [\"array1_value\", \"array2_value\"],\n" + " \"valid_string\": \"string_value\",\n" + " \"valid_key\": 5\n" + "}"; - List messages = schema.validate(inputData, InputFormat.JSON); + List messages = schema.validate(inputData, InputFormat.JSON); assertFalse(messages.isEmpty()); - ValidationMessage message = messages.iterator().next(); + Error message = messages.iterator().next(); assertEquals("/patternProperties/^valid_/type", message.getEvaluationPath().toString()); assertEquals("https://www.example.org/schema#/patternProperties/^valid_/type", message.getSchemaLocation().toString()); assertEquals("/valid_key", message.getInstanceLocation().toString()); assertEquals("[\"array\",\"string\"]", message.getSchemaNode().toString()); assertEquals("5", message.getInstanceNode().toString()); - assertEquals("/valid_key: integer found, [array, string] expected", message.getMessage()); + assertEquals("/valid_key: integer found, [array, string] expected", message.toString()); assertNull(message.getProperty()); String inputData2 = "{\n" @@ -111,7 +109,7 @@ void message() { assertEquals("/valid_array/0", message.getInstanceLocation().toString()); assertEquals("\"string\"", message.getSchemaNode().toString()); assertEquals("999", message.getInstanceNode().toString()); - assertEquals("/valid_array/0: integer found, string expected", message.getMessage()); + assertEquals("/valid_array/0: integer found, string expected", message.toString()); assertNull(message.getProperty()); } @@ -130,16 +128,15 @@ void annotation() { + " }\n" + " }\n" + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema schema = factory.getSchema(schemaData, config); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12); + Schema schema = factory.getSchema(schemaData); String inputData = "{\n" + " \"test\": 5\n" + "}"; OutputUnit outputUnit = schema.validate(inputData, InputFormat.JSON, OutputFormat.HIERARCHICAL, executionContext -> { - executionContext.getExecutionConfig().setAnnotationCollectionEnabled(true); - executionContext.getExecutionConfig().setAnnotationCollectionFilter(keyword -> true); - }); + executionContext.executionConfig(executionConfig -> executionConfig + .annotationCollectionEnabled(true).annotationCollectionFilter(keyword -> true)); + }); Set patternProperties = (Set) outputUnit.getAnnotations().get("patternProperties"); assertTrue(patternProperties.isEmpty()); @@ -148,9 +145,9 @@ void annotation() { + " \"valid_string\": \"string_value\"" + "}"; outputUnit = schema.validate(inputData, InputFormat.JSON, OutputFormat.HIERARCHICAL, executionContext -> { - executionContext.getExecutionConfig().setAnnotationCollectionEnabled(true); - executionContext.getExecutionConfig().setAnnotationCollectionFilter(keyword -> true); - }); + executionContext.executionConfig(executionConfig -> executionConfig + .annotationCollectionEnabled(true).annotationCollectionFilter(keyword -> true)); + }); patternProperties = (Set) outputUnit.getAnnotations().get("patternProperties"); Set all = new HashSet<>(); all.add("valid_array"); diff --git a/src/test/java/com/networknt/schema/PatternValidatorTest.java b/src/test/java/com/networknt/schema/PatternValidatorTest.java index ba77fa00b..3dd1e3188 100644 --- a/src/test/java/com/networknt/schema/PatternValidatorTest.java +++ b/src/test/java/com/networknt/schema/PatternValidatorTest.java @@ -19,8 +19,6 @@ import org.junit.jupiter.api.Test; -import com.networknt.schema.SpecVersion.VersionFlag; - /** * PatternValidatorTest. */ @@ -32,7 +30,7 @@ void failFast() { + " \"pattern\": \"^(\\\\([0-9]{3}\\\\))?[0-9]{3}-[0-9]{4}$\"\r\n" + "}"; String inputData = "\"hello\""; - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12).getSchema(schemaData); boolean result = schema.validate(inputData, InputFormat.JSON, OutputFormat.BOOLEAN); assertFalse(result); } diff --git a/src/test/java/com/networknt/schema/PrefixItemsValidatorTest.java b/src/test/java/com/networknt/schema/PrefixItemsValidatorTest.java index 27bc08db8..dc1281286 100644 --- a/src/test/java/com/networknt/schema/PrefixItemsValidatorTest.java +++ b/src/test/java/com/networknt/schema/PrefixItemsValidatorTest.java @@ -6,9 +6,13 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; -import com.networknt.schema.SpecVersion.VersionFlag; +import com.networknt.schema.keyword.PrefixItemsValidator; +import com.networknt.schema.path.NodePath; import com.networknt.schema.serialization.JsonMapperFactory; -import com.networknt.schema.walk.JsonSchemaWalkListener; +import com.networknt.schema.walk.ApplyDefaultsStrategy; +import com.networknt.schema.walk.ItemWalkListenerRunner; +import com.networknt.schema.walk.WalkListener; +import com.networknt.schema.walk.WalkConfig; import com.networknt.schema.walk.WalkEvent; import com.networknt.schema.walk.WalkFlow; @@ -32,10 +36,10 @@ class PrefixItemsValidatorTest extends AbstractJsonSchemaTestSuite { */ @Test void testEmptyPrefixItemsException() { - Stream dynamicNodeStream = createTests(SpecVersion.VersionFlag.V7, "src/test/resources/prefixItemsException"); + Stream dynamicNodeStream = createTests(SpecificationVersion.DRAFT_7, "src/test/resources/prefixItemsException"); dynamicNodeStream.forEach( dynamicNode -> { - assertThrows(JsonSchemaException.class, () -> { + assertThrows(SchemaException.class, () -> { ((DynamicContainer) dynamicNode).getChildren().forEach(dynamicNode1 -> { }); }); @@ -53,19 +57,19 @@ void messageInvalid() { + " \"$id\": \"https://www.example.org/schema\",\r\n" + " \"prefixItems\": [{\"type\": \"string\"},{\"type\": \"integer\"}]" + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema schema = factory.getSchema(schemaData, config); + SchemaRegistryConfig config = SchemaRegistryConfig.builder().build(); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12, builder -> builder.schemaRegistryConfig(config)); + Schema schema = factory.getSchema(schemaData); String inputData = "[1, \"x\"]"; - List messages = schema.validate(inputData, InputFormat.JSON); + List messages = schema.validate(inputData, InputFormat.JSON); assertFalse(messages.isEmpty()); - ValidationMessage message = messages.iterator().next(); + Error message = messages.iterator().next(); assertEquals("/prefixItems/0/type", message.getEvaluationPath().toString()); assertEquals("https://www.example.org/schema#/prefixItems/0/type", message.getSchemaLocation().toString()); assertEquals("/0", message.getInstanceLocation().toString()); assertEquals("\"string\"", message.getSchemaNode().toString()); assertEquals("1", message.getInstanceNode().toString()); - assertEquals("/0: integer found, string expected", message.getMessage()); + assertEquals("/0: integer found, string expected", message.toString()); assertNull(message.getProperty()); } @@ -79,11 +83,11 @@ void messageValid() { + " \"$id\": \"https://www.example.org/schema\",\r\n" + " \"prefixItems\": [{\"type\": \"string\"},{\"type\": \"integer\"}]" + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema schema = factory.getSchema(schemaData, config); + SchemaRegistryConfig config = SchemaRegistryConfig.builder().build(); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12, builder -> builder.schemaRegistryConfig(config)); + Schema schema = factory.getSchema(schemaData); String inputData = "[\"x\", 1, 1]"; - List messages = schema.validate(inputData, InputFormat.JSON); + List messages = schema.validate(inputData, InputFormat.JSON); assertTrue(messages.isEmpty()); } @@ -98,19 +102,19 @@ void messageInvalidAdditionalItems() { + " \"prefixItems\": [{\"type\": \"string\"},{\"type\": \"integer\"}],\r\n" + " \"items\": false" + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema schema = factory.getSchema(schemaData, config); + SchemaRegistryConfig config = SchemaRegistryConfig.builder().build(); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12, builder -> builder.schemaRegistryConfig(config)); + Schema schema = factory.getSchema(schemaData); String inputData = "[\"x\", 1, 1, 2]"; - List messages = schema.validate(inputData, InputFormat.JSON); + List messages = schema.validate(inputData, InputFormat.JSON); assertFalse(messages.isEmpty()); - ValidationMessage message = messages.iterator().next(); + Error message = messages.iterator().next(); assertEquals("/items", message.getEvaluationPath().toString()); assertEquals("https://www.example.org/schema#/items", message.getSchemaLocation().toString()); assertEquals("", message.getInstanceLocation().toString()); assertEquals("false", message.getSchemaNode().toString()); assertEquals("[\"x\",1,1,2]", message.getInstanceNode().toString()); - assertEquals(": index '2' is not defined in the schema and the schema does not allow additional items", message.getMessage()); + assertEquals(": index '2' is not defined in the schema and the schema does not allow additional items", message.toString()); assertNull(message.getProperty()); } @@ -129,26 +133,29 @@ void walkNull() { + " }\n" + " ]\n" + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().itemWalkListener(new JsonSchemaWalkListener() { + ItemWalkListenerRunner itemWalkListenerRunner = ItemWalkListenerRunner.builder().itemWalkListener(new WalkListener() { @Override public WalkFlow onWalkStart(WalkEvent walkEvent) { return WalkFlow.CONTINUE; } @Override - public void onWalkEnd(WalkEvent walkEvent, List validationMessages) { + public void onWalkEnd(WalkEvent walkEvent, List errors) { @SuppressWarnings("unchecked") List items = (List) walkEvent.getExecutionContext() .getCollectorContext() - .getCollectorMap() - .computeIfAbsent("items", key -> new ArrayList()); + .getData() + .computeIfAbsent("items", key -> new ArrayList()); items.add(walkEvent); } }).build(); - JsonSchema schema = factory.getSchema(schemaData, config); - ValidationResult result = schema.walk(null, true); - assertTrue(result.getValidationMessages().isEmpty()); + WalkConfig walkConfig = WalkConfig.builder().itemWalkListenerRunner(itemWalkListenerRunner).build(); + + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12); + Schema schema = factory.getSchema(schemaData); + Result result = schema.walk(null, true, + executionContext -> executionContext.setWalkConfig(walkConfig)); + assertTrue(result.getErrors().isEmpty()); @SuppressWarnings("unchecked") List items = (List) result.getExecutionContext().getCollectorContext().get("items"); @@ -182,31 +189,31 @@ void walkDefaults() throws JsonProcessingException { + " }\n" + " ]\n" + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder() - .applyDefaultsStrategy(new ApplyDefaultsStrategy(true, true, true)) - .itemWalkListener(new JsonSchemaWalkListener() { - + + ItemWalkListenerRunner itemWalkListenerRunner = ItemWalkListenerRunner.builder() + .itemWalkListener(new WalkListener() { @Override public WalkFlow onWalkStart(WalkEvent walkEvent) { return WalkFlow.CONTINUE; } @Override - public void onWalkEnd(WalkEvent walkEvent, List validationMessages) { + public void onWalkEnd(WalkEvent walkEvent, List errors) { @SuppressWarnings("unchecked") - List items = (List) walkEvent.getExecutionContext() - .getCollectorContext() - .getCollectorMap() - .computeIfAbsent("items", key -> new ArrayList()); + List items = (List) walkEvent.getExecutionContext().getCollectorContext() + .getData().computeIfAbsent("items", key -> new ArrayList()); items.add(walkEvent); } - }) - .build(); - JsonSchema schema = factory.getSchema(schemaData, config); + }).build(); + WalkConfig walkConfig = WalkConfig.builder().applyDefaultsStrategy(new ApplyDefaultsStrategy(true, true, true)) + .itemWalkListenerRunner(itemWalkListenerRunner).build(); + + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12); + Schema schema = factory.getSchema(schemaData); JsonNode input = JsonMapperFactory.getInstance().readTree("[null, null]"); - ValidationResult result = schema.walk(input, true); - assertTrue(result.getValidationMessages().isEmpty()); + Result result = schema.walk(input, true, + executionContext -> executionContext.setWalkConfig(walkConfig)); + assertTrue(result.getErrors().isEmpty()); @SuppressWarnings("unchecked") List items = (List) result.getExecutionContext().getCollectorContext().get("items"); diff --git a/src/test/java/com/networknt/schema/PropertiesTest.java b/src/test/java/com/networknt/schema/PropertiesTest.java index 083a550ed..e427ceeec 100644 --- a/src/test/java/com/networknt/schema/PropertiesTest.java +++ b/src/test/java/com/networknt/schema/PropertiesTest.java @@ -1,7 +1,5 @@ package com.networknt.schema; -import com.networknt.schema.SpecVersion.VersionFlag; - import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.DynamicNode; import org.junit.jupiter.api.TestFactory; @@ -14,7 +12,7 @@ class PropertiesTest extends AbstractJsonSchemaTestSuite { @TestFactory @DisplayName("Draft 2019-09") Stream draft201909() { - return createTests(VersionFlag.V201909, "src/test/resources/draft2019-09/properties.json"); + return createTests(SpecificationVersion.DRAFT_2019_09, "src/test/resources/draft2019-09/properties.json"); } } diff --git a/src/test/java/com/networknt/schema/PropertiesValidatorTest.java b/src/test/java/com/networknt/schema/PropertiesValidatorTest.java index b9de07034..035081c0a 100644 --- a/src/test/java/com/networknt/schema/PropertiesValidatorTest.java +++ b/src/test/java/com/networknt/schema/PropertiesValidatorTest.java @@ -1,6 +1,9 @@ package com.networknt.schema; import com.fasterxml.jackson.databind.JsonNode; +import com.networknt.schema.walk.ApplyDefaultsStrategy; +import com.networknt.schema.walk.WalkConfig; + import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -12,16 +15,12 @@ class PropertiesValidatorTest extends BaseJsonSchemaValidatorTest { @Test void testDoesNotThrowWhenApplyingDefaultPropertiesToNonObjects() throws Exception { Assertions.assertDoesNotThrow(() -> { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V4); - - SchemaValidatorsConfig schemaValidatorsConfig = SchemaValidatorsConfig.builder() - .applyDefaultsStrategy(new ApplyDefaultsStrategy(true, true, true)) - .build(); - - JsonSchema schema = factory.getSchema("{\"type\":\"object\",\"properties\":{\"foo\":{\"type\":\"object\", \"properties\": {} },\"i-have-default\":{\"type\":\"string\",\"default\":\"foo\"}}}", schemaValidatorsConfig); + WalkConfig walkConfig = WalkConfig.builder().applyDefaultsStrategy(new ApplyDefaultsStrategy(true, true, true)).build(); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_4); + Schema schema = factory.getSchema("{\"type\":\"object\",\"properties\":{\"foo\":{\"type\":\"object\", \"properties\": {} },\"i-have-default\":{\"type\":\"string\",\"default\":\"foo\"}}}"); JsonNode node = getJsonNodeFromStringContent("{\"foo\": \"bar\"}"); - ValidationResult result = schema.walk(node, true); - Assertions.assertEquals(result.getValidationMessages().size(), 1); + Result result = schema.walk(node, true, executionContext -> executionContext.setWalkConfig(walkConfig)); + Assertions.assertEquals(result.getErrors().size(), 1); }); } } diff --git a/src/test/java/com/networknt/schema/PropertyNamesValidatorTest.java b/src/test/java/com/networknt/schema/PropertyNamesValidatorTest.java index 9100c6429..e39cc6a42 100644 --- a/src/test/java/com/networknt/schema/PropertyNamesValidatorTest.java +++ b/src/test/java/com/networknt/schema/PropertyNamesValidatorTest.java @@ -22,8 +22,6 @@ import org.junit.jupiter.api.Test; -import com.networknt.schema.SpecVersion.VersionFlag; - /** * PropertyNamesValidatorTest. */ @@ -38,22 +36,21 @@ void messageInvalid() { + " \"$id\": \"https://www.example.org/schema\",\r\n" + " \"propertyNames\": {\"maxLength\": 3}\r\n" + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema schema = factory.getSchema(schemaData, config); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12); + Schema schema = factory.getSchema(schemaData); String inputData = "{\r\n" + " \"foo\": {},\r\n" + " \"foobar\": {}\r\n" + "}"; - List messages = schema.validate(inputData, InputFormat.JSON); + List messages = schema.validate(inputData, InputFormat.JSON); assertFalse(messages.isEmpty()); - ValidationMessage message = messages.iterator().next(); + Error message = messages.iterator().next(); assertEquals("/propertyNames", message.getEvaluationPath().toString()); assertEquals("https://www.example.org/schema#/propertyNames", message.getSchemaLocation().toString()); assertEquals("", message.getInstanceLocation().toString()); assertEquals("{\"maxLength\":3}", message.getSchemaNode().toString()); assertEquals("{\"foo\":{},\"foobar\":{}}", message.getInstanceNode().toString()); - assertEquals(": property 'foobar' name is not valid: must be at most 3 characters long", message.getMessage()); + assertEquals(": property 'foobar' name is not valid: must be at most 3 characters long", message.toString()); assertEquals("foobar", message.getProperty()); } } diff --git a/src/test/java/com/networknt/schema/QuickStartTest.java b/src/test/java/com/networknt/schema/QuickStartTest.java new file mode 100644 index 000000000..6b10c883d --- /dev/null +++ b/src/test/java/com/networknt/schema/QuickStartTest.java @@ -0,0 +1,196 @@ +package com.networknt.schema; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.junit.jupiter.api.Test; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.networknt.schema.dialect.Dialects; +import com.networknt.schema.serialization.JsonMapperFactory; + +/** + * Quick start test. + */ +class QuickStartTest { + @Test + void addressExample() { + String schemaData = "{\r\n" + + " \"$id\": \"https://example.com/address.schema.json\",\r\n" + + " \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\r\n" + + " \"description\": \"An address similar to http://microformats.org/wiki/h-card\",\r\n" + + " \"type\": \"object\",\r\n" + + " \"properties\": {\r\n" + + " \"postOfficeBox\": {\r\n" + + " \"type\": \"string\"\r\n" + + " },\r\n" + + " \"extendedAddress\": {\r\n" + + " \"type\": \"string\"\r\n" + + " },\r\n" + + " \"streetAddress\": {\r\n" + + " \"type\": \"string\"\r\n" + + " },\r\n" + + " \"locality\": {\r\n" + + " \"type\": \"string\"\r\n" + + " },\r\n" + + " \"region\": {\r\n" + + " \"type\": \"string\"\r\n" + + " },\r\n" + + " \"postalCode\": {\r\n" + + " \"type\": \"string\"\r\n" + + " },\r\n" + + " \"countryName\": {\r\n" + + " \"type\": \"string\"\r\n" + + " }\r\n" + + " },\r\n" + + " \"required\": [ \"locality\", \"region\", \"countryName\" ],\r\n" + + " \"dependentRequired\": {\r\n" + + " \"postOfficeBox\": [ \"streetAddress\" ],\r\n" + + " \"extendedAddress\": [ \"streetAddress\" ]\r\n" + + " }\r\n" + + "}\r\n" + + "\r\n" + + ""; + String instanceData = "{\r\n" + + " \"postOfficeBox\": \"123\",\r\n" + + " \"streetAddress\": \"456 Main St\",\r\n" + + " \"locality\": \"Cityville\",\r\n" + + " \"region\": \"State\",\r\n" + + " \"postalCode\": \"12345\",\r\n" + + " \"countryName\": \"Country\"\r\n" + + "}"; + Map schemas = new HashMap<>(); + schemas.put("https://example.com/address.schema.json", schemaData); + SchemaRegistry schemaRegistry = SchemaRegistry.withDialect(Dialects.getDraft202012(), + builder -> builder.schemas(schemas)); + Schema schema = schemaRegistry.getSchema(SchemaLocation.of("https://example.com/address.schema.json")); + List errors = schema.validate(instanceData, InputFormat.JSON); + assertEquals(0, errors.size()); + + String invalidInstanceData = "{\r\n" + + " \"postOfficeBox\": \"123\",\r\n" + + " \"streetAddress\": \"456 Main St\",\r\n" + + " \"region\": \"State\",\r\n" + + " \"postalCode\": \"12345\",\r\n" + + " \"countryName\": \"Country\"\r\n" + + "}"; + errors = schema.validate(invalidInstanceData, InputFormat.JSON); + assertEquals(1, errors.size()); + assertEquals("required", errors.get(0).getKeyword()); + } + + @Test + void schemaFromSchemaLocationMapping() { + SchemaRegistry schemaRegistry = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12, + builder -> builder.schemaIdResolvers(schemaIdResolvers -> schemaIdResolvers + .mapPrefix("https://www.example.com/schema", "classpath:schema"))); + /* + * This should be cached for performance. + */ + Schema schemaFromSchemaLocation = schemaRegistry + .getSchema(SchemaLocation.of("https://www.example.com/schema/example-ref.json")); + /* + * By default all schemas are preloaded eagerly but ref resolve failures are not + * thrown. You check if there are issues with ref resolving using + * initializeValidators() + */ + schemaFromSchemaLocation.initializeValidators(); + List errors = schemaFromSchemaLocation.validate("{\"id\": \"2\"}", InputFormat.JSON, + executionContext -> executionContext + .executionConfig(executionConfig -> executionConfig.formatAssertionsEnabled(true))); + assertEquals(1, errors.size()); + } + + @Test + void schemaFromSchemaLocationContent() { + String schemaData = "{\"enum\":[1, 2, 3, 4]}"; + + SchemaRegistry schemaRegistry = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12, + builder -> builder.schemas( + Collections.singletonMap("https://www.example.com/schema/example-ref.json", schemaData))); + /* + * This should be cached for performance. + */ + Schema schemaFromSchemaLocation = schemaRegistry + .getSchema(SchemaLocation.of("https://www.example.com/schema/example-ref.json")); + /* + * By default all schemas are preloaded eagerly but ref resolve failures are not + * thrown. You check if there are issues with ref resolving using + * initializeValidators() + */ + schemaFromSchemaLocation.initializeValidators(); + List errors = schemaFromSchemaLocation.validate("{\"id\": \"2\"}", InputFormat.JSON, + executionContext -> executionContext + .executionConfig(executionConfig -> executionConfig.formatAssertionsEnabled(true))); + assertEquals(1, errors.size()); + } + + @Test + void schemaFromClasspath() { + SchemaRegistry schemaRegistry = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12); + /* + * This should be cached for performance. + * + * Loading from using the retrieval IRI is not recommended as it may cause + * confusing when resolving relative $ref when $id is also used. + */ + Schema schemaFromClasspath = schemaRegistry.getSchema(SchemaLocation.of("classpath:schema/example-ref.json")); + /* + * By default all schemas are preloaded eagerly but ref resolve failures are not + * thrown. You check if there are issues with ref resolving using + * initializeValidators() + */ + schemaFromClasspath.initializeValidators(); + List errors = schemaFromClasspath.validate("{\"id\": \"2\"}", InputFormat.JSON, + executionContext -> executionContext + .executionConfig(executionConfig -> executionConfig.formatAssertionsEnabled(true))); + assertEquals(1, errors.size()); + } + + @Test + void schemaFromString() { + SchemaRegistry schemaRegistry = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12); + /* + * This should be cached for performance. + * + * Loading from a String is not recommended as there is no base IRI to use for + * resolving relative $ref. + */ + Schema schemaFromString = schemaRegistry.getSchema("{\"enum\":[1, 2, 3, 4]}"); + List errors = schemaFromString.validate("7", InputFormat.JSON, executionContext -> executionContext + .executionConfig(executionConfig -> executionConfig.formatAssertionsEnabled(true))); + assertEquals(1, errors.size()); + } + + @Test + void schemaFromJsonNode() throws JsonProcessingException { + SchemaRegistry schemaRegistry = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12); + JsonNode schemaNode = JsonMapperFactory.getInstance().readTree( + "{\"$schema\": \"http://json-schema.org/draft-06/schema#\", \"properties\": { \"id\": {\"type\": \"number\"}}}"); + /* + * This should be cached for performance. + * + * Loading from a JsonNode is not recommended as there is no base IRI to use for + * resolving relative $ref. + * + * Note that the V202012 from the schemaRegistry is the default version if $schema is + * not specified. As $schema is specified in the data, V6 is used. + */ + Schema schemaFromNode = schemaRegistry.getSchema(schemaNode); + /* + * By default all schemas are preloaded eagerly but ref resolve failures are not + * thrown. You check if there are issues with ref resolving using + * initializeValidators() + */ + schemaFromNode.initializeValidators(); + List errors = schemaFromNode.validate("{\"id\": \"2\"}", InputFormat.JSON, + executionContext -> executionContext + .executionConfig(executionConfig -> executionConfig.formatAssertionsEnabled(true))); + assertEquals(1, errors.size()); + } +} diff --git a/src/test/java/com/networknt/schema/ReadOnlyValidatorTest.java b/src/test/java/com/networknt/schema/ReadOnlyValidatorTest.java index dc2ba4c0d..f9fab9dbb 100644 --- a/src/test/java/com/networknt/schema/ReadOnlyValidatorTest.java +++ b/src/test/java/com/networknt/schema/ReadOnlyValidatorTest.java @@ -19,36 +19,32 @@ class ReadOnlyValidatorTest { @Test void givenConfigWriteFalseWhenReadOnlyTrueThenAllows() throws IOException { ObjectNode node = getJsonNode(); - List errors = loadJsonSchema(false).validate(node); + List errors = loadJsonSchema().validate(node, executionContext -> executionContext + .executionConfig(executionConfig -> executionConfig.readOnly(false))); assertTrue(errors.isEmpty()); } @Test void givenConfigWriteTrueWhenReadOnlyTrueThenDenies() throws IOException { ObjectNode node = getJsonNode(); - List errors = loadJsonSchema(true).validate(node); + List errors = loadJsonSchema().validate(node, executionContext -> executionContext + .executionConfig(executionConfig -> executionConfig.readOnly(true))); assertFalse(errors.isEmpty()); assertEquals("/firstName: is a readonly field, it cannot be changed", - errors.stream().map(e -> e.getMessage()).collect(Collectors.toList()).get(0)); + errors.stream().map(e -> e.toString()).collect(Collectors.toList()).get(0)); } - private JsonSchema loadJsonSchema(Boolean write) { - JsonSchema schema = this.getJsonSchema(write); + private Schema loadJsonSchema() { + Schema schema = this.getJsonSchema(); schema.initializeValidators(); return schema; } - private JsonSchema getJsonSchema(Boolean write) { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V202012); - SchemaValidatorsConfig schemaConfig = createSchemaConfig(write); + private Schema getJsonSchema() { + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12); InputStream schema = getClass().getClassLoader().getResourceAsStream("schema/read-only-schema.json"); - return factory.getSchema(schema, schemaConfig); - } - - private SchemaValidatorsConfig createSchemaConfig(Boolean write) { - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().readOnly(write).build(); - return config; + return factory.getSchema(schema); } private ObjectNode getJsonNode() throws IOException { diff --git a/src/test/java/com/networknt/schema/RecursiveReferenceValidatorExceptionTest.java b/src/test/java/com/networknt/schema/RecursiveReferenceValidatorExceptionTest.java index 1159a57ab..d4f9d373a 100644 --- a/src/test/java/com/networknt/schema/RecursiveReferenceValidatorExceptionTest.java +++ b/src/test/java/com/networknt/schema/RecursiveReferenceValidatorExceptionTest.java @@ -1,6 +1,10 @@ package com.networknt.schema; import com.fasterxml.jackson.databind.JsonNode; +import com.networknt.schema.keyword.RecursiveRefValidator; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.path.PathType; + import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -19,15 +23,15 @@ class RecursiveReferenceValidatorExceptionTest extends AbstractJsonSchemaTestSui void testInvalidRecursiveReference() { // Arrange String invalidSchemaJson = "{ \"$recursiveRef\": \"invalid\" }"; - JsonSchemaFactory jsonSchemaFactory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V202012); - JsonSchema jsonSchema = jsonSchemaFactory.getSchema(invalidSchemaJson); + SchemaRegistry jsonSchemaFactory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12); + Schema jsonSchema = jsonSchemaFactory.getSchema(invalidSchemaJson); JsonNode schemaNode = jsonSchema.getSchemaNode(); - ValidationContext validationContext = new ValidationContext(jsonSchema.getValidationContext().getMetaSchema(), - jsonSchemaFactory, null); + SchemaContext schemaContext = new SchemaContext(jsonSchema.getSchemaContext().getDialect(), + jsonSchemaFactory); // Act and Assert - assertThrows(JsonSchemaException.class, () -> { - new RecursiveRefValidator(SchemaLocation.of(""), new JsonNodePath(PathType.JSON_POINTER), schemaNode, null, validationContext); + assertThrows(SchemaException.class, () -> { + new RecursiveRefValidator(SchemaLocation.of(""), new NodePath(PathType.JSON_POINTER), schemaNode, null, schemaContext); }); } diff --git a/src/test/java/com/networknt/schema/RefTest.java b/src/test/java/com/networknt/schema/RefTest.java index 6ad35635e..ddba8bf53 100644 --- a/src/test/java/com/networknt/schema/RefTest.java +++ b/src/test/java/com/networknt/schema/RefTest.java @@ -9,15 +9,15 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.json.JsonMapper; +import com.networknt.schema.dialect.DialectId; class RefTest { private static final ObjectMapper OBJECT_MAPPER = JsonMapper.builder().build(); @Test void shouldLoadRelativeClasspathReference() throws JsonProcessingException { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V202012); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema schema = factory.getSchema(SchemaLocation.of("classpath:///schema/ref-main.json"), config); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12); + Schema schema = factory.getSchema(SchemaLocation.of("classpath:///schema/ref-main.json")); String input = "{\r\n" + " \"DriverProperties\": {\r\n" + " \"CommonProperties\": {\r\n" @@ -25,10 +25,10 @@ void shouldLoadRelativeClasspathReference() throws JsonProcessingException { + " }\r\n" + " }\r\n" + "}"; - assertEquals(SchemaId.V4, schema.getValidationContext().getMetaSchema().getIri()); - List errors = schema.validate(OBJECT_MAPPER.readTree(input)); + assertEquals(DialectId.DRAFT_4, schema.getSchemaContext().getDialect().getId()); + List errors = schema.validate(OBJECT_MAPPER.readTree(input)); assertEquals(1, errors.size()); - ValidationMessage error = errors.iterator().next(); + Error error = errors.iterator().next(); assertEquals("classpath:///schema/ref-ref.json#/definitions/DriverProperties/required", error.getSchemaLocation().toString()); assertEquals("/properties/DriverProperties/properties/CommonProperties/$ref/required", @@ -38,9 +38,8 @@ void shouldLoadRelativeClasspathReference() throws JsonProcessingException { @Test void shouldLoadSchemaResource() throws JsonProcessingException { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V202012); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema schema = factory.getSchema(SchemaLocation.of("classpath:///schema/ref-main-schema-resource.json"), config); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12); + Schema schema = factory.getSchema(SchemaLocation.of("classpath:///schema/ref-main-schema-resource.json")); String input = "{\r\n" + " \"DriverProperties\": {\r\n" + " \"CommonProperties\": {\r\n" @@ -48,19 +47,19 @@ void shouldLoadSchemaResource() throws JsonProcessingException { + " }\r\n" + " }\r\n" + "}"; - assertEquals(SchemaId.V4, schema.getValidationContext().getMetaSchema().getIri()); - List errors = schema.validate(OBJECT_MAPPER.readTree(input)); + assertEquals(DialectId.DRAFT_4, schema.getSchemaContext().getDialect().getId()); + List errors = schema.validate(OBJECT_MAPPER.readTree(input)); assertEquals(1, errors.size()); - ValidationMessage error = errors.iterator().next(); + Error error = errors.iterator().next(); assertEquals("https://www.example.org/common#/definitions/DriverProperties/required", error.getSchemaLocation().toString()); assertEquals("/properties/DriverProperties/properties/CommonProperties/$ref/required", error.getEvaluationPath().toString()); assertEquals("field1", error.getProperty()); - JsonSchema driver = schema.getValidationContext().getSchemaResources().get("https://www.example.org/driver#"); - JsonSchema common = schema.getValidationContext().getSchemaResources().get("https://www.example.org/common#"); - assertEquals(SchemaId.V4, driver.getValidationContext().getMetaSchema().getIri()); - assertEquals(SchemaId.V7, common.getValidationContext().getMetaSchema().getIri()); + Schema driver = schema.getSchemaContext().getSchemaResources().get("https://www.example.org/driver#"); + Schema common = schema.getSchemaContext().getSchemaResources().get("https://www.example.org/common#"); + assertEquals(DialectId.DRAFT_4, driver.getSchemaContext().getDialect().getId()); + assertEquals(DialectId.DRAFT_7, common.getSchemaContext().getDialect().getId()); } } diff --git a/src/test/java/com/networknt/schema/RefValidatorTest.java b/src/test/java/com/networknt/schema/RefValidatorTest.java index 6f15bd19f..fff84afa8 100644 --- a/src/test/java/com/networknt/schema/RefValidatorTest.java +++ b/src/test/java/com/networknt/schema/RefValidatorTest.java @@ -23,8 +23,6 @@ import org.junit.jupiter.api.Test; -import com.networknt.schema.SpecVersion.VersionFlag; - /** * Tests for RefValidator. */ @@ -40,11 +38,11 @@ void resolveSamePathDotSlash() { + " \"type\": \"integer\"\r\n" + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012, - builder -> builder.schemaLoaders(schemaLoaders -> schemaLoaders.schemas( + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12, + builder -> builder.resourceLoaders(resourceLoaders -> resourceLoaders.resources( Collections.singletonMap("https://www.example.com/schema/integer.json", otherSchema)))); - JsonSchema jsonSchema = factory.getSchema(mainSchema); - List messages = jsonSchema.validate("\"string\"", InputFormat.JSON); + Schema jsonSchema = factory.getSchema(mainSchema); + List messages = jsonSchema.validate("\"string\"", InputFormat.JSON); assertEquals(1, messages.size()); } @@ -59,11 +57,11 @@ void resolveSamePath() { + " \"type\": \"integer\"\r\n" + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012, - builder -> builder.schemaLoaders(schemaLoaders -> schemaLoaders.schemas( + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12, + builder -> builder.resourceLoaders(resourceLoaders -> resourceLoaders.resources( Collections.singletonMap("https://www.example.com/schema/integer.json", otherSchema)))); - JsonSchema jsonSchema = factory.getSchema(mainSchema); - List messages = jsonSchema.validate("\"string\"", InputFormat.JSON); + Schema jsonSchema = factory.getSchema(mainSchema); + List messages = jsonSchema.validate("\"string\"", InputFormat.JSON); assertEquals(1, messages.size()); } @@ -78,11 +76,11 @@ void resolveParent() { + " \"type\": \"integer\"\r\n" + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012, - builder -> builder.schemaLoaders(schemaLoaders -> schemaLoaders.schemas( + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12, + builder -> builder.resourceLoaders(resourceLoaders -> resourceLoaders.resources( Collections.singletonMap("https://www.example.com/integer.json", otherSchema)))); - JsonSchema jsonSchema = factory.getSchema(mainSchema); - List messages = jsonSchema.validate("\"string\"", InputFormat.JSON); + Schema jsonSchema = factory.getSchema(mainSchema); + List messages = jsonSchema.validate("\"string\"", InputFormat.JSON); assertEquals(1, messages.size()); } @@ -97,18 +95,18 @@ void resolveComplex() { + " \"type\": \"integer\"\r\n" + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012, - builder -> builder.schemaLoaders(schemaLoaders -> schemaLoaders.schemas( + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12, + builder -> builder.resourceLoaders(resourceLoaders -> resourceLoaders.resources( Collections.singletonMap("https://www.example.com/schema/hello/integer.json", otherSchema)))); - JsonSchema jsonSchema = factory.getSchema(mainSchema); - List messages = jsonSchema.validate("\"string\"", InputFormat.JSON); + Schema jsonSchema = factory.getSchema(mainSchema); + List messages = jsonSchema.validate("\"string\"", InputFormat.JSON); assertEquals(1, messages.size()); } @Test void classPathSlash() { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V201909); - JsonSchema schema = factory.getSchema(SchemaLocation.of("classpath:/schema/main/main.json")); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2019_09); + Schema schema = factory.getSchema(SchemaLocation.of("classpath:/schema/main/main.json")); String inputData = "{\r\n" + " \"fields\": {\r\n" + " \"ids\": {\r\n" @@ -123,8 +121,8 @@ void classPathSlash() { @Test void classPathNoSlash() { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V201909); - JsonSchema schema = factory.getSchema(SchemaLocation.of("classpath:schema/main/main.json")); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2019_09); + Schema schema = factory.getSchema(SchemaLocation.of("classpath:schema/main/main.json")); String inputData = "{\r\n" + " \"fields\": {\r\n" + " \"ids\": {\r\n" diff --git a/src/test/java/com/networknt/schema/RequiredValidatorTest.java b/src/test/java/com/networknt/schema/RequiredValidatorTest.java index 599b87831..ba542c46f 100644 --- a/src/test/java/com/networknt/schema/RequiredValidatorTest.java +++ b/src/test/java/com/networknt/schema/RequiredValidatorTest.java @@ -22,8 +22,6 @@ import org.junit.jupiter.api.Test; -import com.networknt.schema.SpecVersion.VersionFlag; - /** * RequiredValidatorTest. */ @@ -55,16 +53,17 @@ void validateRequestRequiredReadOnlyShouldBeIgnored() { + " \"name\"\r\n" + " ]\r\n" + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().readOnly(true).build(); - JsonSchema schema = factory.getSchema(schemaData, config); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12); + Schema schema = factory.getSchema(schemaData); String inputData = "{\r\n" + " \"foo\":\"hello\",\r\n" + " \"bar\":\"world\"\r\n" + "}"; - List messages = new ArrayList<>(schema.validate(inputData, InputFormat.JSON)); + List messages = new ArrayList<>( + schema.validate(inputData, InputFormat.JSON, executionContext -> executionContext + .executionConfig(executionConfig -> executionConfig.readOnly(true)))); assertEquals(messages.size(), 2); - ValidationMessage message = messages.get(0); + Error message = messages.get(0); assertEquals("/required", message.getEvaluationPath().toString()); assertEquals("amount", message.getProperty()); message = messages.get(1); @@ -99,16 +98,17 @@ void validateResponseRequiredWriteOnlyShouldBeIgnored() { + " \"name\"\r\n" + " ]\r\n" + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().writeOnly(true).build(); - JsonSchema schema = factory.getSchema(schemaData, config); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12); + Schema schema = factory.getSchema(schemaData); String inputData = "{\r\n" + " \"foo\":\"hello\",\r\n" + " \"bar\":\"world\"\r\n" + "}"; - List messages = new ArrayList<>(schema.validate(inputData, InputFormat.JSON)); + List messages = new ArrayList<>( + schema.validate(inputData, InputFormat.JSON, executionContext -> executionContext + .executionConfig(executionConfig -> executionConfig.writeOnly(true)))); assertEquals(messages.size(), 2); - ValidationMessage message = messages.get(0); + Error message = messages.get(0); assertEquals("/required", message.getEvaluationPath().toString()); assertEquals("description", message.getProperty()); message = messages.get(1); @@ -143,14 +143,15 @@ void validateRequestRequired() { + " \"name\"\r\n" + " ]\r\n" + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().readOnly(true).build(); - JsonSchema schema = factory.getSchema(schemaData, config); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12); + Schema schema = factory.getSchema(schemaData); String inputData = "{\r\n" + " \"amount\":10,\r\n" + " \"description\":\"world\"\r\n" + "}"; - List messages = new ArrayList<>(schema.validate(inputData, InputFormat.JSON)); + List messages = new ArrayList<>( + schema.validate(inputData, InputFormat.JSON, executionContext -> executionContext + .executionConfig(executionConfig -> executionConfig.readOnly(true)))); assertEquals(messages.size(), 0); } @@ -181,14 +182,15 @@ void validateResponseRequired() { + " \"name\"\r\n" + " ]\r\n" + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().writeOnly(true).build(); - JsonSchema schema = factory.getSchema(schemaData, config); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12); + Schema schema = factory.getSchema(schemaData); String inputData = "{\r\n" + " \"description\":\"world\",\r\n" + " \"name\":\"hello\"\r\n" + "}"; - List messages = new ArrayList<>(schema.validate(inputData, InputFormat.JSON)); + List messages = new ArrayList<>( + schema.validate(inputData, InputFormat.JSON, executionContext -> executionContext + .executionConfig(executionConfig -> executionConfig.writeOnly(true)))); assertEquals(messages.size(), 0); } } diff --git a/src/test/java/com/networknt/schema/SampleTest.java b/src/test/java/com/networknt/schema/SampleTest.java deleted file mode 100644 index 650008220..000000000 --- a/src/test/java/com/networknt/schema/SampleTest.java +++ /dev/null @@ -1,124 +0,0 @@ -package com.networknt.schema; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import java.util.Collections; -import java.util.List; - -import org.junit.jupiter.api.Test; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.networknt.schema.SpecVersion.VersionFlag; -import com.networknt.schema.serialization.JsonMapperFactory; - -/** - * Sample test. - */ -class SampleTest { - @Test - void schemaFromSchemaLocationMapping() { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012, builder -> builder.schemaMappers( - schemaMappers -> schemaMappers.mapPrefix("https://www.example.com/schema", "classpath:schema"))); - /* - * This should be cached for performance. - */ - JsonSchema schemaFromSchemaLocation = factory - .getSchema(SchemaLocation.of("https://www.example.com/schema/example-ref.json")); - /* - * By default all schemas are preloaded eagerly but ref resolve failures are not - * thrown. You check if there are issues with ref resolving using - * initializeValidators() - */ - schemaFromSchemaLocation.initializeValidators(); - List errors = schemaFromSchemaLocation.validate("{\"id\": \"2\"}", InputFormat.JSON, - executionContext -> executionContext.getExecutionConfig().setFormatAssertionsEnabled(true)); - assertEquals(1, errors.size()); - } - - @Test - void schemaFromSchemaLocationContent() { - String schemaData = "{\"enum\":[1, 2, 3, 4]}"; - - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012, - builder -> builder.schemaLoaders(schemaLoaders -> schemaLoaders.schemas( - Collections.singletonMap("https://www.example.com/schema/example-ref.json", schemaData)))); - /* - * This should be cached for performance. - */ - JsonSchema schemaFromSchemaLocation = factory - .getSchema(SchemaLocation.of("https://www.example.com/schema/example-ref.json")); - /* - * By default all schemas are preloaded eagerly but ref resolve failures are not - * thrown. You check if there are issues with ref resolving using - * initializeValidators() - */ - schemaFromSchemaLocation.initializeValidators(); - List errors = schemaFromSchemaLocation.validate("{\"id\": \"2\"}", InputFormat.JSON, - executionContext -> executionContext.getExecutionConfig().setFormatAssertionsEnabled(true)); - assertEquals(1, errors.size()); - } - - @Test - void schemaFromClasspath() { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - /* - * This should be cached for performance. - * - * Loading from using the retrieval IRI is not recommended as it may cause - * confusing when resolving relative $ref when $id is also used. - */ - JsonSchema schemaFromClasspath = factory.getSchema(SchemaLocation.of("classpath:schema/example-ref.json")); - /* - * By default all schemas are preloaded eagerly but ref resolve failures are not - * thrown. You check if there are issues with ref resolving using - * initializeValidators() - */ - schemaFromClasspath.initializeValidators(); - List errors = schemaFromClasspath.validate("{\"id\": \"2\"}", InputFormat.JSON, - executionContext -> executionContext.getExecutionConfig().setFormatAssertionsEnabled(true)); - assertEquals(1, errors.size()); - } - - @Test - void schemaFromString() { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - /* - * This should be cached for performance. - * - * Loading from a String is not recommended as there is no base IRI to use for - * resolving relative $ref. - */ - JsonSchema schemaFromString = factory - .getSchema("{\"enum\":[1, 2, 3, 4]}"); - List errors = schemaFromString.validate("7", InputFormat.JSON, - executionContext -> executionContext.getExecutionConfig().setFormatAssertionsEnabled(true)); - assertEquals(1, errors.size()); - } - - @Test - void schemaFromJsonNode() throws JsonProcessingException { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - JsonNode schemaNode = JsonMapperFactory.getInstance().readTree( - "{\"$schema\": \"http://json-schema.org/draft-06/schema#\", \"properties\": { \"id\": {\"type\": \"number\"}}}"); - /* - * This should be cached for performance. - * - * Loading from a JsonNode is not recommended as there is no base IRI to use for - * resolving relative $ref. - * - * Note that the V202012 from the factory is the default version if $schema is not - * specified. As $schema is specified in the data, V6 is used. - */ - JsonSchema schemaFromNode = factory.getSchema(schemaNode); - /* - * By default all schemas are preloaded eagerly but ref resolve failures are not - * thrown. You check if there are issues with ref resolving using - * initializeValidators() - */ - schemaFromNode.initializeValidators(); - List errors = schemaFromNode.validate("{\"id\": \"2\"}", InputFormat.JSON, - executionContext -> executionContext.getExecutionConfig().setFormatAssertionsEnabled(true)); - assertEquals(1, errors.size()); - } -} diff --git a/src/test/java/com/networknt/schema/SchemaLocationTest.java b/src/test/java/com/networknt/schema/SchemaLocationTest.java index f8663039b..fc14ce2e2 100644 --- a/src/test/java/com/networknt/schema/SchemaLocationTest.java +++ b/src/test/java/com/networknt/schema/SchemaLocationTest.java @@ -21,7 +21,7 @@ import org.junit.jupiter.api.Test; -import com.networknt.schema.SpecVersion.VersionFlag; +import com.networknt.schema.path.NodePath; class SchemaLocationTest { @@ -217,10 +217,10 @@ void documentFragment() { @Test void shouldLoadEscapedFragment() { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - JsonSchema schema = factory.getSchema(SchemaLocation + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12); + Schema schema = factory.getSchema(SchemaLocation .of("classpath:schema/example-escaped.yaml#/paths/~1users/post/requestBody/application~1json/schema")); - List result = schema.validate("1", InputFormat.JSON); + List result = schema.validate("1", InputFormat.JSON); assertFalse(result.isEmpty()); result = schema.validate("{}", InputFormat.JSON); assertTrue(result.isEmpty()); @@ -228,7 +228,7 @@ void shouldLoadEscapedFragment() { @Test void escapedJsonPointerFragment() { - JsonNodePath fragment = SchemaLocation.Fragment.of("/paths/~1users/post/requestBody/application~1json/schema"); + NodePath fragment = SchemaLocation.Fragment.of("/paths/~1users/post/requestBody/application~1json/schema"); assertEquals("/paths/~1users/post/requestBody/application~1json/schema", fragment.toString()); assertEquals(6, fragment.getNameCount()); assertEquals("paths", fragment.getName(0)); diff --git a/src/test/java/com/networknt/schema/JsonSchemaFactoryTest.java b/src/test/java/com/networknt/schema/SchemaRegistryTest.java similarity index 81% rename from src/test/java/com/networknt/schema/JsonSchemaFactoryTest.java rename to src/test/java/com/networknt/schema/SchemaRegistryTest.java index 956352fef..4a569eb47 100644 --- a/src/test/java/com/networknt/schema/JsonSchemaFactoryTest.java +++ b/src/test/java/com/networknt/schema/SchemaRegistryTest.java @@ -25,12 +25,12 @@ import org.junit.jupiter.api.Test; -import com.networknt.schema.SpecVersion.VersionFlag; +import com.networknt.schema.dialect.Dialect; /** * Tests for JsonSchemaFactory. */ -class JsonSchemaFactoryTest { +class SchemaRegistryTest { @Test void concurrency() { String metaSchemaData = "{\r\n" @@ -46,29 +46,28 @@ void concurrency() { + " { \"$ref\": \"https://json-schema.org/draft/2020-12/meta/core\" }\r\n" + " ]\r\n" + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012, builder -> builder.schemaLoaders(schemaLoaders -> schemaLoaders.schemas(Collections + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12, builder -> builder.resourceLoaders(resourceLoaders -> resourceLoaders.resources(Collections .singletonMap("https://www.example.com/no-validation-no-format/schema", metaSchemaData)))); AtomicBoolean failed = new AtomicBoolean(false); - JsonMetaSchema[] instance = new JsonMetaSchema[1]; + Dialect[] instance = new Dialect[1]; CountDownLatch latch = new CountDownLatch(1); List threads = new ArrayList<>(); for (int i = 0; i < 50; ++i) { Runnable runner = new Runnable() { public void run() { - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); try { latch.await(); } catch (InterruptedException e) { throw new RuntimeException(e); } - JsonMetaSchema metaSchema = factory.getMetaSchema("https://www.example.com/no-validation-no-format/schema", config); + Dialect dialect = factory.getDialect("https://www.example.com/no-validation-no-format/schema"); synchronized(instance) { if (instance[0] == null) { - instance[0] = metaSchema; + instance[0] = dialect; } // Ensure references are the same despite concurrency - if (!(instance[0] == metaSchema)) { + if (!(instance[0] == dialect)) { failed.set(true); } } diff --git a/src/test/java/com/networknt/schema/JsonSchemaTest.java b/src/test/java/com/networknt/schema/SchemaTest.java similarity index 82% rename from src/test/java/com/networknt/schema/JsonSchemaTest.java rename to src/test/java/com/networknt/schema/SchemaTest.java index 0f76ac1f6..ff1ac400b 100644 --- a/src/test/java/com/networknt/schema/JsonSchemaTest.java +++ b/src/test/java/com/networknt/schema/SchemaTest.java @@ -25,12 +25,10 @@ import org.junit.jupiter.api.Test; -import com.networknt.schema.SpecVersion.VersionFlag; - /** * Tests for JsonSchemaFactory. */ -class JsonSchemaTest { +class SchemaTest { @Test void concurrency() throws Exception { String schemaData = "{\r\n" @@ -55,11 +53,12 @@ void concurrency() throws Exception { String inputData = "{\r\n" + " \"name\": 1\r\n" + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012, - builder -> builder.schemaLoaders(schemaLoaders -> schemaLoaders - .schemas(Collections.singletonMap("http://example.org/ref.json", refSchemaData)))); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().preloadJsonSchema(false).build(); - JsonSchema schema = factory.getSchema(schemaData, config); + SchemaRegistryConfig config = SchemaRegistryConfig.builder().preloadSchema(false).build(); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12, + builder -> builder.schemaRegistryConfig(config) + .resourceLoaders(resourceLoaders -> resourceLoaders + .resources(Collections.singletonMap("http://example.org/ref.json", refSchemaData)))); + Schema schema = factory.getSchema(schemaData); Exception[] instance = new Exception[1]; CountDownLatch latch = new CountDownLatch(1); List threads = new ArrayList<>(); @@ -72,7 +71,7 @@ public void run() { throw new RuntimeException(e); } try { - List messages = schema.validate(inputData, InputFormat.JSON) + List messages = schema.validate(inputData, InputFormat.JSON) .stream() .collect(Collectors.toList()); assertEquals(1, messages.size()); diff --git a/src/test/java/com/networknt/schema/SchemaValidatorsConfigTest.java b/src/test/java/com/networknt/schema/SchemaValidatorsConfigTest.java deleted file mode 100644 index fcfa31304..000000000 --- a/src/test/java/com/networknt/schema/SchemaValidatorsConfigTest.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (c) 2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.networknt.schema; - -import static org.junit.jupiter.api.Assertions.*; - -import org.junit.jupiter.api.Test; - -import com.networknt.schema.regex.ECMAScriptRegularExpressionFactory; -import com.networknt.schema.regex.JDKRegularExpressionFactory; - -/** - * Test for SchemaValidatorsConfig. - */ -@SuppressWarnings("deprecation") -class SchemaValidatorsConfigTest { - @Test - void defaultEcma262Validator() { - SchemaValidatorsConfig config = new SchemaValidatorsConfig(); - assertSame(JDKRegularExpressionFactory.getInstance(), config.getRegularExpressionFactory()); - assertFalse(config.isEcma262Validator()); - } - - @Test - void setEcma262Validator() { - SchemaValidatorsConfig config = new SchemaValidatorsConfig(); - - config.setEcma262Validator(true); - assertSame(ECMAScriptRegularExpressionFactory.getInstance(), config.getRegularExpressionFactory()); - assertTrue(config.isEcma262Validator()); - - config.setEcma262Validator(false); - assertSame(JDKRegularExpressionFactory.getInstance(), config.getRegularExpressionFactory()); - assertFalse(config.isEcma262Validator()); - } - - @Test - void constructorPathType() { - SchemaValidatorsConfig config = new SchemaValidatorsConfig(); - assertEquals(PathType.LEGACY, config.getPathType()); - } - - @Test - void builderPathType() { - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - assertEquals(PathType.JSON_POINTER, config.getPathType()); - } - - @Test - void constructorCustomMessageSupported() { - SchemaValidatorsConfig config = new SchemaValidatorsConfig(); - assertEquals(true, config.isCustomMessageSupported()); - } - - @Test - void builderCustomMessageSupported() { - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - assertEquals(false, config.isCustomMessageSupported()); - } - - @Test - void constructorHandleNullableField() { - SchemaValidatorsConfig config = new SchemaValidatorsConfig(); - assertEquals(true, config.isHandleNullableField()); - } - - @Test - void builderHandleNullableField() { - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - assertEquals(false, config.isHandleNullableField()); - } - - @Test - void constructorMutable() { - SchemaValidatorsConfig config = new SchemaValidatorsConfig(); - assertDoesNotThrow(() -> config.setFailFast(true)); - } - - @Test - void builderImmutable() { - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - assertThrows(UnsupportedOperationException.class, () -> config.setFailFast(true)); - } -} diff --git a/src/test/java/com/networknt/schema/SelfRefTest.java b/src/test/java/com/networknt/schema/SelfRefTest.java index 5c328f77a..75ae08d9e 100644 --- a/src/test/java/com/networknt/schema/SelfRefTest.java +++ b/src/test/java/com/networknt/schema/SelfRefTest.java @@ -26,7 +26,7 @@ class SelfRefTest extends BaseJsonSchemaValidatorTest { @Disabled("This test currently is failing because of a StackOverflow caused by a recursive $ref.") @Test() void testSelfRef() throws Exception { - JsonSchema node = getJsonSchemaFromClasspath("selfRef.json"); + Schema node = getJsonSchemaFromClasspath("selfRef.json"); System.out.println("node = " + node); } } \ No newline at end of file diff --git a/src/test/java/com/networknt/schema/SharedConfigTest.java b/src/test/java/com/networknt/schema/SharedConfigTest.java index a7f469006..edd62b88d 100644 --- a/src/test/java/com/networknt/schema/SharedConfigTest.java +++ b/src/test/java/com/networknt/schema/SharedConfigTest.java @@ -6,7 +6,9 @@ import org.junit.jupiter.api.Test; import com.fasterxml.jackson.databind.ObjectMapper; -import com.networknt.schema.walk.JsonSchemaWalkListener; +import com.networknt.schema.walk.WalkListener; +import com.networknt.schema.walk.KeywordWalkListenerRunner; +import com.networknt.schema.walk.WalkConfig; import com.networknt.schema.walk.WalkEvent; import com.networknt.schema.walk.WalkFlow; @@ -14,7 +16,7 @@ * Issue 918. */ class SharedConfigTest { - private static class AllKeywordListener implements JsonSchemaWalkListener { + private static class AllKeywordListener implements WalkListener { boolean wasCalled = false; @Override @@ -24,31 +26,33 @@ public WalkFlow onWalkStart(WalkEvent walkEvent) { } @Override - public void onWalkEnd(WalkEvent walkEvent, List validationMessages) { + public void onWalkEnd(WalkEvent walkEvent, List errors) { } } @Test void shouldCallAllKeywordListenerOnWalkStart() throws Exception { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7); AllKeywordListener allKeywordListener = new AllKeywordListener(); - SchemaValidatorsConfig schemaValidatorsConfig = SchemaValidatorsConfig.builder() - .keywordWalkListener(allKeywordListener) - .build(); + KeywordWalkListenerRunner keywordWalkListenerRunner = KeywordWalkListenerRunner.builder() + .keywordWalkListener(allKeywordListener).build(); + WalkConfig walkConfig = WalkConfig.builder().keywordWalkListenerRunner(keywordWalkListenerRunner).build(); + + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7); SchemaLocation draft07Schema = SchemaLocation.of("resource:/draft-07/schema#"); // depending on this line the test either passes or fails: // - if this line is executed, then it passes // - if this line is not executed (just comment it) - it fails - JsonSchema firstSchema = factory.getSchema(draft07Schema); + Schema firstSchema = factory.getSchema(draft07Schema); firstSchema.walk(new ObjectMapper().readTree("{ \"id\": 123 }"), true); // note that only second schema takes overridden schemaValidatorsConfig - JsonSchema secondSchema = factory.getSchema(draft07Schema, schemaValidatorsConfig); + Schema secondSchema = factory.getSchema(draft07Schema); - secondSchema.walk(new ObjectMapper().readTree("{ \"id\": 123 }"), true); + secondSchema.walk(new ObjectMapper().readTree("{ \"id\": 123 }"), true, + executionContext -> executionContext.setWalkConfig(walkConfig)); Assertions.assertTrue(allKeywordListener.wasCalled); } } \ No newline at end of file diff --git a/src/main/java/com/networknt/schema/SpecVersionDetector.java b/src/test/java/com/networknt/schema/SpecificationVersionDetector.java similarity index 64% rename from src/main/java/com/networknt/schema/SpecVersionDetector.java rename to src/test/java/com/networknt/schema/SpecificationVersionDetector.java index 219a2866b..73c89678f 100644 --- a/src/main/java/com/networknt/schema/SpecVersionDetector.java +++ b/src/test/java/com/networknt/schema/SpecificationVersionDetector.java @@ -17,7 +17,6 @@ package com.networknt.schema; import com.fasterxml.jackson.databind.JsonNode; -import com.networknt.schema.SpecVersion.VersionFlag; import java.nio.file.Path; import java.util.HashMap; @@ -33,33 +32,33 @@ * @author Subhajitdas298 * @since 25/06/20 */ -public final class SpecVersionDetector { +public final class SpecificationVersionDetector { - private static final Map supportedVersions = new HashMap<>(); + private static final Map supportedVersions = new HashMap<>(); private static final String SCHEMA_TAG = "$schema"; static { - supportedVersions.put("draft2019-09", VersionFlag.V201909); - supportedVersions.put("draft2020-12", VersionFlag.V202012); - supportedVersions.put("draft4", VersionFlag.V4); - supportedVersions.put("draft6", VersionFlag.V6); - supportedVersions.put("draft7", VersionFlag.V7); + supportedVersions.put("draft2019-09", SpecificationVersion.DRAFT_2019_09); + supportedVersions.put("draft2020-12", SpecificationVersion.DRAFT_2020_12); + supportedVersions.put("draft4", SpecificationVersion.DRAFT_4); + supportedVersions.put("draft6", SpecificationVersion.DRAFT_6); + supportedVersions.put("draft7", SpecificationVersion.DRAFT_7); } - private SpecVersionDetector() { + private SpecificationVersionDetector() { // Prevent instantiation of this utility class } /** * Detects schema version based on the schema tag: if the schema tag is not present, throws - * {@link JsonSchemaException} with the corresponding message, otherwise - returns the detected spec version. + * {@link SchemaException} with the corresponding message, otherwise - returns the detected spec version. * * @param jsonNode JSON Node to read from * @return Spec version if present, otherwise throws an exception */ - public static VersionFlag detect(JsonNode jsonNode) { + public static SpecificationVersion detect(JsonNode jsonNode) { return detectOptionalVersion(jsonNode, true).orElseThrow( - () -> new JsonSchemaException("'" + SCHEMA_TAG + "' tag is not present") + () -> new SchemaException("'" + SCHEMA_TAG + "' tag is not present") ); } @@ -71,17 +70,17 @@ public static VersionFlag detect(JsonNode jsonNode) { * @param throwIfUnsupported whether to throw an exception if the version is not supported * @return Spec version if present, otherwise empty */ - public static Optional detectOptionalVersion(JsonNode jsonNode, boolean throwIfUnsupported) { + public static Optional detectOptionalVersion(JsonNode jsonNode, boolean throwIfUnsupported) { return Optional.ofNullable(jsonNode.get(SCHEMA_TAG)).map(schemaTag -> { String schemaTagValue = schemaTag.asText(); - String schemaUri = JsonSchemaFactory.normalizeMetaSchemaUri(schemaTagValue); + String schemaUri = SchemaRegistry.normalizeDialectId(schemaTagValue); if (throwIfUnsupported) { - return VersionFlag.fromId(schemaUri) - .orElseThrow(() -> new JsonSchemaException("'" + schemaTagValue + "' is unrecognizable schema")); + return SpecificationVersion.fromDialectId(schemaUri) + .orElseThrow(() -> new SchemaException("'" + schemaTagValue + "' is unrecognizable schema")); } else { - return VersionFlag.fromId(schemaUri).orElse(null); + return SpecificationVersion.fromDialectId(schemaUri).orElse(null); } }); } @@ -89,7 +88,7 @@ public static Optional detectOptionalVersion(JsonNode jsonNode, boo // For 2019-09 and later published drafts, implementations that are able to // detect the draft of each schema via $schema SHOULD be configured to do so - public static VersionFlag detectVersion(JsonNode jsonNode, Path specification, VersionFlag defaultVersion, boolean throwIfUnsupported) { + public static SpecificationVersion detectVersion(JsonNode jsonNode, Path specification, SpecificationVersion defaultVersion, boolean throwIfUnsupported) { return Stream.of( detectOptionalVersion(jsonNode, throwIfUnsupported), detectVersionFromPath(specification) @@ -103,16 +102,11 @@ public static VersionFlag detectVersion(JsonNode jsonNode, Path specification, V // For draft-07 and earlier, draft-next, and implementations unable to // detect via $schema, implementations MUST be configured to expect the // draft matching the test directory name - public static Optional detectVersionFromPath(Path path) { + public static Optional detectVersionFromPath(Path path) { return StreamSupport.stream(path.spliterator(), false) .map(Path::toString) - .map(supportedVersions::get) + .map(supportedVersions::get) .filter(Objects::nonNull) .findAny(); } - - public static Optional detectOptionalVersion(String schemaUri) { - return VersionFlag.fromId(schemaUri); - } - } diff --git a/src/test/java/com/networknt/schema/SpecVersionDetectorTest.java b/src/test/java/com/networknt/schema/SpecificationVersionDetectorTest.java similarity index 72% rename from src/test/java/com/networknt/schema/SpecVersionDetectorTest.java rename to src/test/java/com/networknt/schema/SpecificationVersionDetectorTest.java index 2c7804242..2fbdd6324 100644 --- a/src/test/java/com/networknt/schema/SpecVersionDetectorTest.java +++ b/src/test/java/com/networknt/schema/SpecificationVersionDetectorTest.java @@ -13,23 +13,23 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; -class SpecVersionDetectorTest { +class SpecificationVersionDetectorTest { private static final ObjectMapper mapper = new ObjectMapper(); @ParameterizedTest @CsvSource({ - "draft4, V4", - "draft6, V6", - "draft7, V7", - "draft2019-09, V201909", - "draft2020-12, V202012" + "draft4, DRAFT_4", + "draft6, DRAFT_6", + "draft7, DRAFT_7", + "draft2019-09, DRAFT_2019_09", + "draft2020-12, DRAFT_2020_12" }) - void detectVersion(String resourceDirectory, SpecVersion.VersionFlag expectedFlag) throws IOException { + void detectVersion(String resourceDirectory, SpecificationVersion expectedFlag) throws IOException { InputStream in = Thread.currentThread().getContextClassLoader() .getResourceAsStream(resourceDirectory + "/schemaTag.json"); JsonNode node = mapper.readTree(in); - SpecVersion.VersionFlag flag = SpecVersionDetector.detect(node); + SpecificationVersion flag = SpecificationVersionDetector.detect(node); assertEquals(expectedFlag, flag); } @@ -41,7 +41,7 @@ void detectVersion(String resourceDirectory, SpecVersion.VersionFlag expectedFla void detectInvalidSchemaVersion(String schemaPath, String expectedError) throws IOException { InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(schemaPath); JsonNode node = mapper.readTree(in); - JsonSchemaException exception = assertThrows(JsonSchemaException.class, () -> SpecVersionDetector.detect(node)); + SchemaException exception = assertThrows(SchemaException.class, () -> SpecificationVersionDetector.detect(node)); assertEquals(expectedError, exception.getMessage()); } @@ -50,7 +50,7 @@ void detectOptionalSpecVersion() throws IOException { InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream( "data/schemaTagMissing.json"); JsonNode node = mapper.readTree(in); - Optional flag = SpecVersionDetector.detectOptionalVersion(node, true); + Optional flag = SpecificationVersionDetector.detectOptionalVersion(node, true); assertEquals(Optional.empty(), flag); } } diff --git a/src/test/java/com/networknt/schema/TypeFactoryTest.java b/src/test/java/com/networknt/schema/TypeFactoryTest.java index 90d410412..b25a9a6f3 100755 --- a/src/test/java/com/networknt/schema/TypeFactoryTest.java +++ b/src/test/java/com/networknt/schema/TypeFactoryTest.java @@ -16,8 +16,8 @@ package com.networknt.schema; -import static com.networknt.schema.TypeFactory.getSchemaNodeType; -import static com.networknt.schema.TypeFactory.getValueNodeType; +import static com.networknt.schema.utils.TypeFactory.getSchemaNodeType; +import static com.networknt.schema.utils.TypeFactory.getValueNodeType; import static org.junit.jupiter.api.Assertions.assertSame; import java.math.BigDecimal; @@ -29,6 +29,7 @@ import com.fasterxml.jackson.databind.node.MissingNode; import com.fasterxml.jackson.databind.node.TextNode; import com.networknt.schema.serialization.JsonMapperFactory; +import com.networknt.schema.utils.JsonType; /** * Test for TypeFactory. @@ -43,7 +44,7 @@ class TypeFactoryTest { @Test void testIntegralValuesWithJavaSemantics() { - SchemaValidatorsConfig schemaValidatorsConfig = SchemaValidatorsConfig.builder().javaSemantics(true).build(); + SchemaRegistryConfig schemaValidatorsConfig = SchemaRegistryConfig.builder().javaSemantics(true).build(); for (String validValue : validIntegralValues) { assertSame(JsonType.INTEGER, getValueNodeType(DecimalNode.valueOf(new BigDecimal(validValue)), schemaValidatorsConfig), @@ -58,7 +59,7 @@ void testIntegralValuesWithJavaSemantics() { @Test void testIntegralValuesWithoutJavaSemantics() { - SchemaValidatorsConfig schemaValidatorsConfig = SchemaValidatorsConfig.builder().javaSemantics(false).build(); + SchemaRegistryConfig schemaValidatorsConfig = SchemaRegistryConfig.builder().javaSemantics(false).build(); for (String validValue : validIntegralValues) { assertSame(JsonType.NUMBER, getValueNodeType(DecimalNode.valueOf(new BigDecimal(validValue)), schemaValidatorsConfig), @@ -73,7 +74,7 @@ void testIntegralValuesWithoutJavaSemantics() { @Test void testWithLosslessNarrowing() { - SchemaValidatorsConfig schemaValidatorsConfig = SchemaValidatorsConfig.builder().losslessNarrowing(true).build(); + SchemaRegistryConfig schemaValidatorsConfig = SchemaRegistryConfig.builder().losslessNarrowing(true).build(); for (String validValue : validIntegralValues) { assertSame(JsonType.INTEGER, getValueNodeType(DecimalNode.valueOf(new BigDecimal("1.0")), schemaValidatorsConfig), validValue); @@ -85,7 +86,7 @@ void testWithLosslessNarrowing() { @Test void testWithoutLosslessNarrowing() { - SchemaValidatorsConfig schemaValidatorsConfig = SchemaValidatorsConfig.builder().losslessNarrowing(false).build(); + SchemaRegistryConfig schemaValidatorsConfig = SchemaRegistryConfig.builder().losslessNarrowing(false).build(); for (String validValue : validIntegralValues) { assertSame(JsonType.NUMBER, getValueNodeType(DecimalNode.valueOf(new BigDecimal("1.0")), schemaValidatorsConfig), validValue); @@ -99,44 +100,44 @@ void testWithoutLosslessNarrowing() { @Test void testObjectValue() { assertSame(JsonType.OBJECT, getValueNodeType(JsonMapperFactory.getInstance().getNodeFactory().objectNode(), - SchemaValidatorsConfig.builder().build())); + SchemaRegistryConfig.builder().build())); } @Test void testArrayValue() { assertSame(JsonType.ARRAY, - getValueNodeType(JsonMapperFactory.getInstance().getNodeFactory().arrayNode(), SchemaValidatorsConfig.builder().build())); + getValueNodeType(JsonMapperFactory.getInstance().getNodeFactory().arrayNode(), SchemaRegistryConfig.builder().build())); } @Test void testBooleanValue() { assertSame(JsonType.BOOLEAN, getValueNodeType( - JsonMapperFactory.getInstance().getNodeFactory().booleanNode(true), SchemaValidatorsConfig.builder().build())); + JsonMapperFactory.getInstance().getNodeFactory().booleanNode(true), SchemaRegistryConfig.builder().build())); } @Test void testNullValue() { assertSame(JsonType.NULL, - getValueNodeType(JsonMapperFactory.getInstance().getNodeFactory().nullNode(), SchemaValidatorsConfig.builder().build())); + getValueNodeType(JsonMapperFactory.getInstance().getNodeFactory().nullNode(), SchemaRegistryConfig.builder().build())); } @Test void testMissingValue() { assertSame(JsonType.UNKNOWN, getValueNodeType(JsonMapperFactory.getInstance().getNodeFactory().missingNode(), - SchemaValidatorsConfig.builder().build())); + SchemaRegistryConfig.builder().build())); } @Test void testIntegerValue() { assertSame(JsonType.INTEGER, getValueNodeType(JsonMapperFactory.getInstance().getNodeFactory().numberNode(10), - SchemaValidatorsConfig.builder().build())); + SchemaRegistryConfig.builder().build())); } @Test void testBinaryValue() { assertSame(JsonType.STRING, getValueNodeType( JsonMapperFactory.getInstance().getNodeFactory().binaryNode("test".getBytes(StandardCharsets.UTF_8)), - SchemaValidatorsConfig.builder().build())); + SchemaRegistryConfig.builder().build())); } @Test diff --git a/src/test/java/com/networknt/schema/TypeValidatorTest.java b/src/test/java/com/networknt/schema/TypeValidatorTest.java index d7f642e13..7c2feb91d 100644 --- a/src/test/java/com/networknt/schema/TypeValidatorTest.java +++ b/src/test/java/com/networknt/schema/TypeValidatorTest.java @@ -22,8 +22,6 @@ import org.junit.jupiter.api.Test; -import com.networknt.schema.SpecVersion.VersionFlag; - /** * Test TypeValidator validator. */ @@ -52,8 +50,8 @@ class TypeValidatorTest { @Test void testTypeLoose() { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); - JsonSchema schema = factory.getSchema(schemaData); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12); + Schema schema = factory.getSchema(schemaData); String inputData = "{\r\n" + " \"array_of_integers\": 1,\r\n" @@ -68,18 +66,19 @@ void testTypeLoose() { + " \"array_of_objects\": {}\r\n" + "}"; // Without type loose this has 2 type errors - List messages = schema.validate(inputData, InputFormat.JSON); + List messages = schema.validate(inputData, InputFormat.JSON); assertEquals(2, messages.size()); - assertEquals(2, messages.stream().filter(m -> "type".equals(m.getType())).count()); + assertEquals(2, messages.stream().filter(m -> "type".equals(m.getKeyword())).count()); // 1 type error in array_of_integers messages = schema.validate(validTypeLooseInputData, InputFormat.JSON); assertEquals(1, messages.size()); - assertEquals(1, messages.stream().filter(m -> "type".equals(m.getType())).count()); + assertEquals(1, messages.stream().filter(m -> "type".equals(m.getKeyword())).count()); // With type loose this has 0 type errors as any item can also be interpreted as an array of 1 item - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().typeLoose(true).build(); - JsonSchema typeLoose = factory.getSchema(schemaData, config); + SchemaRegistryConfig config = SchemaRegistryConfig.builder().typeLoose(true).build(); + factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12, builder -> builder.schemaRegistryConfig(config)); + Schema typeLoose = factory.getSchema(schemaData); messages = typeLoose.validate(inputData, InputFormat.JSON); assertEquals(0, messages.size()); @@ -101,8 +100,8 @@ void integer() { String schemaData = "{\r\n" + " \"type\": \"integer\"\r\n" + "}"; - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData); - List messages = schema.validate("1", InputFormat.JSON); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12).getSchema(schemaData); + List messages = schema.validate("1", InputFormat.JSON); assertEquals(0, messages.size()); messages = schema.validate("2.0", InputFormat.JSON); assertEquals(0, messages.size()); @@ -130,8 +129,8 @@ void integerDraft4() { String schemaData = "{\r\n" + " \"type\": \"integer\"\r\n" + "}"; - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V4).getSchema(schemaData); - List messages = schema.validate("1", InputFormat.JSON); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_4).getSchema(schemaData); + List messages = schema.validate("1", InputFormat.JSON); assertEquals(0, messages.size()); // The logic in JsonNodeUtil specifically excludes V4 from this handling messages = schema.validate("2.0", InputFormat.JSON); @@ -145,9 +144,9 @@ void walkNull() { String schemaData = "{\r\n" + " \"type\": \"integer\"\r\n" + "}"; - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V4).getSchema(schemaData); - ValidationResult result = schema.walk(null, true); - assertTrue(result.getValidationMessages().isEmpty()); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_4).getSchema(schemaData); + Result result = schema.walk(null, true); + assertTrue(result.getErrors().isEmpty()); } @Test @@ -173,12 +172,11 @@ void nullable() { + " \"nested\":null\r\n" + " }\r\n" + "}"; - final JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V7); - final JsonSchema validator = factory.getSchema(schemaData, SchemaValidatorsConfig.builder() - .nullableKeywordEnabled(false) - .build()); + // nullable keyword enabled false + final SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7); + final Schema validator = factory.getSchema(schemaData); - final List errors = validator.validate(inputData, InputFormat.JSON); + final List errors = validator.validate(inputData, InputFormat.JSON); assertEquals(1, errors.size()); } } diff --git a/src/test/java/com/networknt/schema/UnevaluatedItemsTest.java b/src/test/java/com/networknt/schema/UnevaluatedItemsTest.java index 765440666..fb6d8b1a3 100644 --- a/src/test/java/com/networknt/schema/UnevaluatedItemsTest.java +++ b/src/test/java/com/networknt/schema/UnevaluatedItemsTest.java @@ -1,6 +1,5 @@ package com.networknt.schema; -import com.networknt.schema.SpecVersion.VersionFlag; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.DynamicNode; import org.junit.jupiter.api.TestFactory; @@ -13,7 +12,7 @@ class UnevaluatedItemsTest extends AbstractJsonSchemaTestSuite { @TestFactory @DisplayName("Draft 2019-09") Stream draft201909() { - return createTests(VersionFlag.V201909, "src/test/resources/schema/unevaluatedTests/unevaluated-items-tests.json"); + return createTests(SpecificationVersion.DRAFT_2019_09, "src/test/resources/schema/unevaluatedTests/unevaluated-items-tests.json"); } } diff --git a/src/test/java/com/networknt/schema/UnevaluatedItemsValidatorTest.java b/src/test/java/com/networknt/schema/UnevaluatedItemsValidatorTest.java index bfad6228e..159a2925d 100644 --- a/src/test/java/com/networknt/schema/UnevaluatedItemsValidatorTest.java +++ b/src/test/java/com/networknt/schema/UnevaluatedItemsValidatorTest.java @@ -23,8 +23,6 @@ import org.junit.jupiter.api.Test; -import com.networknt.schema.SpecVersion.VersionFlag; - /** * UnevaluatedItemsValidatorTest. */ @@ -43,16 +41,16 @@ void unevaluatedItemsFalse() { + " \"unevaluatedItems\" : false\r\n" + "}"; String inputData = "[1,2,3]"; - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData); - List messages = schema.validate(inputData, InputFormat.JSON); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12).getSchema(schemaData); + List messages = schema.validate(inputData, InputFormat.JSON); assertEquals(2, messages.size()); - List assertions = messages.stream().collect(Collectors.toList()); - assertEquals("unevaluatedItems", assertions.get(0).getType()); - assertEquals("$", assertions.get(0).getInstanceLocation().toString()); - assertEquals("$.unevaluatedItems", assertions.get(0).getEvaluationPath().toString()); - assertEquals("unevaluatedItems", assertions.get(1).getType()); - assertEquals("$", assertions.get(1).getInstanceLocation().toString()); - assertEquals("$.unevaluatedItems", assertions.get(1).getEvaluationPath().toString()); + List assertions = messages.stream().collect(Collectors.toList()); + assertEquals("unevaluatedItems", assertions.get(0).getKeyword()); + assertEquals("", assertions.get(0).getInstanceLocation().toString()); + assertEquals("/unevaluatedItems", assertions.get(0).getEvaluationPath().toString()); + assertEquals("unevaluatedItems", assertions.get(1).getKeyword()); + assertEquals("", assertions.get(1).getInstanceLocation().toString()); + assertEquals("/unevaluatedItems", assertions.get(1).getEvaluationPath().toString()); } @Test @@ -69,15 +67,15 @@ void unevaluatedItemsSchema() { + " \"unevaluatedItems\" : { \"type\" : \"string\" }\r\n" + "}"; String inputData = "[1,2,3]"; - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData); - List messages = schema.validate(inputData, InputFormat.JSON); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12).getSchema(schemaData); + List messages = schema.validate(inputData, InputFormat.JSON); assertEquals(2, messages.size()); - List assertions = messages.stream().collect(Collectors.toList()); - assertEquals("type", assertions.get(0).getType()); - assertEquals("$[1]", assertions.get(0).getInstanceLocation().toString()); - assertEquals("$.unevaluatedItems.type", assertions.get(0).getEvaluationPath().toString()); - assertEquals("type", assertions.get(1).getType()); - assertEquals("$[2]", assertions.get(1).getInstanceLocation().toString()); - assertEquals("$.unevaluatedItems.type", assertions.get(1).getEvaluationPath().toString()); + List assertions = messages.stream().collect(Collectors.toList()); + assertEquals("type", assertions.get(0).getKeyword()); + assertEquals("/1", assertions.get(0).getInstanceLocation().toString()); + assertEquals("/unevaluatedItems/type", assertions.get(0).getEvaluationPath().toString()); + assertEquals("type", assertions.get(1).getKeyword()); + assertEquals("/2", assertions.get(1).getInstanceLocation().toString()); + assertEquals("/unevaluatedItems/type", assertions.get(1).getEvaluationPath().toString()); } } diff --git a/src/test/java/com/networknt/schema/UnevaluatedPropertiesTest.java b/src/test/java/com/networknt/schema/UnevaluatedPropertiesTest.java index 61cf70426..767f59f78 100644 --- a/src/test/java/com/networknt/schema/UnevaluatedPropertiesTest.java +++ b/src/test/java/com/networknt/schema/UnevaluatedPropertiesTest.java @@ -1,7 +1,5 @@ package com.networknt.schema; -import com.networknt.schema.SpecVersion.VersionFlag; - import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.DynamicNode; import org.junit.jupiter.api.TestFactory; @@ -14,7 +12,7 @@ class UnevaluatedPropertiesTest extends AbstractJsonSchemaTestSuite { @TestFactory @DisplayName("Draft 2019-09") Stream draft201909() { - return createTests(VersionFlag.V201909, "src/test/resources/schema/unevaluatedTests/unevaluated-tests.json"); + return createTests(SpecificationVersion.DRAFT_2019_09, "src/test/resources/schema/unevaluatedTests/unevaluated-tests.json"); } } diff --git a/src/test/java/com/networknt/schema/UnevaluatedPropertiesValidatorTest.java b/src/test/java/com/networknt/schema/UnevaluatedPropertiesValidatorTest.java index 5e7ec489d..25b4a59b8 100644 --- a/src/test/java/com/networknt/schema/UnevaluatedPropertiesValidatorTest.java +++ b/src/test/java/com/networknt/schema/UnevaluatedPropertiesValidatorTest.java @@ -26,7 +26,6 @@ import org.junit.jupiter.api.Test; -import com.networknt.schema.SpecVersion.VersionFlag; import com.networknt.schema.output.OutputUnit; /** @@ -61,13 +60,13 @@ void annotationsOnlyDroppedAtTheEndOfSchemaProcessing() { + " \"key3\": \"value3\",\r\n" + " \"key4\": \"value4\"\r\n" + "}"; - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData); - List messages = schema.validate(inputData, InputFormat.JSON); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12).getSchema(schemaData); + List messages = schema.validate(inputData, InputFormat.JSON); assertEquals(2, messages.size()); - List assertions = messages.stream().collect(Collectors.toList()); - assertEquals("required", assertions.get(0).getType()); + List assertions = messages.stream().collect(Collectors.toList()); + assertEquals("required", assertions.get(0).getKeyword()); assertEquals("key1", assertions.get(0).getProperty()); - assertEquals("unevaluatedProperties", assertions.get(1).getType()); + assertEquals("unevaluatedProperties", assertions.get(1).getKeyword()); assertEquals("key4", assertions.get(1).getProperty()); } @@ -116,11 +115,11 @@ void subschemaProcessing() { + " \"notallowed\": false\r\n" + " }\r\n" + "}"; - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V201909).getSchema(schemaData); - List messages = schema.validate(inputData, InputFormat.JSON); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2019_09).getSchema(schemaData); + List messages = schema.validate(inputData, InputFormat.JSON); assertEquals(1, messages.size()); - List assertions = messages.stream().collect(Collectors.toList()); - assertEquals("additionalProperties", assertions.get(0).getType()); + List assertions = messages.stream().collect(Collectors.toList()); + assertEquals("additionalProperties", assertions.get(0).getKeyword()); assertEquals("notallowed", assertions.get(0).getProperty()); } @@ -144,12 +143,12 @@ void unevaluatedPropertiesSchema() { + " \"notallowed\": false\r\n" + " }\r\n" + "}"; - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V201909).getSchema(schemaData); - List messages = schema.validate(inputData, InputFormat.JSON); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2019_09).getSchema(schemaData); + List messages = schema.validate(inputData, InputFormat.JSON); assertEquals(1, messages.size()); - List assertions = messages.stream().collect(Collectors.toList()); - assertEquals("type", assertions.get(0).getType()); - assertEquals("$.unevaluatedProperties.type", assertions.get(0).getEvaluationPath().toString()); + List assertions = messages.stream().collect(Collectors.toList()); + assertEquals("type", assertions.get(0).getKeyword()); + assertEquals("/unevaluatedProperties/type", assertions.get(0).getEvaluationPath().toString()); } @Test @@ -189,8 +188,8 @@ void ref() { + " \"unevaluatedProperties\": false\r\n" + "}"; String inputData = "{ \"pontoons\": {}, \"wheels\": {}, \"surfboard\": \"2\" }"; - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V201909).getSchema(schemaData); - List messages = schema.validate(inputData, InputFormat.JSON); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2019_09).getSchema(schemaData); + List messages = schema.validate(inputData, InputFormat.JSON); assertEquals(0, messages.size()); } @@ -227,16 +226,16 @@ void nestedRef() { Map schemas = new HashMap<>(); schemas.put("https://www.example.org/PrimaryDeviceConfiguration.json", primaryDeviceConfiguration); schemas.put("https://www.example.org/DeviceConfiguration.json", deviceConfiguration); - JsonSchema schema = JsonSchemaFactory - .getInstance(VersionFlag.V201909, - builder -> builder.schemaLoaders(schemaLoaders -> schemaLoaders.schemas(schemas))) + Schema schema = SchemaRegistry + .withDefaultDialect(SpecificationVersion.DRAFT_2019_09, + builder -> builder.resourceLoaders(resourceLoaders -> resourceLoaders.resources(schemas))) .getSchema(schemaData); String inputData = "{ \"isPrimaryDevice\": true, \"roleName\": \"hello\" }"; OutputUnit outputUnit = schema.validate(inputData, InputFormat.JSON, OutputFormat.HIERARCHICAL, executionContext -> { - executionContext.getExecutionConfig().setAnnotationCollectionEnabled(false); - executionContext.getExecutionConfig().setAnnotationCollectionFilter(keyword -> true); - }); + executionContext.executionConfig(executionConfig -> executionConfig + .annotationCollectionEnabled(false).annotationCollectionFilter(keyword -> true)); + }); assertTrue(outputUnit.isValid()); } } diff --git a/src/test/java/com/networknt/schema/UnknownKeywordFactoryTest.java b/src/test/java/com/networknt/schema/UnknownKeywordFactoryTest.java index bbcee921e..8f00ea7c0 100644 --- a/src/test/java/com/networknt/schema/UnknownKeywordFactoryTest.java +++ b/src/test/java/com/networknt/schema/UnknownKeywordFactoryTest.java @@ -19,6 +19,10 @@ import org.junit.jupiter.api.Test; +import com.networknt.schema.keyword.AnnotationKeyword; +import com.networknt.schema.keyword.Keyword; +import com.networknt.schema.keyword.UnknownKeywordFactory; + class UnknownKeywordFactoryTest { @Test diff --git a/src/test/java/com/networknt/schema/UnknownMetaSchemaTest.java b/src/test/java/com/networknt/schema/UnknownMetaSchemaTest.java index dc4688053..0b21409a2 100644 --- a/src/test/java/com/networknt/schema/UnknownMetaSchemaTest.java +++ b/src/test/java/com/networknt/schema/UnknownMetaSchemaTest.java @@ -2,6 +2,8 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import com.networknt.schema.dialect.DialectId; + import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -21,11 +23,11 @@ void testSchema1() throws IOException { ObjectMapper mapper = new ObjectMapper(); JsonNode jsonNode = mapper.readTree(this.json); - JsonSchemaFactory factory = JsonSchemaFactory.builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7)).build(); - JsonSchema jsonSchema = factory.getSchema(schema1); + SchemaRegistry factory = SchemaRegistry.builder(SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7)).build(); + Schema jsonSchema = factory.getSchema(schema1); - List errors = jsonSchema.validate(jsonNode); - for(ValidationMessage error:errors) { + List errors = jsonSchema.validate(jsonNode); + for(Error error:errors) { System.out.println(error.getMessage()); } } @@ -35,11 +37,11 @@ void testSchema2() throws IOException { ObjectMapper mapper = new ObjectMapper(); JsonNode jsonNode = mapper.readTree(this.json); - JsonSchemaFactory factory = JsonSchemaFactory.builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7)).build(); - JsonSchema jsonSchema = factory.getSchema(schema2); + SchemaRegistry factory = SchemaRegistry.builder(SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7)).build(); + Schema jsonSchema = factory.getSchema(schema2); - List errors = jsonSchema.validate(jsonNode); - for(ValidationMessage error:errors) { + List errors = jsonSchema.validate(jsonNode); + for(Error error:errors) { System.out.println(error.getMessage()); } } @@ -48,28 +50,28 @@ void testSchema3() throws IOException { ObjectMapper mapper = new ObjectMapper(); JsonNode jsonNode = mapper.readTree(this.json); - JsonSchemaFactory factory = JsonSchemaFactory.builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7)).build(); - JsonSchema jsonSchema = factory.getSchema(schema3); + SchemaRegistry factory = SchemaRegistry.builder(SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7)).build(); + Schema jsonSchema = factory.getSchema(schema3); - List errors = jsonSchema.validate(jsonNode); - for(ValidationMessage error:errors) { + List errors = jsonSchema.validate(jsonNode); + for(Error error:errors) { System.out.println(error.getMessage()); } } @Test - void testNormalize() throws JsonSchemaException { + void testNormalize() throws SchemaException { String uri01 = "http://json-schema.org/draft-07/schema"; String uri02 = "http://json-schema.org/draft-07/schema#"; String uri03 = "http://json-schema.org/draft-07/schema?key=value"; String uri04 = "http://json-schema.org/draft-07/schema?key=value&key2=value2"; - String expected = SchemaId.V7; + String expected = DialectId.DRAFT_7; - Assertions.assertEquals(expected, JsonSchemaFactory.normalizeMetaSchemaUri(uri01)); - Assertions.assertEquals(expected, JsonSchemaFactory.normalizeMetaSchemaUri(uri02)); - Assertions.assertEquals(expected, JsonSchemaFactory.normalizeMetaSchemaUri(uri03)); - Assertions.assertEquals(expected, JsonSchemaFactory.normalizeMetaSchemaUri(uri04)); + Assertions.assertEquals(expected, SchemaRegistry.normalizeDialectId(uri01)); + Assertions.assertEquals(expected, SchemaRegistry.normalizeDialectId(uri02)); + Assertions.assertEquals(expected, SchemaRegistry.normalizeDialectId(uri03)); + Assertions.assertEquals(expected, SchemaRegistry.normalizeDialectId(uri04)); } } diff --git a/src/test/java/com/networknt/schema/UriMappingTest.java b/src/test/java/com/networknt/schema/UriMappingTest.java index 030c1f4cd..47821235d 100644 --- a/src/test/java/com/networknt/schema/UriMappingTest.java +++ b/src/test/java/com/networknt/schema/UriMappingTest.java @@ -28,11 +28,14 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.networknt.schema.JsonSchemaFactory.Builder; +import com.networknt.schema.SchemaRegistry.Builder; +import com.networknt.schema.dialect.BasicDialectRegistry; +import com.networknt.schema.dialect.Dialect; +import com.networknt.schema.dialect.Dialects; import com.networknt.schema.resource.InputStreamSource; -import com.networknt.schema.resource.MapSchemaMapper; -import com.networknt.schema.resource.SchemaLoader; -import com.networknt.schema.resource.SchemaMapper; +import com.networknt.schema.resource.MapSchemaIdResolver; +import com.networknt.schema.resource.ResourceLoader; +import com.networknt.schema.resource.SchemaIdResolver; class UriMappingTest { @@ -47,13 +50,13 @@ class UriMappingTest { @Test void testBuilderUriMappingUri() throws IOException { URL mappings = UriMappingTest.class.getResource("/uri_mapping/uri-mapping.json"); - JsonMetaSchema draftV4 = JsonMetaSchema.getV4(); - Builder builder = JsonSchemaFactory.builder() - .defaultMetaSchemaIri(draftV4.getIri()) - .metaSchema(draftV4) - .schemaMappers(schemaMappers -> schemaMappers.add(getUriMappingsFromUrl(mappings))); - JsonSchemaFactory instance = builder.build(); - JsonSchema schema = instance.getSchema(SchemaLocation.of( + Dialect draftV4 = Dialects.getDraft4(); + Builder builder = SchemaRegistry.builder() + .defaultDialectId(draftV4.getId()) + .dialectRegistry(new BasicDialectRegistry(draftV4)) + .schemaIdResolvers(schemaIdResolvers -> schemaIdResolvers.add(getUriMappingsFromUrl(mappings))); + SchemaRegistry instance = builder.build(); + Schema schema = instance.getSchema(SchemaLocation.of( "https://raw.githubusercontent.com/networknt/json-schema-validator/master/src/test/resources/draft4/extra/uri_mapping/uri-mapping.schema.json")); assertEquals(0, schema.validate(mapper.readTree(mappings)).size()); } @@ -68,9 +71,9 @@ void testBuilderUriMappingUri() throws IOException { */ @Test void testBuilderExampleMappings() throws IOException { - SchemaLoader schemaLoader = new SchemaLoader() { + ResourceLoader schemaLoader = new ResourceLoader() { @Override - public InputStreamSource getSchema(AbsoluteIri absoluteIri) { + public InputStreamSource getResource(AbsoluteIri absoluteIri) { String iri = absoluteIri.toString(); if ("https://example.com/invalid/schema/url".equals(iri)) { return () -> { @@ -80,15 +83,15 @@ public InputStreamSource getSchema(AbsoluteIri absoluteIri) { return null; } }; - JsonSchemaFactory instance = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V4, - builder -> builder.schemaLoaders(schemaLoaders -> schemaLoaders.add(schemaLoader))); + SchemaRegistry instance = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_4, + builder -> builder.resourceLoaders(resourceLoaders -> resourceLoaders.add(schemaLoader))); SchemaLocation example = SchemaLocation.of("https://example.com/invalid/schema/url"); // first test that attempting to use example URL throws an error try { - JsonSchema schema = instance.getSchema(example); + Schema schema = instance.getSchema(example); schema.validate(mapper.createObjectNode()); fail("Expected exception not thrown"); - } catch (JsonSchemaException ex) { + } catch (SchemaException ex) { Throwable cause = ex.getCause(); if (!(cause instanceof IOException )) { fail("Unexpected cause for JsonSchemaException", ex); @@ -98,13 +101,13 @@ public InputStreamSource getSchema(AbsoluteIri absoluteIri) { fail("Unexpected exception thrown", ex); } URL mappings = UriMappingTest.class.getResource("/uri_mapping/invalid-schema-uri.json"); - JsonMetaSchema draftV4 = JsonMetaSchema.getV4(); - Builder builder = JsonSchemaFactory.builder() - .defaultMetaSchemaIri(draftV4.getIri()) - .metaSchema(draftV4) - .schemaMappers(schemaMappers -> schemaMappers.add(getUriMappingsFromUrl(mappings))); + Dialect draftV4 = Dialects.getDraft4(); + Builder builder = SchemaRegistry.builder() + .defaultDialectId(draftV4.getId()) + .dialectRegistry(new BasicDialectRegistry(draftV4)) + .schemaIdResolvers(schemaIdResolvers -> schemaIdResolvers.add(getUriMappingsFromUrl(mappings))); instance = builder.build(); - JsonSchema schema = instance.getSchema(example); + Schema schema = instance.getSchema(example); assertEquals(0, schema.validate(mapper.createObjectNode()).size()); } @@ -117,9 +120,9 @@ public InputStreamSource getSchema(AbsoluteIri absoluteIri) { @Test void testValidatorConfigUriMappingUri() throws IOException { URL mappings = UriMappingTest.class.getResource("/uri_mapping/uri-mapping.json"); - JsonSchemaFactory instance = JsonSchemaFactory.builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V4)) - .schemaMappers(schemaMappers -> schemaMappers.add(getUriMappingsFromUrl(mappings))).build(); - JsonSchema schema = instance.getSchema(SchemaLocation.of( + SchemaRegistry instance = SchemaRegistry.builder(SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_4)) + .schemaIdResolvers(schemaIdResolvers -> schemaIdResolvers.add(getUriMappingsFromUrl(mappings))).build(); + Schema schema = instance.getSchema(SchemaLocation.of( "https://raw.githubusercontent.com/networknt/json-schema-validator/master/src/test/resources/draft4/extra/uri_mapping/uri-mapping.schema.json")); assertEquals(0, schema.validate(mapper.readTree(mappings)).size()); } @@ -134,9 +137,9 @@ void testValidatorConfigUriMappingUri() throws IOException { */ @Test void testValidatorConfigExampleMappings() throws IOException { - SchemaLoader schemaLoader = new SchemaLoader() { + ResourceLoader schemaLoader = new ResourceLoader() { @Override - public InputStreamSource getSchema(AbsoluteIri absoluteIri) { + public InputStreamSource getResource(AbsoluteIri absoluteIri) { String iri = absoluteIri.toString(); if ("https://example.com/invalid/schema/url".equals(iri)) { return () -> { @@ -147,16 +150,15 @@ public InputStreamSource getSchema(AbsoluteIri absoluteIri) { } }; URL mappings = UriMappingTest.class.getResource("/uri_mapping/invalid-schema-uri.json"); - JsonSchemaFactory instance = JsonSchemaFactory.builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V4, - builder -> builder.schemaLoaders(schemaLoaders -> schemaLoaders.add(schemaLoader)))).build(); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); + SchemaRegistry instance = SchemaRegistry.builder(SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_4, + builder -> builder.resourceLoaders(resourceLoaders -> resourceLoaders.add(schemaLoader)))).build(); SchemaLocation example = SchemaLocation.of("https://example.com/invalid/schema/url"); // first test that attempting to use example URL throws an error try { - JsonSchema schema = instance.getSchema(example, config); + Schema schema = instance.getSchema(example); schema.validate(mapper.createObjectNode()); fail("Expected exception not thrown"); - } catch (JsonSchemaException ex) { + } catch (SchemaException ex) { Throwable cause = ex.getCause(); if (!(cause instanceof IOException)) { fail("Unexpected cause for JsonSchemaException"); @@ -165,24 +167,23 @@ public InputStreamSource getSchema(AbsoluteIri absoluteIri) { } catch (Exception ex) { fail("Unexpected exception thrown"); } - instance = JsonSchemaFactory.builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V4)) - .schemaMappers(schemaMappers -> schemaMappers.add(getUriMappingsFromUrl(mappings))).build(); - JsonSchema schema = instance.getSchema(example, config); + instance = SchemaRegistry.builder(SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_4)) + .schemaIdResolvers(schemaIdResolvers -> schemaIdResolvers.add(getUriMappingsFromUrl(mappings))).build(); + Schema schema = instance.getSchema(example); assertEquals(0, schema.validate(mapper.createObjectNode()).size()); } @Test void testMappingsForRef() throws IOException { URL mappings = UriMappingTest.class.getResource("/uri_mapping/schema-with-ref-mapping.json"); - JsonSchemaFactory instance = JsonSchemaFactory.builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V4)) - .schemaMappers(schemaMappers -> schemaMappers.add(getUriMappingsFromUrl(mappings))).build(); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema schema = instance.getSchema(SchemaLocation.of("resource:uri_mapping/schema-with-ref.json"), - config); + SchemaRegistry instance = SchemaRegistry.builder(SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_4)) + .schemaIdResolvers(schemaIdResolvers -> schemaIdResolvers.add(getUriMappingsFromUrl(mappings))).build(); + Schema schema = instance.getSchema(SchemaLocation.of("resource:uri_mapping/schema-with-ref.json") + ); assertEquals(0, schema.validate(mapper.readTree("[]")).size()); } - private SchemaMapper getUriMappingsFromUrl(URL url) { + private SchemaIdResolver getUriMappingsFromUrl(URL url) { HashMap map = new HashMap(); try { for (JsonNode mapping : mapper.readTree(url)) { @@ -192,6 +193,6 @@ private SchemaMapper getUriMappingsFromUrl(URL url) { } catch (IOException e) { throw new UncheckedIOException(e); } - return new MapSchemaMapper(map); + return new MapSchemaIdResolver(map); } } diff --git a/src/test/java/com/networknt/schema/UrnTest.java b/src/test/java/com/networknt/schema/UrnTest.java index dbf29283e..b60430674 100644 --- a/src/test/java/com/networknt/schema/UrnTest.java +++ b/src/test/java/com/networknt/schema/UrnTest.java @@ -1,46 +1,25 @@ package com.networknt.schema; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; import java.io.IOException; -import java.io.InputStream; -import java.net.URL; - -import static org.junit.jupiter.api.Assertions.assertEquals; -class UrnTest -{ - private final ObjectMapper mapper = new ObjectMapper(); +import org.junit.jupiter.api.Test; - /** - * Validate that a JSON URI Mapping file containing the URI Mapping schema is - * schema valid. - * - * @throws IOException if unable to parse the mapping file - */ - @Test - void testURNToURI() throws Exception { - InputStream urlTestData = UrnTest.class.getResourceAsStream("/draft7/urn/test.json"); - InputStream is = null; - try { - is = new URL("https://raw.githubusercontent.com/francesc79/json-schema-validator/feature/urn-management/src/test/resources/draft7/urn/urn.schema.json").openStream(); - JsonMetaSchema draftV7 = JsonMetaSchema.getV7(); - JsonSchemaFactory.Builder builder = JsonSchemaFactory.builder() - .defaultMetaSchemaIri(draftV7.getIri()) - .metaSchema(draftV7) - .schemaMappers(schemaMappers -> schemaMappers.add(value -> AbsoluteIri.of(String.format("resource:draft7/urn/%s.schema.json", value.toString()))) - ); - JsonSchemaFactory instance = builder.build(); - JsonSchema schema = instance.getSchema(is); - assertEquals(0, schema.validate(mapper.readTree(urlTestData)).size()); - } catch( Exception e) { - e.printStackTrace(); - } - finally { - if (is != null) { - is.close(); - } +class UrnTest { + /** + * Validate that a JSON URI Mapping file containing the URI Mapping schema is + * schema valid. + * + * @throws IOException if unable to parse the mapping file + */ + @Test + void testURNToURI() throws Exception { + SchemaRegistry schemaRegistry = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7, + builder -> builder.schemaIdResolvers(schemaIdResolvers -> schemaIdResolvers.add(value -> { + return AbsoluteIri.of(String.format("%s.schema.json", value.toString())); + }))); + Schema schema = schemaRegistry.getSchema(SchemaLocation.of("classpath:/draft7/urn/urn")); + assertEquals(0, schema.validate(AbsoluteIri.of("classpath:/draft7/urn/test.json"), InputFormat.JSON).size()); } - } } diff --git a/src/test/java/com/networknt/schema/V4JsonSchemaTest.java b/src/test/java/com/networknt/schema/V4JsonSchemaTest.java index fca017322..cb203ef8a 100644 --- a/src/test/java/com/networknt/schema/V4JsonSchemaTest.java +++ b/src/test/java/com/networknt/schema/V4JsonSchemaTest.java @@ -37,9 +37,9 @@ class V4JsonSchemaTest { void testLoadingWithId() throws Exception { try (InputStream inputStream = new FileInputStream("src/test/resources/remotes/self_ref/selfRef.json")) { JsonNode schemaJson = mapper.readTree(inputStream); - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V4); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_4); @SuppressWarnings("unused") - JsonSchema schema = factory.getSchema(schemaJson); + Schema schema = factory.getSchema(schemaJson); } } @@ -48,7 +48,7 @@ void testLoadingWithId() throws Exception { */ @Test void testFailFast_AllErrors() throws IOException { - List messages = validateFailingFastSchemaFor("extra/product/product.schema.json", + List messages = validateFailingFastSchemaFor("extra/product/product.schema.json", "extra/product/product-all-errors-data.json"); assertEquals(1, messages.size()); } @@ -58,7 +58,7 @@ void testFailFast_AllErrors() throws IOException { */ @Test void testFailFast_OneErrors() throws IOException { - List messages = validateFailingFastSchemaFor("extra/product/product.schema.json", + List messages = validateFailingFastSchemaFor("extra/product/product.schema.json", "extra/product/product-one-error-data.json"); assertEquals(1, messages.size()); } @@ -68,31 +68,29 @@ void testFailFast_OneErrors() throws IOException { */ @Test void testFailFast_TwoErrors() throws IOException { - List messages = validateFailingFastSchemaFor("extra/product/product.schema.json", + List messages = validateFailingFastSchemaFor("extra/product/product.schema.json", "extra/product/product-two-errors-data.json"); assertEquals(1, messages.size()); } /** * The file contains no errors, in ths case - * {@link Set}<{@link ValidationMessage}> must be empty + * {@link Set}<{@link Error}> must be empty */ @Test void testFailFast_NoErrors() throws IOException { - final List messages = validateFailingFastSchemaFor("extra/product/product.schema.json", + final List messages = validateFailingFastSchemaFor("extra/product/product.schema.json", "extra/product/product-no-errors-data.json"); assertTrue(messages.isEmpty()); } - private List validateFailingFastSchemaFor(final String schemaFileName, final String dataFileName) throws IOException { + private List validateFailingFastSchemaFor(final String schemaFileName, final String dataFileName) throws IOException { final ObjectMapper objectMapper = new ObjectMapper(); final JsonNode schema = getJsonNodeFromResource(objectMapper, schemaFileName); final JsonNode dataFile = getJsonNodeFromResource(objectMapper, dataFileName); - final SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().failFast(true).build(); - return JsonSchemaFactory - .builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V4)) - .build() - .getSchema(schema, config) + final SchemaRegistryConfig config = SchemaRegistryConfig.builder().failFast(true).build(); + return SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_4, builder -> builder.schemaRegistryConfig(config)) + .getSchema(schema) .validate(dataFile); } diff --git a/src/test/java/com/networknt/schema/benchmark/NetworkntBasicRunner.java b/src/test/java/com/networknt/schema/benchmark/NetworkntBasicRunner.java index 9297804f6..48c6b8f21 100644 --- a/src/test/java/com/networknt/schema/benchmark/NetworkntBasicRunner.java +++ b/src/test/java/com/networknt/schema/benchmark/NetworkntBasicRunner.java @@ -11,22 +11,22 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectReader; -import com.networknt.schema.JsonSchema; -import com.networknt.schema.JsonSchemaFactory; -import com.networknt.schema.SpecVersion.VersionFlag; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaRegistry; +import com.networknt.schema.SpecificationVersion; /** * Basic Benchmark. */ public class NetworkntBasicRunner implements Callable { private static final Logger logger = LoggerFactory.getLogger(NetworkntBasicRunner.class); - private JsonSchema jsonSchema; + private Schema jsonSchema; private JsonNode schemas; private List schemaNames; public NetworkntBasicRunner() { ObjectMapper objectMapper = new ObjectMapper(); - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V4); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_4); try { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); ObjectReader reader = objectMapper.reader(); diff --git a/src/test/java/com/networknt/schema/benchmark/NetworkntTestSuite202012OptionalPerf.java b/src/test/java/com/networknt/schema/benchmark/NetworkntTestSuite202012OptionalPerf.java index 1a2704c42..d5dee00aa 100644 --- a/src/test/java/com/networknt/schema/benchmark/NetworkntTestSuite202012OptionalPerf.java +++ b/src/test/java/com/networknt/schema/benchmark/NetworkntTestSuite202012OptionalPerf.java @@ -2,12 +2,12 @@ import java.util.concurrent.Callable; -import com.networknt.schema.SpecVersion.VersionFlag; +import com.networknt.schema.SpecificationVersion; public class NetworkntTestSuite202012OptionalPerf { public static void main(String[] args) throws Exception { Callable runner = new NetworkntTestSuiteRunner(NetworkntTestSuiteTestCases.findTestCases( - VersionFlag.V202012, "src/test/suite/tests/draft2020-12", TestCaseFilter.optionalType())); + SpecificationVersion.DRAFT_2020_12, "src/test/suite/tests/draft2020-12", TestCaseFilter.optionalType())); runner.call(); } } diff --git a/src/test/java/com/networknt/schema/benchmark/NetworkntTestSuite202012RequiredPerf.java b/src/test/java/com/networknt/schema/benchmark/NetworkntTestSuite202012RequiredPerf.java index 7935441e0..d8f8c576f 100644 --- a/src/test/java/com/networknt/schema/benchmark/NetworkntTestSuite202012RequiredPerf.java +++ b/src/test/java/com/networknt/schema/benchmark/NetworkntTestSuite202012RequiredPerf.java @@ -2,12 +2,12 @@ import java.util.concurrent.Callable; -import com.networknt.schema.SpecVersion.VersionFlag; +import com.networknt.schema.SpecificationVersion; public class NetworkntTestSuite202012RequiredPerf { public static void main(String[] args) throws Exception { Callable runner = new NetworkntTestSuiteRunner(NetworkntTestSuiteTestCases.findTestCases( - VersionFlag.V202012, "src/test/suite/tests/draft2020-12", TestCaseFilter.requiredType())); + SpecificationVersion.DRAFT_2020_12, "src/test/suite/tests/draft2020-12", TestCaseFilter.requiredType())); runner.call(); } } diff --git a/src/test/java/com/networknt/schema/benchmark/NetworkntTestSuiteOptionalBenchmark.java b/src/test/java/com/networknt/schema/benchmark/NetworkntTestSuiteOptionalBenchmark.java index 9b3e5059a..1c639e14c 100644 --- a/src/test/java/com/networknt/schema/benchmark/NetworkntTestSuiteOptionalBenchmark.java +++ b/src/test/java/com/networknt/schema/benchmark/NetworkntTestSuiteOptionalBenchmark.java @@ -18,7 +18,7 @@ import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; -import com.networknt.schema.SpecVersion.VersionFlag; +import com.networknt.schema.SpecificationVersion; public class NetworkntTestSuiteOptionalBenchmark { public static final String VERSION_202012 = "2020-12"; @@ -33,17 +33,17 @@ public static class BenchmarkState { private String specification; private Callable draft202012Optional = new NetworkntTestSuiteRunner( - NetworkntTestSuiteTestCases.findTestCases(VersionFlag.V202012, "src/test/suite/tests/draft2020-12", + NetworkntTestSuiteTestCases.findTestCases(SpecificationVersion.DRAFT_2020_12, "src/test/suite/tests/draft2020-12", TestCaseFilter.optionalType())); private Callable draft201909Optional = new NetworkntTestSuiteRunner( - NetworkntTestSuiteTestCases.findTestCases(VersionFlag.V201909, "src/test/suite/tests/draft2019-09", + NetworkntTestSuiteTestCases.findTestCases(SpecificationVersion.DRAFT_2019_09, "src/test/suite/tests/draft2019-09", TestCaseFilter.optionalType())); private Callable draft7Optional = new NetworkntTestSuiteRunner(NetworkntTestSuiteTestCases - .findTestCases(VersionFlag.V7, "src/test/suite/tests/draft7", TestCaseFilter.optionalType())); + .findTestCases(SpecificationVersion.DRAFT_7, "src/test/suite/tests/draft7", TestCaseFilter.optionalType())); private Callable draft6Optional = new NetworkntTestSuiteRunner(NetworkntTestSuiteTestCases - .findTestCases(VersionFlag.V6, "src/test/suite/tests/draft6", TestCaseFilter.optionalType())); + .findTestCases(SpecificationVersion.DRAFT_6, "src/test/suite/tests/draft6", TestCaseFilter.optionalType())); private Callable draft4Optional = new NetworkntTestSuiteRunner(NetworkntTestSuiteTestCases - .findTestCases(VersionFlag.V4, "src/test/suite/tests/draft4", TestCaseFilter.optionalType())); + .findTestCases(SpecificationVersion.DRAFT_4, "src/test/suite/tests/draft4", TestCaseFilter.optionalType())); private Callable getTestSuite() { switch (specification) { diff --git a/src/test/java/com/networknt/schema/benchmark/NetworkntTestSuiteRequiredBenchmark.java b/src/test/java/com/networknt/schema/benchmark/NetworkntTestSuiteRequiredBenchmark.java index 08526aa39..60b24d17b 100644 --- a/src/test/java/com/networknt/schema/benchmark/NetworkntTestSuiteRequiredBenchmark.java +++ b/src/test/java/com/networknt/schema/benchmark/NetworkntTestSuiteRequiredBenchmark.java @@ -18,7 +18,7 @@ import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; -import com.networknt.schema.SpecVersion.VersionFlag; +import com.networknt.schema.SpecificationVersion; public class NetworkntTestSuiteRequiredBenchmark { public static final String VERSION_202012 = "2020-12"; @@ -33,15 +33,15 @@ public static class BenchmarkState { private String specification; private Callable draft202012 = new NetworkntTestSuiteRunner(NetworkntTestSuiteTestCases.findTestCases( - VersionFlag.V202012, "src/test/suite/tests/draft2020-12", TestCaseFilter.requiredType())); + SpecificationVersion.DRAFT_2020_12, "src/test/suite/tests/draft2020-12", TestCaseFilter.requiredType())); private Callable draft201909 = new NetworkntTestSuiteRunner(NetworkntTestSuiteTestCases.findTestCases( - VersionFlag.V201909, "src/test/suite/tests/draft2019-09", TestCaseFilter.requiredType())); + SpecificationVersion.DRAFT_2019_09, "src/test/suite/tests/draft2019-09", TestCaseFilter.requiredType())); private Callable draft7 = new NetworkntTestSuiteRunner(NetworkntTestSuiteTestCases - .findTestCases(VersionFlag.V7, "src/test/suite/tests/draft7", TestCaseFilter.requiredType())); + .findTestCases(SpecificationVersion.DRAFT_7, "src/test/suite/tests/draft7", TestCaseFilter.requiredType())); private Callable draft6 = new NetworkntTestSuiteRunner(NetworkntTestSuiteTestCases - .findTestCases(VersionFlag.V6, "src/test/suite/tests/draft6", TestCaseFilter.requiredType())); + .findTestCases(SpecificationVersion.DRAFT_6, "src/test/suite/tests/draft6", TestCaseFilter.requiredType())); private Callable draft4 = new NetworkntTestSuiteRunner(NetworkntTestSuiteTestCases - .findTestCases(VersionFlag.V4, "src/test/suite/tests/draft4", TestCaseFilter.requiredType())); + .findTestCases(SpecificationVersion.DRAFT_4, "src/test/suite/tests/draft4", TestCaseFilter.requiredType())); private Callable getTestSuite() { switch (specification) { diff --git a/src/test/java/com/networknt/schema/benchmark/NetworkntTestSuiteRunner.java b/src/test/java/com/networknt/schema/benchmark/NetworkntTestSuiteRunner.java index c4fd63e17..1f3baa11b 100644 --- a/src/test/java/com/networknt/schema/benchmark/NetworkntTestSuiteRunner.java +++ b/src/test/java/com/networknt/schema/benchmark/NetworkntTestSuiteRunner.java @@ -21,13 +21,15 @@ public NetworkntTestSuiteRunner(List testCases) { public Object call() { List results = new ArrayList<>(); for (NetworkntTestSuiteTestCase testCase : testCases) { - for (TestSpec testSpec : testCase.getTestCase().getTests()) { - results.add( - testCase.getSchema().validate(testSpec.getData(), OutputFormat.DEFAULT, executionContext -> { - executionContext.getExecutionConfig() - .setFormatAssertionsEnabled(testCase.getFormatAssertionsEnabled()); - })); - } + for (TestSpec testSpec : testCase.getTestCase().getTests()) { + results.add( + testCase.getSchema().validate(testSpec.getData(), OutputFormat.DEFAULT, executionContext -> { + if (testCase.getFormatAssertionsEnabled() != null) { + executionContext.executionConfig(executionConfig -> executionConfig + .formatAssertionsEnabled(testCase.getFormatAssertionsEnabled())); + } + })); + } } return results; } diff --git a/src/test/java/com/networknt/schema/benchmark/NetworkntTestSuiteTestCase.java b/src/test/java/com/networknt/schema/benchmark/NetworkntTestSuiteTestCase.java index 450572408..16345e080 100644 --- a/src/test/java/com/networknt/schema/benchmark/NetworkntTestSuiteTestCase.java +++ b/src/test/java/com/networknt/schema/benchmark/NetworkntTestSuiteTestCase.java @@ -1,20 +1,20 @@ package com.networknt.schema.benchmark; -import com.networknt.schema.JsonSchema; +import com.networknt.schema.Schema; import com.networknt.schema.suite.TestCase; public class NetworkntTestSuiteTestCase { - private final JsonSchema schema; + private final Schema schema; private final TestCase testCase; private final Boolean formatAssertionsEnabled; - public NetworkntTestSuiteTestCase(JsonSchema schema, TestCase testCase, Boolean formatAssertionsEnabled) { + public NetworkntTestSuiteTestCase(Schema schema, TestCase testCase, Boolean formatAssertionsEnabled) { this.schema = schema; this.testCase = testCase; this.formatAssertionsEnabled = formatAssertionsEnabled; } - public JsonSchema getSchema() { + public Schema getSchema() { return schema; } diff --git a/src/test/java/com/networknt/schema/benchmark/NetworkntTestSuiteTestCases.java b/src/test/java/com/networknt/schema/benchmark/NetworkntTestSuiteTestCases.java index af3aa3310..c54e99dab 100644 --- a/src/test/java/com/networknt/schema/benchmark/NetworkntTestSuiteTestCases.java +++ b/src/test/java/com/networknt/schema/benchmark/NetworkntTestSuiteTestCases.java @@ -13,14 +13,12 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import com.networknt.schema.AbsoluteIri; -import com.networknt.schema.JsonSchema; -import com.networknt.schema.JsonSchemaFactory; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaRegistry; import com.networknt.schema.SchemaLocation; -import com.networknt.schema.SchemaValidatorsConfig; -import com.networknt.schema.SpecVersion.VersionFlag; +import com.networknt.schema.SchemaRegistryConfig; +import com.networknt.schema.SpecificationVersion; import com.networknt.schema.regex.JoniRegularExpressionFactory; -import com.networknt.schema.resource.InputStreamSource; import com.networknt.schema.resource.SchemaLoader; import com.networknt.schema.suite.TestCase; import com.networknt.schema.suite.TestSource; @@ -38,25 +36,22 @@ private static List findTestCasePaths(String basePath, Predicate findTestCases(VersionFlag defaultVersion, String basePath) { + public static List findTestCases(SpecificationVersion defaultVersion, String basePath) { return findTestCases(defaultVersion, basePath, path -> true); } - public static List findTestCases(VersionFlag defaultVersion, String basePath, + public static List findTestCases(SpecificationVersion defaultVersion, String basePath, Predicate filter) { - SchemaLoader schemaLoader = new SchemaLoader() { - @Override - public InputStreamSource getSchema(AbsoluteIri absoluteIri) { - String iri = absoluteIri.toString(); - if (iri.startsWith("http://localhost:1234")) { - return () -> { - String path = iri.substring("http://localhost:1234".length()); - return new FileInputStream("src/test/suite/remotes" + path); - }; - } - return null; + SchemaLoader schemaLoader = new SchemaLoader(location -> { + String iri = location.toString(); + if (iri.startsWith("http://localhost:1234")) { + return () -> { + String path = iri.substring("http://localhost:1234".length()); + return new FileInputStream("src/test/suite/remotes" + path); + }; } - }; + return null; + }); List results = new ArrayList<>(); List testCasePaths = findTestCasePaths(basePath, filter); for (Path path : testCasePaths) { @@ -66,11 +61,13 @@ public InputStreamSource getSchema(AbsoluteIri absoluteIri) { for (TestCase testCase : testSource.getTestCases()) { SchemaLocation testCaseFileUri = SchemaLocation .of("classpath:" + toForwardSlashPath(testCase.getSpecification())); - JsonSchema schema = JsonSchemaFactory - .getInstance(defaultVersion, - builder -> builder.schemaLoaders(schemaLoaders -> schemaLoaders.add(schemaLoader))) - .getSchema(testCaseFileUri, testCase.getSchema(), SchemaValidatorsConfig.builder() - .regularExpressionFactory(JoniRegularExpressionFactory.getInstance()).build()); + SchemaRegistryConfig config = SchemaRegistryConfig.builder() + .regularExpressionFactory(JoniRegularExpressionFactory.getInstance()).build(); + Schema schema = SchemaRegistry + .withDefaultDialect(defaultVersion, + builder -> builder.schemaRegistryConfig(config) + .schemaLoader(schemaLoader)) + .getSchema(testCaseFileUri, testCase.getSchema()); results.add(new NetworkntTestSuiteTestCase(schema, testCase, testCase.getSource().getPath().getParent().toString().endsWith("format") ? true : null)); } diff --git a/src/test/java/com/networknt/schema/format/IriFormatTest.java b/src/test/java/com/networknt/schema/format/IriFormatTest.java index 497604b6d..84479f45a 100644 --- a/src/test/java/com/networknt/schema/format/IriFormatTest.java +++ b/src/test/java/com/networknt/schema/format/IriFormatTest.java @@ -23,11 +23,10 @@ import org.junit.jupiter.api.Test; import com.networknt.schema.InputFormat; -import com.networknt.schema.JsonSchema; -import com.networknt.schema.JsonSchemaFactory; -import com.networknt.schema.SchemaValidatorsConfig; -import com.networknt.schema.SpecVersion.VersionFlag; -import com.networknt.schema.ValidationMessage; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaRegistry; +import com.networknt.schema.SpecificationVersion; +import com.networknt.schema.Error; class IriFormatTest { @Test @@ -36,10 +35,9 @@ void uriShouldPass() { + " \"format\": \"iri\"\r\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().formatAssertionsEnabled(true).build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, config); - List messages = schema.validate("\"https://test.com/assets/product.pdf\"", - InputFormat.JSON); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12).getSchema(schemaData); + List messages = schema.validate("\"https://test.com/assets/product.pdf\"", + InputFormat.JSON, executionContext -> executionContext.executionConfig(executionConfig -> executionConfig.formatAssertionsEnabled(true))); assertTrue(messages.isEmpty()); } @@ -49,10 +47,9 @@ void queryWithBracketsShouldFail() { + " \"format\": \"iri\"\r\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().formatAssertionsEnabled(true).build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, config); - List messages = schema.validate("\"https://test.com/assets/product.pdf?filter[test]=1\"", - InputFormat.JSON); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12).getSchema(schemaData); + List messages = schema.validate("\"https://test.com/assets/product.pdf?filter[test]=1\"", + InputFormat.JSON, executionContext -> executionContext.executionConfig(executionConfig -> executionConfig.formatAssertionsEnabled(true))); assertFalse(messages.isEmpty()); } @@ -62,10 +59,9 @@ void queryWithEncodedBracketsShouldPass() { + " \"format\": \"iri\"\r\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().formatAssertionsEnabled(true).build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, config); - List messages = schema.validate("\"https://test.com/assets/product.pdf?filter%5Btest%5D=1\"", - InputFormat.JSON); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12).getSchema(schemaData); + List messages = schema.validate("\"https://test.com/assets/product.pdf?filter%5Btest%5D=1\"", + InputFormat.JSON, executionContext -> executionContext.executionConfig(executionConfig -> executionConfig.formatAssertionsEnabled(true))); assertTrue(messages.isEmpty()); } @@ -75,10 +71,9 @@ void iriShouldPass() { + " \"format\": \"iri\"\r\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().formatAssertionsEnabled(true).build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, config); - List messages = schema.validate("\"https://test.com/assets/produktdatenblätter.pdf\"", - InputFormat.JSON); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12).getSchema(schemaData); + List messages = schema.validate("\"https://test.com/assets/produktdatenblätter.pdf\"", + InputFormat.JSON, executionContext -> executionContext.executionConfig(executionConfig -> executionConfig.formatAssertionsEnabled(true))); assertTrue(messages.isEmpty()); } @@ -88,9 +83,8 @@ void noAuthorityShouldPass() { + " \"format\": \"iri\"\r\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().formatAssertionsEnabled(true).build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, config); - List messages = schema.validate("\"http://\"", InputFormat.JSON); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12).getSchema(schemaData); + List messages = schema.validate("\"http://\"", InputFormat.JSON, executionContext -> executionContext.executionConfig(executionConfig -> executionConfig.formatAssertionsEnabled(true))); assertTrue(messages.isEmpty()); } @@ -100,9 +94,8 @@ void noSchemeNoAuthorityShouldPass() { + " \"format\": \"iri\"\r\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().formatAssertionsEnabled(true).build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, config); - List messages = schema.validate("\"//\"", InputFormat.JSON); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12).getSchema(schemaData); + List messages = schema.validate("\"//\"", InputFormat.JSON, executionContext -> executionContext.executionConfig(executionConfig -> executionConfig.formatAssertionsEnabled(true))); assertTrue(messages.isEmpty()); } @@ -112,9 +105,8 @@ void noPathShouldPass() { + " \"format\": \"iri\"\r\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().formatAssertionsEnabled(true).build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, config); - List messages = schema.validate("\"about:\"", InputFormat.JSON); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12).getSchema(schemaData); + List messages = schema.validate("\"about:\"", InputFormat.JSON, executionContext -> executionContext.executionConfig(executionConfig -> executionConfig.formatAssertionsEnabled(true))); assertTrue(messages.isEmpty()); } } diff --git a/src/test/java/com/networknt/schema/format/IriReferenceFormatTest.java b/src/test/java/com/networknt/schema/format/IriReferenceFormatTest.java index b541ee3fc..a05a262a5 100644 --- a/src/test/java/com/networknt/schema/format/IriReferenceFormatTest.java +++ b/src/test/java/com/networknt/schema/format/IriReferenceFormatTest.java @@ -23,11 +23,11 @@ import org.junit.jupiter.api.Test; import com.networknt.schema.InputFormat; -import com.networknt.schema.JsonSchema; -import com.networknt.schema.JsonSchemaFactory; -import com.networknt.schema.SchemaValidatorsConfig; -import com.networknt.schema.SpecVersion.VersionFlag; -import com.networknt.schema.ValidationMessage; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaRegistry; +import com.networknt.schema.SchemaRegistryConfig; +import com.networknt.schema.SpecificationVersion; +import com.networknt.schema.Error; class IriReferenceFormatTest { @Test @@ -36,9 +36,11 @@ void uriShouldPass() { + " \"format\": \"iri-reference\"\r\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().formatAssertionsEnabled(true).build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, config); - List messages = schema.validate("\"https://test.com/assets/product.pdf\"", + SchemaRegistryConfig config = SchemaRegistryConfig.builder().formatAssertionsEnabled(true).build(); + Schema schema = SchemaRegistry + .withDefaultDialect(SpecificationVersion.DRAFT_2020_12, builder -> builder.schemaRegistryConfig(config)) + .getSchema(schemaData); + List messages = schema.validate("\"https://test.com/assets/product.pdf\"", InputFormat.JSON); assertTrue(messages.isEmpty()); } @@ -49,9 +51,11 @@ void queryWithBracketsShouldFail() { + " \"format\": \"iri-reference\"\r\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().formatAssertionsEnabled(true).build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, config); - List messages = schema.validate("\"https://test.com/assets/product.pdf?filter[test]=1\"", + SchemaRegistryConfig config = SchemaRegistryConfig.builder().formatAssertionsEnabled(true).build(); + Schema schema = SchemaRegistry + .withDefaultDialect(SpecificationVersion.DRAFT_2020_12, builder -> builder.schemaRegistryConfig(config)) + .getSchema(schemaData); + List messages = schema.validate("\"https://test.com/assets/product.pdf?filter[test]=1\"", InputFormat.JSON); assertFalse(messages.isEmpty()); } @@ -62,9 +66,11 @@ void queryWithEncodedBracketsShouldPass() { + " \"format\": \"iri-reference\"\r\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().formatAssertionsEnabled(true).build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, config); - List messages = schema.validate("\"https://test.com/assets/product.pdf?filter%5Btest%5D=1\"", + SchemaRegistryConfig config = SchemaRegistryConfig.builder().formatAssertionsEnabled(true).build(); + Schema schema = SchemaRegistry + .withDefaultDialect(SpecificationVersion.DRAFT_2020_12, builder -> builder.schemaRegistryConfig(config)) + .getSchema(schemaData); + List messages = schema.validate("\"https://test.com/assets/product.pdf?filter%5Btest%5D=1\"", InputFormat.JSON); assertTrue(messages.isEmpty()); } @@ -75,9 +81,11 @@ void iriShouldPass() { + " \"format\": \"iri-reference\"\r\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().formatAssertionsEnabled(true).build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, config); - List messages = schema.validate("\"https://test.com/assets/produktdatenblätter.pdf\"", + SchemaRegistryConfig config = SchemaRegistryConfig.builder().formatAssertionsEnabled(true).build(); + Schema schema = SchemaRegistry + .withDefaultDialect(SpecificationVersion.DRAFT_2020_12, builder -> builder.schemaRegistryConfig(config)) + .getSchema(schemaData); + List messages = schema.validate("\"https://test.com/assets/produktdatenblätter.pdf\"", InputFormat.JSON); assertTrue(messages.isEmpty()); } @@ -88,9 +96,11 @@ void noAuthorityShouldPass() { + " \"format\": \"iri-reference\"\r\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().formatAssertionsEnabled(true).build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, config); - List messages = schema.validate("\"http://\"", InputFormat.JSON); + SchemaRegistryConfig config = SchemaRegistryConfig.builder().formatAssertionsEnabled(true).build(); + Schema schema = SchemaRegistry + .withDefaultDialect(SpecificationVersion.DRAFT_2020_12, builder -> builder.schemaRegistryConfig(config)) + .getSchema(schemaData); + List messages = schema.validate("\"http://\"", InputFormat.JSON); assertTrue(messages.isEmpty()); } @@ -100,9 +110,11 @@ void noSchemeNoAuthorityShouldPass() { + " \"format\": \"iri-reference\"\r\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().formatAssertionsEnabled(true).build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, config); - List messages = schema.validate("\"//\"", InputFormat.JSON); + SchemaRegistryConfig config = SchemaRegistryConfig.builder().formatAssertionsEnabled(true).build(); + Schema schema = SchemaRegistry + .withDefaultDialect(SpecificationVersion.DRAFT_2020_12, builder -> builder.schemaRegistryConfig(config)) + .getSchema(schemaData); + List messages = schema.validate("\"//\"", InputFormat.JSON); assertTrue(messages.isEmpty()); } @@ -112,9 +124,8 @@ void noPathShouldPass() { + " \"format\": \"iri-reference\"\r\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().formatAssertionsEnabled(true).build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, config); - List messages = schema.validate("\"about:\"", InputFormat.JSON); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12).getSchema(schemaData); + List messages = schema.validate("\"about:\"", InputFormat.JSON, executionContext -> executionContext.executionConfig(executionConfig -> executionConfig.formatAssertionsEnabled(true))); assertTrue(messages.isEmpty()); } diff --git a/src/test/java/com/networknt/schema/format/TimeFormatTest.java b/src/test/java/com/networknt/schema/format/TimeFormatTest.java index 373e660c0..2081d2203 100644 --- a/src/test/java/com/networknt/schema/format/TimeFormatTest.java +++ b/src/test/java/com/networknt/schema/format/TimeFormatTest.java @@ -23,11 +23,10 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.EnumSource; import com.networknt.schema.InputFormat; -import com.networknt.schema.JsonSchema; -import com.networknt.schema.JsonSchemaFactory; -import com.networknt.schema.SchemaValidatorsConfig; -import com.networknt.schema.SpecVersion.VersionFlag; -import com.networknt.schema.ValidationMessage; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaRegistry; +import com.networknt.schema.SpecificationVersion; +import com.networknt.schema.Error; class TimeFormatTest { @@ -59,9 +58,9 @@ void validTimeShouldPass(ValidTimeFormatInput input) { String inputData = "\""+input.format+"\""; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().formatAssertionsEnabled(true).build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, config); - List messages = schema.validate(inputData, InputFormat.JSON); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12).getSchema(schemaData); + List messages = schema.validate(inputData, InputFormat.JSON, + executionContext -> executionContext.executionConfig(executionConfig -> executionConfig.formatAssertionsEnabled(true))); assertTrue(messages.isEmpty()); } @@ -88,9 +87,9 @@ void invalidTimeShouldFail(InvalidTimeFormatInput input) { String inputData = "\""+input.format+"\""; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().formatAssertionsEnabled(true).build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, config); - List messages = schema.validate(inputData, InputFormat.JSON); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12).getSchema(schemaData); + List messages = schema.validate(inputData, InputFormat.JSON, + executionContext -> executionContext.executionConfig(executionConfig -> executionConfig.formatAssertionsEnabled(true))); assertFalse(messages.isEmpty()); } } diff --git a/src/test/java/com/networknt/schema/format/UriFormatTest.java b/src/test/java/com/networknt/schema/format/UriFormatTest.java index 02edd5cf2..c7a5c83ca 100644 --- a/src/test/java/com/networknt/schema/format/UriFormatTest.java +++ b/src/test/java/com/networknt/schema/format/UriFormatTest.java @@ -23,11 +23,10 @@ import org.junit.jupiter.api.Test; import com.networknt.schema.InputFormat; -import com.networknt.schema.JsonSchema; -import com.networknt.schema.JsonSchemaFactory; -import com.networknt.schema.SchemaValidatorsConfig; -import com.networknt.schema.SpecVersion.VersionFlag; -import com.networknt.schema.ValidationMessage; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaRegistry; +import com.networknt.schema.SpecificationVersion; +import com.networknt.schema.Error; class UriFormatTest { @Test @@ -36,10 +35,9 @@ void uriShouldPass() { + " \"format\": \"uri\"\r\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().formatAssertionsEnabled(true).build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, config); - List messages = schema.validate("\"https://test.com/assets/product.pdf\"", - InputFormat.JSON); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12).getSchema(schemaData); + List messages = schema.validate("\"https://test.com/assets/product.pdf\"", + InputFormat.JSON, executionContext -> executionContext.executionConfig(executionConfig -> executionConfig.formatAssertionsEnabled(true))); assertTrue(messages.isEmpty()); } @@ -48,11 +46,9 @@ void queryWithBracketsShouldFail() { String schemaData = "{\r\n" + " \"format\": \"uri\"\r\n" + "}"; - - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().formatAssertionsEnabled(true).build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, config); - List messages = schema.validate("\"https://test.com/assets/product.pdf?filter[test]=1\"", - InputFormat.JSON); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12).getSchema(schemaData); + List messages = schema.validate("\"https://test.com/assets/product.pdf?filter[test]=1\"", + InputFormat.JSON, executionContext -> executionContext.executionConfig(executionConfig -> executionConfig.formatAssertionsEnabled(true))); assertFalse(messages.isEmpty()); } @@ -62,10 +58,9 @@ void queryWithEncodedBracketsShouldPass() { + " \"format\": \"uri\"\r\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().formatAssertionsEnabled(true).build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, config); - List messages = schema.validate("\"https://test.com/assets/product.pdf?filter%5Btest%5D=1\"", - InputFormat.JSON); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12).getSchema(schemaData); + List messages = schema.validate("\"https://test.com/assets/product.pdf?filter%5Btest%5D=1\"", + InputFormat.JSON, executionContext -> executionContext.executionConfig(executionConfig -> executionConfig.formatAssertionsEnabled(true))); assertTrue(messages.isEmpty()); } @@ -75,10 +70,9 @@ void iriShouldFail() { + " \"format\": \"uri\"\r\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().formatAssertionsEnabled(true).build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, config); - List messages = schema.validate("\"https://test.com/assets/produktdatenblätter.pdf\"", - InputFormat.JSON); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12).getSchema(schemaData); + List messages = schema.validate("\"https://test.com/assets/produktdatenblätter.pdf\"", + InputFormat.JSON, executionContext -> executionContext.executionConfig(executionConfig -> executionConfig.formatAssertionsEnabled(true))); assertFalse(messages.isEmpty()); } @@ -87,10 +81,8 @@ void noAuthorityShouldPass() { String schemaData = "{\r\n" + " \"format\": \"uri\"\r\n" + "}"; - - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().formatAssertionsEnabled(true).build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, config); - List messages = schema.validate("\"http://\"", InputFormat.JSON); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12).getSchema(schemaData); + List messages = schema.validate("\"http://\"", InputFormat.JSON, executionContext -> executionContext.executionConfig(executionConfig -> executionConfig.formatAssertionsEnabled(true))); assertTrue(messages.isEmpty()); } @@ -100,9 +92,8 @@ void noSchemeNoAuthorityShouldPass() { + " \"format\": \"uri\"\r\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().formatAssertionsEnabled(true).build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, config); - List messages = schema.validate("\"//\"", InputFormat.JSON); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12).getSchema(schemaData); + List messages = schema.validate("\"//\"", InputFormat.JSON, executionContext -> executionContext.executionConfig(executionConfig -> executionConfig.formatAssertionsEnabled(true))); assertTrue(messages.isEmpty()); } @@ -111,10 +102,8 @@ void noPathShouldPass() { String schemaData = "{\r\n" + " \"format\": \"uri\"\r\n" + "}"; - - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().formatAssertionsEnabled(true).build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, config); - List messages = schema.validate("\"about:\"", InputFormat.JSON); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12).getSchema(schemaData); + List messages = schema.validate("\"about:\"", InputFormat.JSON, executionContext -> executionContext.executionConfig(executionConfig -> executionConfig.formatAssertionsEnabled(true))); assertTrue(messages.isEmpty()); } } diff --git a/src/test/java/com/networknt/schema/format/UriReferenceFormatTest.java b/src/test/java/com/networknt/schema/format/UriReferenceFormatTest.java index 00c8b855e..5092c3c01 100644 --- a/src/test/java/com/networknt/schema/format/UriReferenceFormatTest.java +++ b/src/test/java/com/networknt/schema/format/UriReferenceFormatTest.java @@ -23,11 +23,10 @@ import org.junit.jupiter.api.Test; import com.networknt.schema.InputFormat; -import com.networknt.schema.JsonSchema; -import com.networknt.schema.JsonSchemaFactory; -import com.networknt.schema.SchemaValidatorsConfig; -import com.networknt.schema.SpecVersion.VersionFlag; -import com.networknt.schema.ValidationMessage; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaRegistry; +import com.networknt.schema.SpecificationVersion; +import com.networknt.schema.Error; class UriReferenceFormatTest { @Test @@ -36,10 +35,9 @@ void uriShouldPass() { + " \"format\": \"uri-reference\"\r\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().formatAssertionsEnabled(true).build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, config); - List messages = schema.validate("\"https://test.com/assets/product.pdf\"", - InputFormat.JSON); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12).getSchema(schemaData); + List messages = schema.validate("\"https://test.com/assets/product.pdf\"", + InputFormat.JSON, executionContext -> executionContext.executionConfig(executionConfig -> executionConfig.formatAssertionsEnabled(true))); assertTrue(messages.isEmpty()); } @@ -49,10 +47,9 @@ void queryWithBracketsShouldFail() { + " \"format\": \"uri-reference\"\r\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().formatAssertionsEnabled(true).build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, config); - List messages = schema.validate("\"https://test.com/assets/product.pdf?filter[test]=1\"", - InputFormat.JSON); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12).getSchema(schemaData); + List messages = schema.validate("\"https://test.com/assets/product.pdf?filter[test]=1\"", + InputFormat.JSON, executionContext -> executionContext.executionConfig(executionConfig -> executionConfig.formatAssertionsEnabled(true))); assertFalse(messages.isEmpty()); } @@ -62,10 +59,9 @@ void queryWithEncodedBracketsShouldPass() { + " \"format\": \"uri-reference\"\r\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().formatAssertionsEnabled(true).build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, config); - List messages = schema.validate("\"https://test.com/assets/product.pdf?filter%5Btest%5D=1\"", - InputFormat.JSON); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12).getSchema(schemaData); + List messages = schema.validate("\"https://test.com/assets/product.pdf?filter%5Btest%5D=1\"", + InputFormat.JSON, executionContext -> executionContext.executionConfig(executionConfig -> executionConfig.formatAssertionsEnabled(true))); assertTrue(messages.isEmpty()); } @@ -75,10 +71,9 @@ void iriShouldFail() { + " \"format\": \"uri-reference\"\r\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().formatAssertionsEnabled(true).build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, config); - List messages = schema.validate("\"https://test.com/assets/produktdatenblätter.pdf\"", - InputFormat.JSON); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12).getSchema(schemaData); + List messages = schema.validate("\"https://test.com/assets/produktdatenblätter.pdf\"", + InputFormat.JSON, executionContext -> executionContext.executionConfig(executionConfig -> executionConfig.formatAssertionsEnabled(true))); assertFalse(messages.isEmpty()); } @@ -88,9 +83,8 @@ void noAuthorityShouldPass() { + " \"format\": \"uri-reference\"\r\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().formatAssertionsEnabled(true).build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, config); - List messages = schema.validate("\"http://\"", InputFormat.JSON); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12).getSchema(schemaData); + List messages = schema.validate("\"http://\"", InputFormat.JSON, executionContext -> executionContext.executionConfig(executionConfig -> executionConfig.formatAssertionsEnabled(true))); assertTrue(messages.isEmpty()); } @@ -100,9 +94,8 @@ void noSchemeNoAuthorityShouldPass() { + " \"format\": \"uri-reference\"\r\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().formatAssertionsEnabled(true).build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, config); - List messages = schema.validate("\"//\"", InputFormat.JSON); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12).getSchema(schemaData); + List messages = schema.validate("\"//\"", InputFormat.JSON, executionContext -> executionContext.executionConfig(executionConfig -> executionConfig.formatAssertionsEnabled(true))); assertTrue(messages.isEmpty()); } @@ -112,9 +105,8 @@ void noPathShouldPass() { + " \"format\": \"uri-reference\"\r\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().formatAssertionsEnabled(true).build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, config); - List messages = schema.validate("\"about:\"", InputFormat.JSON); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12).getSchema(schemaData); + List messages = schema.validate("\"about:\"", InputFormat.JSON, executionContext -> executionContext.executionConfig(executionConfig -> executionConfig.formatAssertionsEnabled(true))); assertTrue(messages.isEmpty()); } } diff --git a/src/test/java/com/networknt/schema/i18n/ResourceBundleMessageSourceTest.java b/src/test/java/com/networknt/schema/i18n/ResourceBundleMessageSourceTest.java index aa69109be..86e91e223 100644 --- a/src/test/java/com/networknt/schema/i18n/ResourceBundleMessageSourceTest.java +++ b/src/test/java/com/networknt/schema/i18n/ResourceBundleMessageSourceTest.java @@ -63,8 +63,8 @@ void messageFrench() { @Test void messageMaxItems() { - String message = messageSource.getMessage("maxItems", Locale.getDefault(), "item", 5, 10); - assertEquals("item: must have at most 5 items but found 10", message); + String message = messageSource.getMessage("maxItems", Locale.getDefault(), 5, 10); + assertEquals("must have at most 5 items but found 10", message); } @Test @@ -78,6 +78,6 @@ void overrideMessage() { MessageSource messageSource = new ResourceBundleMessageSource("jsv-messages-override", "jsv-messages"); assertEquals("path: overridden message value", messageSource.getMessage("allOf", Locale.ROOT, "path", "value")); assertEquals("path: overridden message value", messageSource.getMessage("allOf", Locale.FRENCH, "path", "value")); - assertEquals("path: must be valid to any of the schemas value", messageSource.getMessage("anyOf", Locale.ROOT, "path", "value")); + assertEquals("must be valid to any of the schemas value", messageSource.getMessage("anyOf", Locale.ROOT, "value")); } } diff --git a/src/test/java/com/networknt/schema/keyword/PropertyDependenciesValidatorTest.java b/src/test/java/com/networknt/schema/keyword/PropertyDependenciesValidatorTest.java new file mode 100644 index 000000000..6e086c549 --- /dev/null +++ b/src/test/java/com/networknt/schema/keyword/PropertyDependenciesValidatorTest.java @@ -0,0 +1,58 @@ +package com.networknt.schema.keyword; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.List; + +import org.junit.jupiter.api.Test; + +import com.networknt.schema.Error; +import com.networknt.schema.InputFormat; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaRegistry; +import com.networknt.schema.dialect.Dialect; +import com.networknt.schema.dialect.Dialects; + +/** + * Test for propertyDependencies. + */ +public class PropertyDependenciesValidatorTest { + @Test + void basicTest() { + Dialect dialect = Dialect.builder(Dialects.getDraft202012()).keyword(KeywordType.PROPERTY_DEPENDENCIES).build(); + SchemaRegistry schemaRegistry = SchemaRegistry.withDialect(dialect); + String schemaData = "{\r\n" + + " \"propertyDependencies\": {\r\n" + + " \"foo\": {\r\n" + + " \"aaa\": {\r\n" + + " \"$ref\": \"#/$defs/foo-aaa\"\r\n" + + " }\r\n" + + " }\r\n" + + " },\r\n" + + " \"$defs\": {\r\n" + + " \"foo-aaa\": {\r\n" + + " \"type\": \"object\",\r\n" + + " \"properties\": {\r\n" + + " \"foo\": {\r\n" + + " \"type\": \"string\"\r\n" + + " },\r\n" + + " \"bar\": {\r\n" + + " \"type\": \"string\"\r\n" + + " }\r\n" + + " }\r\n" + + " }\r\n" + + " }\r\n" + + "}"; + String instanceData = "{\r\n" + + " \"foo\": \"aaa\",\r\n" + + " \"bar\": 1\r\n" + + "}"; + Schema schema = schemaRegistry.getSchema(schemaData, InputFormat.JSON); + List errors = schema.validate(instanceData, InputFormat.JSON); + assertEquals(1, errors.size()); + assertEquals("/propertyDependencies/foo/aaa/$ref/properties/bar/type", errors.get(0).getEvaluationPath().toString()); + assertEquals("#/$defs/foo-aaa/properties/bar/type", errors.get(0).getSchemaLocation().toString()); + assertEquals("type", errors.get(0).getKeyword()); + } + +} diff --git a/src/test/java/com/networknt/schema/ThresholdMixinPerfTest.java b/src/test/java/com/networknt/schema/keyword/ThresholdMixinPerfTest.java similarity index 96% rename from src/test/java/com/networknt/schema/ThresholdMixinPerfTest.java rename to src/test/java/com/networknt/schema/keyword/ThresholdMixinPerfTest.java index 98cae3484..014c117e0 100644 --- a/src/test/java/com/networknt/schema/ThresholdMixinPerfTest.java +++ b/src/test/java/com/networknt/schema/keyword/ThresholdMixinPerfTest.java @@ -13,18 +13,23 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.keyword; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.node.*; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; +import static java.lang.System.out; import java.math.BigDecimal; import java.math.BigInteger; -import static java.lang.System.out; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.BigIntegerNode; +import com.fasterxml.jackson.databind.node.DecimalNode; +import com.fasterxml.jackson.databind.node.DoubleNode; +import com.fasterxml.jackson.databind.node.LongNode; +import com.fasterxml.jackson.databind.node.TextNode; @Disabled class ThresholdMixinPerfTest { @@ -32,9 +37,11 @@ class ThresholdMixinPerfTest { private final LongNode maximumLong = new LongNode(thresholdIntegral); + @SuppressWarnings("unused") private final BigIntegerNode maximumBigInt = new BigIntegerNode(BigInteger.valueOf(thresholdIntegral)); private final LongNode valueLong = new LongNode(Long.MAX_VALUE); + @SuppressWarnings("unused") private final BigIntegerNode valueBigInt = new BigIntegerNode(BigInteger.valueOf(Long.MAX_VALUE)); // private final double threshold = Double.MAX_VALUE - 1; @@ -204,6 +211,7 @@ public String thresholdValue() { } ThresholdMixin asDouble = new ThresholdMixin() { + @SuppressWarnings("unused") @Override public boolean crossesThreshold(JsonNode node) { double lm = maximumDouble.doubleValue(); @@ -218,6 +226,7 @@ public String thresholdValue() { }; ThresholdMixin asLong = new ThresholdMixin() { + @SuppressWarnings("unused") @Override public boolean crossesThreshold(JsonNode node) { long lm = maximumLong.longValue(); @@ -232,6 +241,7 @@ public String thresholdValue() { }; ThresholdMixin typedThreshold = new ThresholdMixin() { + @SuppressWarnings("unused") @Override public boolean crossesThreshold(JsonNode node) { if (node.isDouble()) { @@ -258,6 +268,7 @@ public String thresholdValue() { }; ThresholdMixin currentImplementationDouble = new ThresholdMixin() { + @SuppressWarnings("unused") @Override public boolean crossesThreshold(JsonNode node) { if (maximumDouble.isDouble() && maximumDouble.doubleValue() == Double.POSITIVE_INFINITY) { @@ -286,6 +297,7 @@ public String thresholdValue() { ThresholdMixin currentImplementationDecimal = new ThresholdMixin() { + @SuppressWarnings("unused") @Override public boolean crossesThreshold(JsonNode node) { if (maximumDecimal.isDouble() && maximumDecimal.doubleValue() == Double.POSITIVE_INFINITY) { @@ -313,6 +325,7 @@ public String thresholdValue() { }; ThresholdMixin oneMixinForIntegerAndNumber = new ThresholdMixin() { + @SuppressWarnings("unused") @Override public boolean crossesThreshold(JsonNode node) { BigDecimal value = new BigDecimal(node.asText()); diff --git a/src/test/java/com/networknt/schema/oas/OpenApi30Test.java b/src/test/java/com/networknt/schema/oas/OpenApi30Test.java index 08ba18786..dbe246c40 100644 --- a/src/test/java/com/networknt/schema/oas/OpenApi30Test.java +++ b/src/test/java/com/networknt/schema/oas/OpenApi30Test.java @@ -24,16 +24,15 @@ import org.junit.jupiter.api.Test; -import com.networknt.schema.DisallowUnknownJsonMetaSchemaFactory; import com.networknt.schema.InputFormat; -import com.networknt.schema.JsonSchema; -import com.networknt.schema.JsonSchemaFactory; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaRegistry; import com.networknt.schema.OutputFormat; -import com.networknt.schema.PathType; import com.networknt.schema.SchemaLocation; -import com.networknt.schema.SchemaValidatorsConfig; -import com.networknt.schema.SpecVersion.VersionFlag; -import com.networknt.schema.ValidationMessage; +import com.networknt.schema.SchemaRegistryConfig; +import com.networknt.schema.dialect.Dialects; +import com.networknt.schema.path.PathType; +import com.networknt.schema.Error; /** * OpenApi30Test. @@ -44,17 +43,14 @@ class OpenApi30Test { */ @Test void validateMetaSchema() { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V7, - builder -> builder.metaSchema(OpenApi30.getInstance()) - .defaultMetaSchemaIri(OpenApi30.getInstance().getIri()) - .metaSchemaFactory(DisallowUnknownJsonMetaSchemaFactory.getInstance())); - JsonSchema schema = factory.getSchema(SchemaLocation.of( + SchemaRegistry factory = SchemaRegistry.withDialect(Dialects.getOpenApi30()); + Schema schema = factory.getSchema(SchemaLocation.of( "classpath:schema/oas/3.0/petstore.yaml#/paths/~1pet/post/requestBody/content/application~1json/schema")); String input = "{\r\n" + " \"petType\": \"dog\",\r\n" + " \"bark\": \"woof\"\r\n" + "}"; - List messages = schema.validate(input, InputFormat.JSON); + List messages = schema.validate(input, InputFormat.JSON); assertEquals(0, messages.size()); String invalid = "{\r\n" @@ -63,9 +59,9 @@ void validateMetaSchema() { + "}"; messages = schema.validate(invalid, InputFormat.JSON); assertEquals(2, messages.size()); - List list = messages.stream().collect(Collectors.toList()); - assertEquals("oneOf", list.get(0).getType()); - assertEquals("required", list.get(1).getType()); + List list = messages.stream().collect(Collectors.toList()); + assertEquals("oneOf", list.get(0).getKeyword()); + assertEquals("required", list.get(1).getKeyword()); assertEquals("bark", list.get(1).getProperty()); } @@ -74,11 +70,11 @@ void validateMetaSchema() { */ @Test void jsonPointerWithNumberInFragment() { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V7, builder -> builder - .metaSchema(OpenApi30.getInstance()).defaultMetaSchemaIri(OpenApi30.getInstance().getIri())); - JsonSchema schema = factory.getSchema(SchemaLocation.of( - "classpath:schema/oas/3.0/petstore.yaml#/paths/~1pet/post/responses/200/content/application~1json/schema"), - SchemaValidatorsConfig.builder().pathType(PathType.JSON_PATH).build()); + SchemaRegistryConfig config = SchemaRegistryConfig.builder().pathType(PathType.JSON_PATH).build(); + SchemaRegistry factory = SchemaRegistry.withDialect(Dialects.getOpenApi30(), builder -> builder.schemaRegistryConfig(config)); + Schema schema = factory.getSchema(SchemaLocation.of( + "classpath:schema/oas/3.0/petstore.yaml#/paths/~1pet/post/responses/200/content/application~1json/schema") + ); assertNotNull(schema); assertEquals("$.paths['/pet'].post.responses['200'].content['application/json'].schema", schema.getEvaluationPath().toString()); @@ -95,9 +91,8 @@ void exclusiveMaximum() { + " \"maximum\": 100,\r\n" + " \"exclusiveMaximum\": true\r\n" + "}\r\n"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V7, builder -> builder - .metaSchema(OpenApi30.getInstance()).defaultMetaSchemaIri(OpenApi30.getInstance().getIri())); - JsonSchema schema = factory.getSchema(schemaData); + SchemaRegistry factory = SchemaRegistry.withDialect(Dialects.getOpenApi30()); + Schema schema = factory.getSchema(schemaData); assertFalse(schema.validate("100", InputFormat.JSON, OutputFormat.BOOLEAN)); } @@ -112,9 +107,8 @@ void exclusiveMinimum() { + " \"maximum\": 100,\r\n" + " \"exclusiveMinimum\": true\r\n" + "}\r\n"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V7, builder -> builder - .metaSchema(OpenApi30.getInstance()).defaultMetaSchemaIri(OpenApi30.getInstance().getIri())); - JsonSchema schema = factory.getSchema(schemaData); + SchemaRegistry factory = SchemaRegistry.withDialect(Dialects.getOpenApi30()); + Schema schema = factory.getSchema(schemaData); assertFalse(schema.validate("0", InputFormat.JSON, OutputFormat.BOOLEAN)); } } diff --git a/src/test/java/com/networknt/schema/oas/OpenApi31Test.java b/src/test/java/com/networknt/schema/oas/OpenApi31Test.java index 74d9a12f8..84ab471b2 100644 --- a/src/test/java/com/networknt/schema/oas/OpenApi31Test.java +++ b/src/test/java/com/networknt/schema/oas/OpenApi31Test.java @@ -22,13 +22,13 @@ import org.junit.jupiter.api.Test; -import com.networknt.schema.DisallowUnknownJsonMetaSchemaFactory; import com.networknt.schema.InputFormat; -import com.networknt.schema.JsonSchema; -import com.networknt.schema.JsonSchemaFactory; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaRegistry; import com.networknt.schema.SchemaLocation; -import com.networknt.schema.SpecVersion.VersionFlag; -import com.networknt.schema.ValidationMessage; +import com.networknt.schema.SpecificationVersion; +import com.networknt.schema.dialect.Dialects; +import com.networknt.schema.Error; /** * OpenApi31Test. @@ -39,16 +39,16 @@ class OpenApi31Test { */ @Test void validateVocabulary() { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012, - builder -> builder.schemaMappers(schemaMappers -> schemaMappers + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12, + builder -> builder.schemaIdResolvers(schemaIdResolvers -> schemaIdResolvers .mapPrefix("https://spec.openapis.org/oas/3.1", "classpath:oas/3.1"))); - JsonSchema schema = factory + Schema schema = factory .getSchema(SchemaLocation.of("classpath:schema/oas/3.1/petstore.yaml#/components/schemas/PetResponse")); String input = "{\r\n" + " \"petType\": \"dog\",\r\n" + " \"bark\": \"woof\"\r\n" + "}"; - List messages = schema.validate(input, InputFormat.JSON); + List messages = schema.validate(input, InputFormat.JSON); assertEquals(0, messages.size()); String invalid = "{\r\n" @@ -57,9 +57,9 @@ void validateVocabulary() { + "}"; messages = schema.validate(invalid, InputFormat.JSON); assertEquals(2, messages.size()); - List list = messages.stream().collect(Collectors.toList()); - assertEquals("oneOf", list.get(0).getType()); - assertEquals("required", list.get(1).getType()); + List list = messages.stream().collect(Collectors.toList()); + assertEquals("oneOf", list.get(0).getKeyword()); + assertEquals("required", list.get(1).getKeyword()); assertEquals("bark", list.get(1).getProperty()); } @@ -68,16 +68,14 @@ void validateVocabulary() { */ @Test void validateMetaSchema() { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012, - builder -> builder.metaSchema(OpenApi31.getInstance()) - .metaSchemaFactory(DisallowUnknownJsonMetaSchemaFactory.getInstance())); - JsonSchema schema = factory + SchemaRegistry factory = SchemaRegistry.withDialect(Dialects.getOpenApi31()); + Schema schema = factory .getSchema(SchemaLocation.of("classpath:schema/oas/3.1/petstore.yaml#/components/schemas/PetResponse")); String input = "{\r\n" + " \"petType\": \"dog\",\r\n" + " \"bark\": \"woof\"\r\n" + "}"; - List messages = schema.validate(input, InputFormat.JSON); + List messages = schema.validate(input, InputFormat.JSON); assertEquals(0, messages.size()); String invalid = "{\r\n" @@ -86,9 +84,9 @@ void validateMetaSchema() { + "}"; messages = schema.validate(invalid, InputFormat.JSON); assertEquals(2, messages.size()); - List list = messages.stream().collect(Collectors.toList()); - assertEquals("oneOf", list.get(0).getType()); - assertEquals("required", list.get(1).getType()); + List list = messages.stream().collect(Collectors.toList()); + assertEquals("oneOf", list.get(0).getKeyword()); + assertEquals("required", list.get(1).getKeyword()); assertEquals("bark", list.get(1).getProperty()); } @@ -98,19 +96,17 @@ void validateMetaSchema() { */ @Test void discriminatorOneOfMultipleMatchShouldFail() { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012, - builder -> builder.metaSchema(OpenApi31.getInstance()) - .metaSchemaFactory(DisallowUnknownJsonMetaSchemaFactory.getInstance())); - JsonSchema schema = factory + SchemaRegistry factory = SchemaRegistry.withDialect(Dialects.getOpenApi31()); + Schema schema = factory .getSchema(SchemaLocation.of("classpath:schema/oas/3.1/petstore.yaml#/components/schemas/PetResponse")); String input = "{\r\n" + " \"petType\": \"dog\",\r\n" + " \"bark\": \"woof\",\r\n" + " \"lovesRocks\": true\r\n" + "}"; - List messages = schema.validate(input, InputFormat.JSON); - List list = messages.stream().collect(Collectors.toList()); - assertEquals("oneOf", list.get(0).getType()); + List messages = schema.validate(input, InputFormat.JSON); + List list = messages.stream().collect(Collectors.toList()); + assertEquals("oneOf", list.get(0).getKeyword()); } /** @@ -118,19 +114,17 @@ void discriminatorOneOfMultipleMatchShouldFail() { */ @Test void discriminatorOneOfNoMatchShouldFail() { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012, - builder -> builder.metaSchema(OpenApi31.getInstance()) - .metaSchemaFactory(DisallowUnknownJsonMetaSchemaFactory.getInstance())); - JsonSchema schema = factory + SchemaRegistry factory = SchemaRegistry.withDialect(Dialects.getOpenApi31()); + Schema schema = factory .getSchema(SchemaLocation.of("classpath:schema/oas/3.1/petstore.yaml#/components/schemas/PetResponse")); String input = "{\r\n" + " \"petType\": \"lizard\",\r\n" + " \"none\": true\r\n" + "}"; - List messages = schema.validate(input, InputFormat.JSON); - List list = messages.stream().collect(Collectors.toList()); - assertEquals("oneOf", list.get(0).getType()); - assertEquals("required", list.get(1).getType()); + List messages = schema.validate(input, InputFormat.JSON); + List list = messages.stream().collect(Collectors.toList()); + assertEquals("oneOf", list.get(0).getKeyword()); + assertEquals("required", list.get(1).getKeyword()); assertEquals("lovesRocks", list.get(1).getProperty()); } @@ -140,16 +134,14 @@ void discriminatorOneOfNoMatchShouldFail() { */ @Test void discriminatorOneOfOneMatchWrongDiscriminatorShouldSucceed() { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012, - builder -> builder.metaSchema(OpenApi31.getInstance()) - .metaSchemaFactory(DisallowUnknownJsonMetaSchemaFactory.getInstance())); - JsonSchema schema = factory + SchemaRegistry factory = SchemaRegistry.withDialect(Dialects.getOpenApi31()); + Schema schema = factory .getSchema(SchemaLocation.of("classpath:schema/oas/3.1/petstore.yaml#/components/schemas/PetResponse")); String input = "{\r\n" + " \"petType\": \"dog\",\r\n" + " \"lovesRocks\": true\r\n" + "}"; - List messages = schema.validate(input, InputFormat.JSON); + List messages = schema.validate(input, InputFormat.JSON); assertEquals(0, messages.size()); } diff --git a/src/test/java/com/networknt/schema/output/OutputUnitDataTest.java b/src/test/java/com/networknt/schema/output/OutputUnitDataTest.java deleted file mode 100644 index 098ba11ae..000000000 --- a/src/test/java/com/networknt/schema/output/OutputUnitDataTest.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.networknt.schema.output; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import org.junit.jupiter.api.Test; - -/** - * OutputUnitDataTest. - */ -class OutputUnitDataTest { - - @Test - void format() { - String result = OutputUnitData.formatMessage("hello:"); - assertEquals("", result); - result = OutputUnitData.formatMessage("hello: "); - assertEquals("", result); - result = OutputUnitData.formatMessage("hello: "); - assertEquals("", result); - result = OutputUnitData.formatMessage("hello: world"); - assertEquals("world", result); - } -} diff --git a/src/test/java/com/networknt/schema/PathTypeTest.java b/src/test/java/com/networknt/schema/path/PathTypeTest.java similarity index 96% rename from src/test/java/com/networknt/schema/PathTypeTest.java rename to src/test/java/com/networknt/schema/path/PathTypeTest.java index 0f317e2b7..278bf4008 100644 --- a/src/test/java/com/networknt/schema/PathTypeTest.java +++ b/src/test/java/com/networknt/schema/path/PathTypeTest.java @@ -1,4 +1,4 @@ -package com.networknt.schema; +package com.networknt.schema.path; import static org.junit.jupiter.api.Assertions.*; diff --git a/src/test/java/com/networknt/schema/resource/DisallowSchemaLoaderTest.java b/src/test/java/com/networknt/schema/resource/DisallowSchemaLoaderTest.java deleted file mode 100644 index dde349e15..000000000 --- a/src/test/java/com/networknt/schema/resource/DisallowSchemaLoaderTest.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.networknt.schema.resource; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; - -import org.junit.jupiter.api.Test; - -import com.networknt.schema.InvalidSchemaException; -import com.networknt.schema.JsonSchemaFactory; -import com.networknt.schema.SchemaLocation; -import com.networknt.schema.SpecVersion.VersionFlag; - -/** - * Test for DisallowSchemaLoader. - */ -class DisallowSchemaLoaderTest { - - @Test - void integration() { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012, builder -> builder - .schemaLoaders(schemaLoaders -> schemaLoaders.add(DisallowSchemaLoader.getInstance()))); - InvalidSchemaException invalidSchemaException = assertThrows(InvalidSchemaException.class, - () -> factory.getSchema(SchemaLocation.of("classpath:schema/example-main.json"))); - assertEquals("classpath:schema/example-main.json", - invalidSchemaException.getError().getArguments()[0].toString()); - } - -} diff --git a/src/test/java/com/networknt/schema/resource/UriSchemaLoaderTest.java b/src/test/java/com/networknt/schema/resource/IriResourceLoaderTest.java similarity index 76% rename from src/test/java/com/networknt/schema/resource/UriSchemaLoaderTest.java rename to src/test/java/com/networknt/schema/resource/IriResourceLoaderTest.java index dc3e3f70f..04eab650e 100644 --- a/src/test/java/com/networknt/schema/resource/UriSchemaLoaderTest.java +++ b/src/test/java/com/networknt/schema/resource/IriResourceLoaderTest.java @@ -33,7 +33,7 @@ /** * Tests for URI schema Loader. */ -class UriSchemaLoaderTest { +class IriResourceLoaderTest { /** * This test should only be run manually so as not to always hit the remote * server. @@ -43,8 +43,8 @@ class UriSchemaLoaderTest { @Test @Disabled("manual") void shouldLoadAbsoluteIri() throws IOException { - UriSchemaLoader schemaLoader = new UriSchemaLoader(); - InputStreamSource inputStreamSource = schemaLoader.getSchema(AbsoluteIri.of("https://ç§ã®å›£ä½“ã‚‚.jp/")); + IriResourceLoader schemaLoader = new IriResourceLoader(); + InputStreamSource inputStreamSource = schemaLoader.getResource(AbsoluteIri.of("https://ç§ã®å›£ä½“ã‚‚.jp/")); try (InputStream inputStream = inputStreamSource.getInputStream()) { String result = new BufferedReader(new InputStreamReader(inputStream)).lines() .collect(Collectors.joining("\n")); @@ -54,13 +54,13 @@ void shouldLoadAbsoluteIri() throws IOException { @Test void shouldNotThrowAbsoluteIri() throws IOException { - UriSchemaLoader schemaLoader = new UriSchemaLoader(); - assertDoesNotThrow(() -> schemaLoader.getSchema(AbsoluteIri.of("https://ç§ã®å›£ä½“ã‚‚.jp/"))); + IriResourceLoader schemaLoader = new IriResourceLoader(); + assertDoesNotThrow(() -> schemaLoader.getResource(AbsoluteIri.of("https://ç§ã®å›£ä½“ã‚‚.jp/"))); } @Test void shouldThrowRelativeIri() throws IOException { - UriSchemaLoader schemaLoader = new UriSchemaLoader(); - assertThrows(IllegalArgumentException.class, () -> schemaLoader.getSchema(AbsoluteIri.of("ç§ã®å›£ä½“ã‚‚.jp/"))); + IriResourceLoader schemaLoader = new IriResourceLoader(); + assertThrows(IllegalArgumentException.class, () -> schemaLoader.getResource(AbsoluteIri.of("ç§ã®å›£ä½“ã‚‚.jp/"))); } } diff --git a/src/test/java/com/networknt/schema/resource/MapSchemaLoaderTest.java b/src/test/java/com/networknt/schema/resource/MapResourceLoaderTest.java similarity index 81% rename from src/test/java/com/networknt/schema/resource/MapSchemaLoaderTest.java rename to src/test/java/com/networknt/schema/resource/MapResourceLoaderTest.java index 9fe9a7078..ba02ed9fb 100644 --- a/src/test/java/com/networknt/schema/resource/MapSchemaLoaderTest.java +++ b/src/test/java/com/networknt/schema/resource/MapResourceLoaderTest.java @@ -27,7 +27,7 @@ import com.networknt.schema.AbsoluteIri; -class MapSchemaLoaderTest { +class MapResourceLoaderTest { static class Result { private final String schema; @@ -46,8 +46,8 @@ void testMappingsWithTwoFunctions() throws IOException { mappings.put("http://www.example.org/test.json", new Result("test")); mappings.put("http://www.example.org/hello.json", new Result("hello")); - MapSchemaLoader loader = new MapSchemaLoader(mappings::get, Result::getSchema); - InputStreamSource source = loader.getSchema(AbsoluteIri.of("http://www.example.org/test.json")); + MapResourceLoader loader = new MapResourceLoader(mappings::get, Result::getSchema); + InputStreamSource source = loader.getResource(AbsoluteIri.of("http://www.example.org/test.json")); try (InputStream inputStream = source.getInputStream()) { byte[] r = new byte[4]; inputStream.read(r); @@ -55,7 +55,7 @@ void testMappingsWithTwoFunctions() throws IOException { assertEquals("test", value); } - InputStreamSource result = loader.getSchema(AbsoluteIri.of("http://www.example.org/not-found.json")); + InputStreamSource result = loader.getResource(AbsoluteIri.of("http://www.example.org/not-found.json")); assertNull(result); } } diff --git a/src/test/java/com/networknt/schema/resource/MapSchemaMapperTest.java b/src/test/java/com/networknt/schema/resource/MapSchemaIdResolverTest.java similarity index 73% rename from src/test/java/com/networknt/schema/resource/MapSchemaMapperTest.java rename to src/test/java/com/networknt/schema/resource/MapSchemaIdResolverTest.java index d9697b6b1..896bf6299 100644 --- a/src/test/java/com/networknt/schema/resource/MapSchemaMapperTest.java +++ b/src/test/java/com/networknt/schema/resource/MapSchemaIdResolverTest.java @@ -21,15 +21,15 @@ import com.networknt.schema.AbsoluteIri; -class MapSchemaMapperTest { +class MapSchemaIdResolverTest { @Test void predicateMapping() { - MapSchemaMapper mapper = new MapSchemaMapper(test -> test.startsWith("http://www.example.org/"), + MapSchemaIdResolver mapper = new MapSchemaIdResolver(test -> test.startsWith("http://www.example.org/"), original -> original.replaceFirst("http://www.example.org/", "classpath:")); - AbsoluteIri result = mapper.map(AbsoluteIri.of("http://www.example.org/hello")); + AbsoluteIri result = mapper.resolve(AbsoluteIri.of("http://www.example.org/hello")); assertEquals("classpath:hello", result.toString()); - result = mapper.map(AbsoluteIri.of("notmatchingprefixhttp://www.example.org/hello")); + result = mapper.resolve(AbsoluteIri.of("notmatchingprefixhttp://www.example.org/hello")); assertNull(result); } diff --git a/src/test/java/com/networknt/schema/resource/MetaSchemaMapperTest.java b/src/test/java/com/networknt/schema/resource/MetaSchemaIdResolverTest.java similarity index 69% rename from src/test/java/com/networknt/schema/resource/MetaSchemaMapperTest.java rename to src/test/java/com/networknt/schema/resource/MetaSchemaIdResolverTest.java index dd8980455..8aac3c8ea 100644 --- a/src/test/java/com/networknt/schema/resource/MetaSchemaMapperTest.java +++ b/src/test/java/com/networknt/schema/resource/MetaSchemaIdResolverTest.java @@ -25,19 +25,19 @@ import org.junit.jupiter.params.provider.EnumSource; import com.networknt.schema.AbsoluteIri; -import com.networknt.schema.SchemaId; +import com.networknt.schema.dialect.DialectId; /** * MetaSchemaMapperTest. */ -class MetaSchemaMapperTest { +class MetaSchemaIdResolverTest { enum MapInput { - V4(SchemaId.V4), - V6(SchemaId.V6), - V7(SchemaId.V7), - V201909(SchemaId.V201909), - V202012(SchemaId.V202012); + V4(DialectId.DRAFT_4), + V6(DialectId.DRAFT_6), + V7(DialectId.DRAFT_7), + V201909(DialectId.DRAFT_2019_09), + V202012(DialectId.DRAFT_2020_12); String iri; @@ -49,10 +49,10 @@ enum MapInput { @ParameterizedTest @EnumSource(MapInput.class) void map(MapInput input) throws IOException { - MetaSchemaMapper mapper = new MetaSchemaMapper(); - AbsoluteIri result = mapper.map(AbsoluteIri.of(input.iri)); - ClasspathSchemaLoader loader = new ClasspathSchemaLoader(); - InputStreamSource source = loader.getSchema(result); + MetaSchemaIdResolver mapper = new MetaSchemaIdResolver(); + AbsoluteIri result = mapper.resolve(AbsoluteIri.of(input.iri)); + ClasspathResourceLoader loader = new ClasspathResourceLoader(); + InputStreamSource source = loader.getResource(result); assertNotNull(source); try (InputStream inputStream = source.getInputStream()) { inputStream.read(); diff --git a/src/test/java/com/networknt/schema/resource/AllowSchemaLoaderTest.java b/src/test/java/com/networknt/schema/resource/SchemaLoaderTest.java similarity index 51% rename from src/test/java/com/networknt/schema/resource/AllowSchemaLoaderTest.java rename to src/test/java/com/networknt/schema/resource/SchemaLoaderTest.java index 331a96b15..4174a7ba8 100644 --- a/src/test/java/com/networknt/schema/resource/AllowSchemaLoaderTest.java +++ b/src/test/java/com/networknt/schema/resource/SchemaLoaderTest.java @@ -22,27 +22,31 @@ import org.junit.jupiter.api.Test; import com.networknt.schema.InvalidSchemaException; -import com.networknt.schema.JsonSchema; -import com.networknt.schema.JsonSchemaFactory; +import com.networknt.schema.Schema; import com.networknt.schema.SchemaLocation; -import com.networknt.schema.SpecVersion.VersionFlag; - -/** - * Test for AllowSchemaLoader. - */ -class AllowSchemaLoaderTest { +import com.networknt.schema.SchemaRegistry; +import com.networknt.schema.SpecificationVersion; +public class SchemaLoaderTest { @Test - void integration() { - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012, - builder -> builder.schemaLoaders(schemaLoaders -> schemaLoaders - .add(new AllowSchemaLoader(iri -> iri.toString().startsWith("classpath:"))))); + void allow() { + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12, + builder -> builder.schemaLoader( + schemaLoader -> schemaLoader.allow(iri -> iri.toString().startsWith("classpath:")))); InvalidSchemaException invalidSchemaException = assertThrows(InvalidSchemaException.class, () -> factory.getSchema(SchemaLocation.of("http://www.example.org/schema"))); - assertEquals("http://www.example.org/schema", - invalidSchemaException.getError().getArguments()[0].toString()); - JsonSchema schema = factory.getSchema(SchemaLocation.of("classpath:schema/example-main.json")); + assertEquals("http://www.example.org/schema", invalidSchemaException.getError().getArguments()[0].toString()); + Schema schema = factory.getSchema(SchemaLocation.of("classpath:schema/example-main.json")); assertNotNull(schema); } + @Test + void block() { + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12, + builder -> builder.schemaLoader(schemaLoader -> schemaLoader.block(iri -> true))); + InvalidSchemaException invalidSchemaException = assertThrows(InvalidSchemaException.class, + () -> factory.getSchema(SchemaLocation.of("classpath:schema/example-main.json"))); + assertEquals("classpath:schema/example-main.json", + invalidSchemaException.getError().getArguments()[0].toString()); + } } diff --git a/src/test/java/com/networknt/schema/serialization/DefaultJsonNodeReaderTest.java b/src/test/java/com/networknt/schema/serialization/DefaultNodeReaderTest.java similarity index 79% rename from src/test/java/com/networknt/schema/serialization/DefaultJsonNodeReaderTest.java rename to src/test/java/com/networknt/schema/serialization/DefaultNodeReaderTest.java index b508cf167..e6a61f0e9 100644 --- a/src/test/java/com/networknt/schema/serialization/DefaultJsonNodeReaderTest.java +++ b/src/test/java/com/networknt/schema/serialization/DefaultNodeReaderTest.java @@ -29,7 +29,7 @@ /** * Test for Default Object Reader. */ -class DefaultJsonNodeReaderTest { +class DefaultNodeReaderTest { @Test void location() throws JsonParseException, IOException { String schemaData = "{\r\n" @@ -41,19 +41,19 @@ void location() throws JsonParseException, IOException { + " }\r\n" + " }\r\n" + "}"; - JsonNode jsonNode = JsonNodeReader.builder().locationAware().build().readTree(schemaData, InputFormat.JSON); + JsonNode jsonNode = NodeReader.builder().locationAware().build().readTree(schemaData, InputFormat.JSON); JsonNode idNode = jsonNode.at("/$id"); - JsonLocation location = JsonNodes.tokenLocationOf(idNode); + JsonLocation location = JsonNodes.tokenStreamLocationOf(idNode); assertEquals(2, location.getLineNr()); assertEquals(10, location.getColumnNr()); JsonNode formatNode = jsonNode.at("/properties/startDate/format"); - location = JsonNodes.tokenLocationOf(formatNode); + location = JsonNodes.tokenStreamLocationOf(formatNode); assertEquals(5, location.getLineNr()); assertEquals(17, location.getColumnNr()); JsonNode minLengthNode = jsonNode.at("/properties/startDate/minLength"); - location = JsonNodes.tokenLocationOf(minLengthNode); + location = JsonNodes.tokenStreamLocationOf(minLengthNode); assertEquals(6, location.getLineNr()); assertEquals(20, location.getColumnNr()); } @@ -69,10 +69,10 @@ void jsonLocation() throws IOException { + " }\r\n" + " }\r\n" + "}"; - JsonNode jsonNode = JsonNodeReader.builder().locationAware().build().readTree(schemaData, InputFormat.JSON); + JsonNode jsonNode = NodeReader.builder().locationAware().build().readTree(schemaData, InputFormat.JSON); - JsonLocation formatSchemaNodeTokenLocation = JsonNodes.tokenLocationOf(jsonNode.at("/properties/startDate/format")); - JsonLocation minLengthSchemaNodeTokenLocation = JsonNodes.tokenLocationOf(jsonNode.at("/properties/startDate/minLength")); + JsonLocation formatSchemaNodeTokenLocation = JsonNodes.tokenStreamLocationOf(jsonNode.at("/properties/startDate/format")); + JsonLocation minLengthSchemaNodeTokenLocation = JsonNodes.tokenStreamLocationOf(jsonNode.at("/properties/startDate/minLength")); assertEquals(5, formatSchemaNodeTokenLocation.getLineNr()); assertEquals(17, formatSchemaNodeTokenLocation.getColumnNr()); @@ -89,10 +89,10 @@ void yamlLocation() throws IOException { + " startDate:\r\n" + " format: 'date'\r\n" + " minLength: 6\r\n"; - JsonNode jsonNode = JsonNodeReader.builder().locationAware().build().readTree(schemaData, InputFormat.YAML); + JsonNode jsonNode = NodeReader.builder().locationAware().build().readTree(schemaData, InputFormat.YAML); - JsonLocation formatSchemaNodeTokenLocation = JsonNodes.tokenLocationOf(jsonNode.at("/properties/startDate/format")); - JsonLocation minLengthSchemaNodeTokenLocation = JsonNodes.tokenLocationOf(jsonNode.at("/properties/startDate/minLength")); + JsonLocation formatSchemaNodeTokenLocation = JsonNodes.tokenStreamLocationOf(jsonNode.at("/properties/startDate/format")); + JsonLocation minLengthSchemaNodeTokenLocation = JsonNodes.tokenStreamLocationOf(jsonNode.at("/properties/startDate/minLength")); assertEquals(5, formatSchemaNodeTokenLocation.getLineNr()); assertEquals(13, formatSchemaNodeTokenLocation.getColumnNr()); diff --git a/src/test/java/com/networknt/schema/suite/TestSpec.java b/src/test/java/com/networknt/schema/suite/TestSpec.java index 0b03625c7..e06e27f9f 100644 --- a/src/test/java/com/networknt/schema/suite/TestSpec.java +++ b/src/test/java/com/networknt/schema/suite/TestSpec.java @@ -3,7 +3,7 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.JsonNode; -import com.networknt.schema.SchemaValidatorsConfig; +import com.networknt.schema.SchemaRegistryConfig; import java.util.Collections; import java.util.HashMap; @@ -56,7 +56,7 @@ public class TestSpec { * This is an extension of the schema used to describe tests in the compliance suite *

*/ - private final Set validationMessages; + private final Set errors; /** * Indicates whether this test should be executed @@ -100,7 +100,7 @@ public class TestSpec { private final RegexKind regex; /** - * Config information to be provided for {@link SchemaValidatorsConfig} with which schema can be validated + * Config information to be provided for {@link SchemaRegistryConfig} with which schema can be validated *

* This is an extension of the schema used to describe tests in the * compliance suite @@ -120,7 +120,7 @@ public class TestSpec { * @param data The instance which should be validated against the schema in "schema" (Required) * @param valid Whether the validation process of this instance should consider the instance valid or not (Required) * @param strictness A mapping of how strict a keyword's validators should be. - * @param validationMessages A sequence of validation messages expected from testing data against the schema + * @param errors A sequence of validation messages expected from testing data against the schema * @param disabled Indicates whether this test should be executed (Defaults to FALSE) * @param isTypeLoose Indicates whether the test should consider a strict definition of an enum (Defaults to FALSE) */ @@ -132,7 +132,7 @@ public TestSpec( @JsonProperty("data") JsonNode data, @JsonProperty("valid") boolean valid, @JsonProperty("strictness") Map strictness, - @JsonProperty("validationMessages") Set validationMessages, + @JsonProperty("errors") Set errors, @JsonProperty("isTypeLoose") Boolean isTypeLoose, @JsonProperty("disabled") Boolean disabled, @JsonProperty("reason") String reason, @@ -143,7 +143,7 @@ public TestSpec( this.config = config; this.data = data; this.valid = valid; - this.validationMessages = validationMessages; + this.errors = errors; this.disabled = Boolean.TRUE.equals(disabled); this.reason = reason; this.typeLoose = Boolean.TRUE.equals(isTypeLoose); @@ -186,7 +186,7 @@ public String getComment() { /** - * Config information to be provided for {@link SchemaValidatorsConfig} with which schema can be validated + * Config information to be provided for {@link SchemaRegistryConfig} with which schema can be validated */ public Map getConfig() { return config; @@ -237,8 +237,8 @@ public Map getStrictness() { * * @return a non-null list of expected validation messages */ - public Set getValidationMessages() { - return new HashSet<>(null != this.validationMessages ? this.validationMessages : Collections.emptySet()); + public Set getErrors() { + return new HashSet<>(null != this.errors ? this.errors : Collections.emptySet()); } /** diff --git a/src/test/java/com/networknt/schema/utils/JsonNodesTest.java b/src/test/java/com/networknt/schema/utils/JsonNodesTest.java index bb8184366..fef8bfc6f 100644 --- a/src/test/java/com/networknt/schema/utils/JsonNodesTest.java +++ b/src/test/java/com/networknt/schema/utils/JsonNodesTest.java @@ -32,13 +32,12 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.networknt.schema.InputFormat; -import com.networknt.schema.JsonSchema; -import com.networknt.schema.JsonSchemaFactory; -import com.networknt.schema.SchemaValidatorsConfig; -import com.networknt.schema.SpecVersion.VersionFlag; -import com.networknt.schema.ValidationMessage; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaRegistry; +import com.networknt.schema.SpecificationVersion; +import com.networknt.schema.Error; import com.networknt.schema.serialization.JsonMapperFactory; -import com.networknt.schema.serialization.JsonNodeReader; +import com.networknt.schema.serialization.NodeReader; import com.networknt.schema.serialization.node.LocationJsonNodeFactoryFactory; /** * Tests for JsonNodes. @@ -58,17 +57,17 @@ void location() throws JsonParseException, IOException { JsonNode jsonNode = JsonNodes.readTree(JsonMapperFactory.getInstance(), schemaData, LocationJsonNodeFactoryFactory.getInstance()); JsonNode idNode = jsonNode.at("/$id"); - JsonLocation location = JsonNodes.tokenLocationOf(idNode); + JsonLocation location = JsonNodes.tokenStreamLocationOf(idNode); assertEquals(2, location.getLineNr()); assertEquals(10, location.getColumnNr()); JsonNode formatNode = jsonNode.at("/properties/startDate/format"); - location = JsonNodes.tokenLocationOf(formatNode); + location = JsonNodes.tokenStreamLocationOf(formatNode); assertEquals(5, location.getLineNr()); assertEquals(17, location.getColumnNr()); JsonNode minLengthNode = jsonNode.at("/properties/startDate/minLength"); - location = JsonNodes.tokenLocationOf(minLengthNode); + location = JsonNodes.tokenStreamLocationOf(minLengthNode); assertEquals(6, location.getLineNr()); assertEquals(20, location.getColumnNr()); } @@ -87,22 +86,21 @@ void jsonLocation() { String inputData = "{\r\n" + " \"startDate\": \"1\"\r\n" + "}"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012, - builder -> builder.jsonNodeReader(JsonNodeReader.builder().locationAware().build())); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema schema = factory.getSchema(schemaData, InputFormat.JSON, config); - List messages = schema.validate(inputData, InputFormat.JSON, executionContext -> { - executionContext.getExecutionConfig().setFormatAssertionsEnabled(true); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12, + builder -> builder.nodeReader(nodeReader -> nodeReader.locationAware())); + Schema schema = factory.getSchema(schemaData, InputFormat.JSON); + List messages = schema.validate(inputData, InputFormat.JSON, executionContext -> { + executionContext.executionConfig(executionConfig -> executionConfig.formatAssertionsEnabled(true)); }); - List list = messages.stream().collect(Collectors.toList()); - ValidationMessage format = list.get(0); - JsonLocation formatInstanceNodeTokenLocation = JsonNodes.tokenLocationOf(format.getInstanceNode()); - JsonLocation formatSchemaNodeTokenLocation = JsonNodes.tokenLocationOf(format.getSchemaNode()); - ValidationMessage minLength = list.get(1); - JsonLocation minLengthInstanceNodeTokenLocation = JsonNodes.tokenLocationOf(minLength.getInstanceNode()); - JsonLocation minLengthSchemaNodeTokenLocation = JsonNodes.tokenLocationOf(minLength.getSchemaNode()); + List list = messages.stream().collect(Collectors.toList()); + Error format = list.get(0); + JsonLocation formatInstanceNodeTokenLocation = JsonNodes.tokenStreamLocationOf(format.getInstanceNode()); + JsonLocation formatSchemaNodeTokenLocation = JsonNodes.tokenStreamLocationOf(format.getSchemaNode()); + Error minLength = list.get(1); + JsonLocation minLengthInstanceNodeTokenLocation = JsonNodes.tokenStreamLocationOf(minLength.getInstanceNode()); + JsonLocation minLengthSchemaNodeTokenLocation = JsonNodes.tokenStreamLocationOf(minLength.getSchemaNode()); - assertEquals("format", format.getType()); + assertEquals("format", format.getKeyword()); assertEquals("date", format.getSchemaNode().asText()); assertEquals(5, formatSchemaNodeTokenLocation.getLineNr()); @@ -112,7 +110,7 @@ void jsonLocation() { assertEquals(2, formatInstanceNodeTokenLocation.getLineNr()); assertEquals(16, formatInstanceNodeTokenLocation.getColumnNr()); - assertEquals("minLength", minLength.getType()); + assertEquals("minLength", minLength.getKeyword()); assertEquals("6", minLength.getSchemaNode().asText()); assertEquals(6, minLengthSchemaNodeTokenLocation.getLineNr()); @@ -133,22 +131,21 @@ void yamlLocation() { + " minLength: 6\r\n"; String inputData = "---\r\n" + "startDate: '1'\r\n"; - JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012, - builder -> builder.jsonNodeReader(JsonNodeReader.builder().locationAware().build())); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build(); - JsonSchema schema = factory.getSchema(schemaData, InputFormat.YAML, config); - List messages = schema.validate(inputData, InputFormat.YAML, executionContext -> { - executionContext.getExecutionConfig().setFormatAssertionsEnabled(true); + SchemaRegistry factory = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12, + builder -> builder.nodeReader(NodeReader.builder().locationAware().build())); + Schema schema = factory.getSchema(schemaData, InputFormat.YAML); + List messages = schema.validate(inputData, InputFormat.YAML, executionContext -> { + executionContext.executionConfig(executionConfig -> executionConfig.formatAssertionsEnabled(true)); }); - List list = messages.stream().collect(Collectors.toList()); - ValidationMessage format = list.get(0); - JsonLocation formatInstanceNodeTokenLocation = JsonNodes.tokenLocationOf(format.getInstanceNode()); - JsonLocation formatSchemaNodeTokenLocation = JsonNodes.tokenLocationOf(format.getSchemaNode()); - ValidationMessage minLength = list.get(1); - JsonLocation minLengthInstanceNodeTokenLocation = JsonNodes.tokenLocationOf(minLength.getInstanceNode()); - JsonLocation minLengthSchemaNodeTokenLocation = JsonNodes.tokenLocationOf(minLength.getSchemaNode()); + List list = messages.stream().collect(Collectors.toList()); + Error format = list.get(0); + JsonLocation formatInstanceNodeTokenLocation = JsonNodes.tokenStreamLocationOf(format.getInstanceNode()); + JsonLocation formatSchemaNodeTokenLocation = JsonNodes.tokenStreamLocationOf(format.getSchemaNode()); + Error minLength = list.get(1); + JsonLocation minLengthInstanceNodeTokenLocation = JsonNodes.tokenStreamLocationOf(minLength.getInstanceNode()); + JsonLocation minLengthSchemaNodeTokenLocation = JsonNodes.tokenStreamLocationOf(minLength.getSchemaNode()); - assertEquals("format", format.getType()); + assertEquals("format", format.getKeyword()); assertEquals("date", format.getSchemaNode().asText()); assertEquals(5, formatSchemaNodeTokenLocation.getLineNr()); @@ -158,7 +155,7 @@ void yamlLocation() { assertEquals(2, formatInstanceNodeTokenLocation.getLineNr()); assertEquals(12, formatInstanceNodeTokenLocation.getColumnNr()); - assertEquals("minLength", minLength.getType()); + assertEquals("minLength", minLength.getKeyword()); assertEquals("6", minLength.getSchemaNode().asText()); assertEquals(6, minLengthSchemaNodeTokenLocation.getLineNr()); @@ -194,16 +191,16 @@ void types() { .enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS); JsonNode root = JsonNodes.readTree(objectMapper, json, LocationJsonNodeFactoryFactory.getInstance()); JsonNode numberNode = root.at("/properties/number"); - assertEquals(3, JsonNodes.tokenLocationOf(numberNode).getLineNr()); + assertEquals(3, JsonNodes.tokenStreamLocationOf(numberNode).getLineNr()); JsonNode stringNode = root.at("/properties/string"); - assertEquals(4, JsonNodes.tokenLocationOf(stringNode).getLineNr()); + assertEquals(4, JsonNodes.tokenStreamLocationOf(stringNode).getLineNr()); JsonNode booleanNode = root.at("/properties/boolean"); - assertEquals(5, JsonNodes.tokenLocationOf(booleanNode).getLineNr()); + assertEquals(5, JsonNodes.tokenStreamLocationOf(booleanNode).getLineNr()); JsonNode arrayNode = root.at("/properties/array"); - assertEquals(6, JsonNodes.tokenLocationOf(arrayNode).getLineNr()); + assertEquals(6, JsonNodes.tokenStreamLocationOf(arrayNode).getLineNr()); JsonNode objectNode = root.at("/properties/object"); - assertEquals(7, JsonNodes.tokenLocationOf(objectNode).getLineNr()); + assertEquals(7, JsonNodes.tokenStreamLocationOf(objectNode).getLineNr()); JsonNode nullNode = root.at("/properties/null"); - assertEquals(8, JsonNodes.tokenLocationOf(nullNode).getLineNr()); + assertEquals(8, JsonNodes.tokenStreamLocationOf(nullNode).getLineNr()); } } diff --git a/src/test/java/com/networknt/schema/utils/SetViewTest.java b/src/test/java/com/networknt/schema/utils/SetViewTest.java deleted file mode 100644 index 7b039cc85..000000000 --- a/src/test/java/com/networknt/schema/utils/SetViewTest.java +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright (c) 2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.networknt.schema.utils; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.util.Collections; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -import org.junit.jupiter.api.Test; - -/** - * Test for SetView. - */ -class SetViewTest { - - @Test - void testUnion() { - Set a = new LinkedHashSet<>(); - Set b = new LinkedHashSet<>(); - Set c = new LinkedHashSet<>(); - a.add(1); - a.add(2); - c.add(3); - - Set view = new SetView().union(a).union(b).union(c); - assertEquals(3, view.size()); - List values = view.stream().collect(Collectors.toList()); - assertEquals(1, values.get(0)); - assertEquals(2, values.get(1)); - assertEquals(3, values.get(2)); - } - - @Test - void testToString() { - Set a = new LinkedHashSet<>(); - Set b = new LinkedHashSet<>(); - Set c = new LinkedHashSet<>(); - a.add(1); - a.add(2); - c.add(3); - - Set view = new SetView().union(a).union(b).union(c); - String value = view.toString(); - assertEquals("[1, 2, 3]", value); - } - - @Test - void testIsEmpty() { - Set a = new LinkedHashSet<>(); - a.add(1); - a.add(2); - - SetView view = new SetView<>(); - assertTrue(view.isEmpty()); - view.union(a); - assertFalse(view.isEmpty()); - } - - @Test - void testEquals() { - Set a = new LinkedHashSet<>(); - Set b = new LinkedHashSet<>(); - Set c = new LinkedHashSet<>(); - a.add(1); - a.add(2); - c.add(3); - - Set view = new SetView().union(a).union(b).union(c); - assertEquals(3, view.size()); - - Set result = new HashSet<>(); - result.add(1); - result.add(2); - result.add(3); - assertEquals(result, view); - } - - @Test - void testContains() { - Set a = new LinkedHashSet<>(); - Set b = new LinkedHashSet<>(); - Set c = new LinkedHashSet<>(); - a.add(1); - a.add(2); - c.add(3); - - Set view = new SetView().union(a).union(b).union(c); - assertTrue(view.contains(1)); - assertTrue(view.contains(2)); - assertTrue(view.contains(3)); - assertFalse(view.contains(4)); - } - - @Test - void testContainsAll() { - Set a = new LinkedHashSet<>(); - Set b = new LinkedHashSet<>(); - Set c = new LinkedHashSet<>(); - a.add(1); - a.add(2); - c.add(3); - - Set view = new SetView().union(a).union(b).union(c); - Set result = new HashSet<>(); - result.add(1); - result.add(2); - result.add(3); - assertTrue(view.containsAll(result)); - result.add(4); - assertFalse(view.containsAll(result)); - } - - @Test - void testToArray() { - Set a = new LinkedHashSet<>(); - Set b = new LinkedHashSet<>(); - Set c = new LinkedHashSet<>(); - a.add(1); - a.add(2); - c.add(3); - - Set view = new SetView().union(a).union(b).union(c); - assertEquals(3, view.size()); - - Object[] result = view.toArray(); - assertEquals(3, result.length); - assertEquals(1, result[0]); - assertEquals(2, result[1]); - assertEquals(3, result[2]); - } - - @Test - void testToArrayArray() { - Set a = new LinkedHashSet<>(); - Set b = new LinkedHashSet<>(); - Set c = new LinkedHashSet<>(); - a.add(1); - a.add(2); - c.add(3); - - Set view = new SetView().union(a).union(b).union(c); - assertEquals(3, view.size()); - - Integer[] result = view.toArray(new Integer[0]); - assertEquals(3, result.length); - assertEquals(1, result[0]); - assertEquals(2, result[1]); - assertEquals(3, result[2]); - } - - @Test - void testAddAll() { - Set view = new SetView<>(); - assertThrows(UnsupportedOperationException.class, () -> view.addAll(Collections.singleton(1))); - } - - @Test - void testAdd() { - Set view = new SetView<>(); - assertThrows(UnsupportedOperationException.class, () -> view.add(1)); - } - - @Test - void testClear() { - Set view = new SetView<>(); - assertThrows(UnsupportedOperationException.class, () -> view.clear()); - } - - @Test - void testRemove() { - Set view = new SetView<>(); - assertThrows(UnsupportedOperationException.class, () -> view.remove(1)); - } - - @Test - void testRemoveAll() { - Set view = new SetView<>(); - assertThrows(UnsupportedOperationException.class, () -> view.removeAll(Collections.singleton(1))); - } - - @Test - void testRetainAll() { - Set view = new SetView<>(); - assertThrows(UnsupportedOperationException.class, () -> view.retainAll(Collections.singleton(1))); - } - -} diff --git a/src/test/java/com/networknt/schema/StringCheckerTest.java b/src/test/java/com/networknt/schema/utils/StringsTest.java similarity index 88% rename from src/test/java/com/networknt/schema/StringCheckerTest.java rename to src/test/java/com/networknt/schema/utils/StringsTest.java index 6978a03e1..cac42ceda 100755 --- a/src/test/java/com/networknt/schema/StringCheckerTest.java +++ b/src/test/java/com/networknt/schema/utils/StringsTest.java @@ -14,15 +14,14 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.utils; import org.junit.jupiter.api.Test; -import static com.networknt.schema.utils.StringChecker.isNumeric; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; -class StringCheckerTest { +class StringsTest { private static final String[] validNumericValues = { "1", "-1", "1.1", "-1.1", "0E+1", "0E-1", "0E1", "-0E+1", "-0E-1", "-0E1", "0.1E+1", "0.1E-1", "0.1E1", @@ -39,14 +38,14 @@ class StringCheckerTest { @Test void testNumericValues() { for (String validValue : validNumericValues) { - assertTrue(isNumeric(validValue), validValue); + assertTrue(Strings.isNumeric(validValue), validValue); } } @Test void testNonNumericValues() { for (String invalidValue : invalidNumericValues) { - assertFalse(isNumeric(invalidValue), invalidValue); + assertFalse(Strings.isNumeric(invalidValue), invalidValue); } } } diff --git a/src/test/java/com/networknt/schema/CachedSupplierTest.java b/src/test/java/com/networknt/schema/utils/ThreadSafeCachingSupplierTest.java similarity index 88% rename from src/test/java/com/networknt/schema/CachedSupplierTest.java rename to src/test/java/com/networknt/schema/utils/ThreadSafeCachingSupplierTest.java index f0b8cfab5..3c52f11a0 100644 --- a/src/test/java/com/networknt/schema/CachedSupplierTest.java +++ b/src/test/java/com/networknt/schema/utils/ThreadSafeCachingSupplierTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.utils; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; @@ -28,10 +28,10 @@ /** * Test for CachedSupplier. */ -class CachedSupplierTest { +class ThreadSafeCachingSupplierTest { @Test void nullValue() { - CachedSupplier supplier = new CachedSupplier<>(null); + ThreadSafeCachingSupplier supplier = new ThreadSafeCachingSupplier<>(null); assertNull(supplier.get()); } @@ -39,7 +39,7 @@ void nullValue() { void concurrency() throws Exception { AtomicInteger value = new AtomicInteger(0); - CachedSupplier supplier = new CachedSupplier<>(() -> { + ThreadSafeCachingSupplier supplier = new ThreadSafeCachingSupplier<>(() -> { return value.addAndGet(1); }); Exception[] instance = new Exception[1]; diff --git a/src/test/java/com/networknt/schema/VocabularyTest.java b/src/test/java/com/networknt/schema/vocabulary/VocabularyTest.java similarity index 70% rename from src/test/java/com/networknt/schema/VocabularyTest.java rename to src/test/java/com/networknt/schema/vocabulary/VocabularyTest.java index 57da5b7a9..b90e5d205 100644 --- a/src/test/java/com/networknt/schema/VocabularyTest.java +++ b/src/test/java/com/networknt/schema/vocabulary/VocabularyTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.networknt.schema; +package com.networknt.schema.vocabulary; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -25,7 +25,17 @@ import org.junit.jupiter.api.Test; -import com.networknt.schema.SpecVersion.VersionFlag; +import com.networknt.schema.Error; +import com.networknt.schema.InputFormat; +import com.networknt.schema.InvalidSchemaException; +import com.networknt.schema.OutputFormat; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaRegistry; +import com.networknt.schema.SpecificationVersion; +import com.networknt.schema.dialect.BasicDialectRegistry; +import com.networknt.schema.dialect.Dialect; +import com.networknt.schema.dialect.Dialects; +import com.networknt.schema.keyword.AnnotationKeyword; import com.networknt.schema.output.OutputUnit; /** @@ -57,9 +67,9 @@ void noValidation() { + " }\r\n" + " }\r\n" + "}"; - JsonSchema schema = JsonSchemaFactory - .getInstance(VersionFlag.V202012, - builder -> builder.schemaLoaders(schemaLoaders -> schemaLoaders.schemas(Collections + Schema schema = SchemaRegistry + .withDefaultDialectId("https://www.example.com/no-validation-no-format/schema", + builder -> builder.resourceLoaders(resourceLoaders -> resourceLoaders.resources(Collections .singletonMap("https://www.example.com/no-validation-no-format/schema", metaSchemaData)))) .getSchema(schemaData); @@ -68,21 +78,21 @@ void noValidation() { + " \"numberProperty\": 1\r\n" + "}"; - List messages = schema.validate(inputDataNoValidation, InputFormat.JSON); + List messages = schema.validate(inputDataNoValidation, InputFormat.JSON); assertEquals(0, messages.size()); // Set validation vocab - schema = JsonSchemaFactory - .getInstance(VersionFlag.V202012, - builder -> builder.schemaLoaders(schemaLoaders -> schemaLoaders.schemas(Collections + schema = SchemaRegistry + .withDefaultDialectId("https://www.example.com/no-validation-no-format/schema", + builder -> builder.resourceLoaders(resourceLoaders -> resourceLoaders.resources(Collections .singletonMap("https://www.example.com/no-validation-no-format/schema", metaSchemaData.replace("https://www.example.com/vocab/validation", - Vocabulary.V202012_VALIDATION.getIri()))))) + Vocabulary.DRAFT_2020_12_VALIDATION.getId()))))) .getSchema(schemaData); messages = schema.validate(inputDataNoValidation, InputFormat.JSON); assertEquals(1, messages.size()); - assertEquals("minimum", messages.iterator().next().getType()); - assertEquals(VersionFlag.V202012, schema.getValidationContext().activeDialect().get()); + assertEquals("minimum", messages.iterator().next().getKeyword()); + assertEquals(SpecificationVersion.DRAFT_2020_12, schema.getSchemaContext().getDialect().getSpecificationVersion()); } @Test @@ -109,9 +119,9 @@ void noFormatValidation() { + " }\r\n" + " }\r\n" + "}"; - JsonSchema schema = JsonSchemaFactory - .getInstance(VersionFlag.V202012, - builder -> builder.schemaLoaders(schemaLoaders -> schemaLoaders.schemas(Collections + Schema schema = SchemaRegistry + .withDefaultDialectId("https://www.example.com/no-validation-no-format/schema", + builder -> builder.resourceLoaders(resourceLoaders -> resourceLoaders.resources(Collections .singletonMap("https://www.example.com/no-validation-no-format/schema", metaSchemaData)))) .getSchema(schemaData); @@ -120,21 +130,21 @@ void noFormatValidation() { + " \"dateProperty\": \"hello\"\r\n" + "}"; - List messages = schema.validate(inputDataNoValidation, InputFormat.JSON, - executionContext -> executionContext.getExecutionConfig().setFormatAssertionsEnabled(true)); + List messages = schema.validate(inputDataNoValidation, InputFormat.JSON, + executionContext -> executionContext.executionConfig(executionConfig -> executionConfig.formatAssertionsEnabled(true))); assertEquals(0, messages.size()); - + // Set format assertion vocab - schema = JsonSchemaFactory - .getInstance(VersionFlag.V202012, - builder -> builder.schemaLoaders(schemaLoaders -> schemaLoaders.schemas(Collections + schema = SchemaRegistry + .withDefaultDialectId("https://www.example.com/no-validation-no-format/schema", + builder -> builder.resourceLoaders(resourceLoaders -> resourceLoaders.resources(Collections .singletonMap("https://www.example.com/no-validation-no-format/schema", metaSchemaData.replace("https://www.example.com/vocab/format", - Vocabulary.V202012_FORMAT_ASSERTION.getIri()))))) + Vocabulary.DRAFT_2020_12_FORMAT_ASSERTION.getId()))))) .getSchema(schemaData); messages = schema.validate(inputDataNoValidation, InputFormat.JSON); assertEquals(1, messages.size()); - assertEquals("format", messages.iterator().next().getType()); + assertEquals("format", messages.iterator().next().getKeyword()); } @Test @@ -161,9 +171,9 @@ void requiredUnknownVocabulary() { + " }\r\n" + " }\r\n" + "}"; - JsonSchemaFactory factory = JsonSchemaFactory - .getInstance(VersionFlag.V202012, - builder -> builder.schemaLoaders(schemaLoaders -> schemaLoaders.schemas(Collections + SchemaRegistry factory = SchemaRegistry + .withDefaultDialectId("https://www.example.com/no-validation-no-format/schema", + builder -> builder.resourceLoaders(resourceLoaders -> resourceLoaders.resources(Collections .singletonMap("https://www.example.com/no-validation-no-format/schema", metaSchemaData)))); assertThrows(InvalidSchemaException.class, () -> factory.getSchema(schemaData)); @@ -193,27 +203,27 @@ void customVocabulary() { + " }\r\n" + " }\r\n" + "}"; - VocabularyFactory vocabularyFactory = uri -> { - if ("https://www.example.com/vocab/format".equals(uri)) { + VocabularyRegistry vocabularyRegistry = id -> { + if ("https://www.example.com/vocab/format".equals(id)) { return new Vocabulary("https://www.example.com/vocab/format", new AnnotationKeyword("hello")); } return null; }; - JsonMetaSchema metaSchema = JsonMetaSchema - .builder(JsonMetaSchema.getV202012().getIri(), JsonMetaSchema.getV202012()) - .vocabularyFactory(vocabularyFactory) + Dialect dialect = Dialect + .builder("https://www.example.com/no-validation-no-format/schema", Dialects.getDraft202012()) + .vocabularyRegistry(vocabularyRegistry) .build(); - JsonSchemaFactory factory = JsonSchemaFactory - .getInstance(VersionFlag.V202012, - builder -> builder.metaSchema(metaSchema).schemaLoaders(schemaLoaders -> schemaLoaders.schemas(Collections + SchemaRegistry schemaRegistry = SchemaRegistry + .withDefaultDialect(SpecificationVersion.DRAFT_2020_12, + builder -> builder.dialectRegistry(new BasicDialectRegistry(dialect)).resourceLoaders(resourceLoaders -> resourceLoaders.resources(Collections .singletonMap("https://www.example.com/no-validation-no-format/schema", metaSchemaData)))); - JsonSchema schema = factory.getSchema(schemaData); + Schema schema = schemaRegistry.getSchema(schemaData); OutputUnit outputUnit = schema.validate("{}", InputFormat.JSON, OutputFormat.HIERARCHICAL, executionContext -> { - executionContext.getExecutionConfig().setAnnotationCollectionEnabled(true); - executionContext.getExecutionConfig().setAnnotationCollectionFilter(keyword -> true); - }); + executionContext.executionConfig(executionConfig -> executionConfig + .annotationCollectionEnabled(true).annotationCollectionFilter(keyword -> true)); + }); assertNotNull(outputUnit.getAnnotations().get("hello")); } } diff --git a/src/test/java/com/networknt/schema/walk/JsonSchemaWalkListenerTest.java b/src/test/java/com/networknt/schema/walk/WalkListenerTest.java similarity index 81% rename from src/test/java/com/networknt/schema/walk/JsonSchemaWalkListenerTest.java rename to src/test/java/com/networknt/schema/walk/WalkListenerTest.java index f8f4db5d0..c3efecda7 100644 --- a/src/test/java/com/networknt/schema/walk/JsonSchemaWalkListenerTest.java +++ b/src/test/java/com/networknt/schema/walk/WalkListenerTest.java @@ -33,30 +33,28 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.JsonNodeFactory; import com.fasterxml.jackson.databind.node.ObjectNode; -import com.networknt.schema.ApplyDefaultsStrategy; import com.networknt.schema.InputFormat; -import com.networknt.schema.ItemsValidator; -import com.networknt.schema.ItemsValidator202012; -import com.networknt.schema.JsonNodePath; -import com.networknt.schema.JsonSchema; -import com.networknt.schema.JsonSchemaFactory; -import com.networknt.schema.JsonSchemaRef; -import com.networknt.schema.PropertiesValidator; -import com.networknt.schema.SchemaId; +import com.networknt.schema.Schema; +import com.networknt.schema.SchemaRegistry; +import com.networknt.schema.SchemaRef; import com.networknt.schema.SchemaLocation; -import com.networknt.schema.SchemaValidatorsConfig; -import com.networknt.schema.SpecVersion.VersionFlag; +import com.networknt.schema.SpecificationVersion; +import com.networknt.schema.dialect.DialectId; +import com.networknt.schema.keyword.ItemsLegacyValidator; +import com.networknt.schema.keyword.ItemsValidator; +import com.networknt.schema.keyword.PropertiesValidator; +import com.networknt.schema.path.NodePath; +import com.networknt.schema.keyword.KeywordType; import com.networknt.schema.serialization.JsonMapperFactory; import com.networknt.schema.utils.JsonNodes; -import com.networknt.schema.utils.JsonSchemaRefs; -import com.networknt.schema.ValidationMessage; -import com.networknt.schema.ValidationResult; -import com.networknt.schema.ValidatorTypeCode; +import com.networknt.schema.utils.SchemaRefs; +import com.networknt.schema.Error; +import com.networknt.schema.Result; /** * JsonSchemaWalkListenerTest. */ -class JsonSchemaWalkListenerTest { +class WalkListenerTest { @Test void keywordListener() { @@ -86,25 +84,25 @@ void keywordListener() { + " }\r\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder() - .keywordWalkListener(ValidatorTypeCode.PROPERTIES.getValue(), new JsonSchemaWalkListener() { + KeywordWalkListenerRunner keywordWalkListenerRunner = KeywordWalkListenerRunner.builder() + .keywordWalkListener(KeywordType.PROPERTIES.getValue(), new WalkListener() { @Override public WalkFlow onWalkStart(WalkEvent walkEvent) { @SuppressWarnings("unchecked") List propertyKeywords = (List) walkEvent.getExecutionContext() .getCollectorContext() - .getCollectorMap() + .getData() .computeIfAbsent("propertyKeywords", key -> new ArrayList<>()); propertyKeywords.add(walkEvent); return WalkFlow.CONTINUE; } @Override - public void onWalkEnd(WalkEvent walkEvent, List validationMessages) { + public void onWalkEnd(WalkEvent walkEvent, List errors) { } }) .build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V7).getSchema(schemaData, config); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7).getSchema(schemaData); String inputData = "{\r\n" + " \"tags\": [\r\n" + " {\r\n" @@ -117,8 +115,11 @@ public void onWalkEnd(WalkEvent walkEvent, List validationMes + " }\r\n" + " ]\r\n" + "}"; - ValidationResult result = schema.walk(inputData, InputFormat.JSON, true); - assertTrue(result.getValidationMessages().isEmpty()); + WalkConfig walkConfig = WalkConfig.builder() + .keywordWalkListenerRunner(keywordWalkListenerRunner) + .build(); + Result result = schema.walk(inputData, InputFormat.JSON, true, executionContext -> executionContext.setWalkConfig(walkConfig)); + assertTrue(result.getErrors().isEmpty()); @SuppressWarnings("unchecked") List propertyKeywords = (List) result.getExecutionContext().getCollectorContext().get("propertyKeywords"); assertEquals(3, propertyKeywords.size()); @@ -166,25 +167,25 @@ void propertyListener() { + " }\r\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder() - .propertyWalkListener(new JsonSchemaWalkListener() { + PropertyWalkListenerRunner propertyWalkListenerRunner = PropertyWalkListenerRunner.builder() + .propertyWalkListener(new WalkListener() { @Override public WalkFlow onWalkStart(WalkEvent walkEvent) { @SuppressWarnings("unchecked") List properties = (List) walkEvent.getExecutionContext() .getCollectorContext() - .getCollectorMap() + .getData() .computeIfAbsent("properties", key -> new ArrayList<>()); properties.add(walkEvent); return WalkFlow.CONTINUE; } @Override - public void onWalkEnd(WalkEvent walkEvent, List validationMessages) { + public void onWalkEnd(WalkEvent walkEvent, List errors) { } }) .build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V7).getSchema(schemaData, config); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7).getSchema(schemaData); String inputData = "{\r\n" + " \"tags\": [\r\n" + " {\r\n" @@ -197,8 +198,11 @@ public void onWalkEnd(WalkEvent walkEvent, List validationMes + " }\r\n" + " ]\r\n" + "}"; - ValidationResult result = schema.walk(inputData, InputFormat.JSON, true); - assertTrue(result.getValidationMessages().isEmpty()); + WalkConfig walkConfig = WalkConfig.builder() + .propertyWalkListenerRunner(propertyWalkListenerRunner) + .build(); + Result result = schema.walk(inputData, InputFormat.JSON, true, executionContext -> executionContext.setWalkConfig(walkConfig)); + assertTrue(result.getErrors().isEmpty()); @SuppressWarnings("unchecked") List properties = (List) result.getExecutionContext().getCollectorContext().get("properties"); @@ -253,23 +257,23 @@ void itemsListener() { + " }\r\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().itemWalkListener(new JsonSchemaWalkListener() { + ItemWalkListenerRunner itemWalkListenerRunner = ItemWalkListenerRunner.builder().itemWalkListener(new WalkListener() { @Override public WalkFlow onWalkStart(WalkEvent walkEvent) { @SuppressWarnings("unchecked") List items = (List) walkEvent.getExecutionContext() .getCollectorContext() - .getCollectorMap() + .getData() .computeIfAbsent("items", key -> new ArrayList<>()); items.add(walkEvent); return WalkFlow.CONTINUE; } @Override - public void onWalkEnd(WalkEvent walkEvent, List validationMessages) { + public void onWalkEnd(WalkEvent walkEvent, List errors) { } }).build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V7).getSchema(schemaData, config); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7).getSchema(schemaData); String inputData = "{\r\n" + " \"tags\": [\r\n" + " {\r\n" @@ -282,14 +286,18 @@ public void onWalkEnd(WalkEvent walkEvent, List validationMes + " }\r\n" + " ]\r\n" + "}"; - ValidationResult result = schema.walk(inputData, InputFormat.JSON, true); - assertTrue(result.getValidationMessages().isEmpty()); + WalkConfig walkConfig = WalkConfig.builder() + .itemWalkListenerRunner(itemWalkListenerRunner) + .build(); + + Result result = schema.walk(inputData, InputFormat.JSON, true, executionContext -> executionContext.setWalkConfig(walkConfig)); + assertTrue(result.getErrors().isEmpty()); @SuppressWarnings("unchecked") List items = (List) result.getExecutionContext().getCollectorContext().get("items"); assertEquals(2, items.size()); assertEquals("items", items.get(0).getValidator().getKeyword()); - assertInstanceOf(ItemsValidator.class, items.get(0).getValidator()); + assertInstanceOf(ItemsLegacyValidator.class, items.get(0).getValidator()); assertEquals("/tags/0", items.get(0).getInstanceLocation().toString()); assertEquals("/properties/tags/items", items.get(0).getSchema().getEvaluationPath().toString()); @@ -326,23 +334,23 @@ void items202012Listener() { + " }\r\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().itemWalkListener(new JsonSchemaWalkListener() { + ItemWalkListenerRunner itemWalkListenerRunner = ItemWalkListenerRunner.builder().itemWalkListener(new WalkListener() { @Override public WalkFlow onWalkStart(WalkEvent walkEvent) { @SuppressWarnings("unchecked") List items = (List) walkEvent.getExecutionContext() .getCollectorContext() - .getCollectorMap() + .getData() .computeIfAbsent("items", key -> new ArrayList<>()); items.add(walkEvent); return WalkFlow.CONTINUE; } @Override - public void onWalkEnd(WalkEvent walkEvent, List validationMessages) { + public void onWalkEnd(WalkEvent walkEvent, List errors) { } }).build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V7).getSchema(schemaData, config); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_7).getSchema(schemaData); String inputData = "{\r\n" + " \"tags\": [\r\n" + " {\r\n" @@ -355,14 +363,17 @@ public void onWalkEnd(WalkEvent walkEvent, List validationMes + " }\r\n" + " ]\r\n" + "}"; - ValidationResult result = schema.walk(inputData, InputFormat.JSON, true); - assertTrue(result.getValidationMessages().isEmpty()); + WalkConfig walkConfig = WalkConfig.builder() + .itemWalkListenerRunner(itemWalkListenerRunner) + .build(); + Result result = schema.walk(inputData, InputFormat.JSON, true, executionContext -> executionContext.setWalkConfig(walkConfig)); + assertTrue(result.getErrors().isEmpty()); @SuppressWarnings("unchecked") List items = (List) result.getExecutionContext().getCollectorContext().get("items"); assertEquals(2, items.size()); assertEquals("items", items.get(0).getValidator().getKeyword()); - assertInstanceOf(ItemsValidator202012.class, items.get(0).getValidator()); + assertInstanceOf(ItemsValidator.class, items.get(0).getValidator()); assertEquals("/tags/0", items.get(0).getInstanceLocation().toString()); assertEquals("/properties/tags/items", items.get(0).getSchema().getEvaluationPath().toString()); @@ -373,26 +384,27 @@ public void onWalkEnd(WalkEvent walkEvent, List validationMes @Test void draft201909() { - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder() - .keywordWalkListener(ValidatorTypeCode.PROPERTIES.getValue(), new JsonSchemaWalkListener() { + KeywordWalkListenerRunner keywordWalkListenerRunner = KeywordWalkListenerRunner.builder() + .keywordWalkListener(KeywordType.PROPERTIES.getValue(), new WalkListener() { @Override public WalkFlow onWalkStart(WalkEvent walkEvent) { @SuppressWarnings("unchecked") List propertyKeywords = (List) walkEvent.getExecutionContext() .getCollectorContext() - .getCollectorMap() + .getData() .computeIfAbsent("propertyKeywords", key -> new ArrayList<>()); propertyKeywords.add(walkEvent); return WalkFlow.CONTINUE; } @Override - public void onWalkEnd(WalkEvent walkEvent, List validationMessages) { + public void onWalkEnd(WalkEvent walkEvent, List errors) { } }) .build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V201909) - .getSchema(SchemaLocation.of(SchemaId.V201909), config); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2019_09) + .getSchema(SchemaLocation.of(DialectId.DRAFT_2019_09)); + String inputData = "{\r\n" + " \"$schema\": \"https://json-schema.org/draft/2019-09/schema\",\r\n" + " \"type\": \"object\",\r\n" @@ -408,11 +420,13 @@ public void onWalkEnd(WalkEvent walkEvent, List validationMes + " }\r\n" + " }\r\n" + "}"; - ValidationResult result = schema.walk(inputData, InputFormat.JSON, true); - assertTrue(result.getValidationMessages().isEmpty()); + WalkConfig walkConfig = WalkConfig.builder() + .keywordWalkListenerRunner(keywordWalkListenerRunner) + .build(); + Result result = schema.walk(inputData, InputFormat.JSON, true, executionContext -> executionContext.setWalkConfig(walkConfig)); + assertTrue(result.getErrors().isEmpty()); - @SuppressWarnings("unchecked") - List propertyKeywords = (List) result.getExecutionContext().getCollectorContext().getCollectorMap().get("propertyKeywords"); + List propertyKeywords = result.getExecutionContext().getCollectorContext().get("propertyKeywords"); assertEquals(28, propertyKeywords.size()); @@ -552,14 +566,13 @@ void applyDefaults() throws JsonProcessingException { + " }\r\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder() - .applyDefaultsStrategy(new ApplyDefaultsStrategy(true, true, true)) - .build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, config); + WalkConfig walkConfig = WalkConfig.builder() + .applyDefaultsStrategy(new ApplyDefaultsStrategy(true, true, true)).build(); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12).getSchema(schemaData); JsonNode inputNode = JsonMapperFactory.getInstance().readTree("{}"); - ValidationResult result = schema.walk(inputNode, true); + Result result = schema.walk(inputNode, true, executionContext -> executionContext.setWalkConfig(walkConfig)); assertEquals("{\"s\":\"S\",\"ref\":\"REF\"}", inputNode.toString()); - assertTrue(result.getValidationMessages().isEmpty()); + assertTrue(result.getErrors().isEmpty()); } @Test @@ -585,14 +598,14 @@ void applyDefaultsWithWalker() throws JsonProcessingException { + " }\r\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder() - .propertyWalkListener(new JsonSchemaWalkListener() { + PropertyWalkListenerRunner propertyWalkListenerRunner = PropertyWalkListenerRunner.builder() + .propertyWalkListener(new WalkListener() { @Override public WalkFlow onWalkStart(WalkEvent walkEvent) { if (walkEvent.getInstanceNode() == null || walkEvent.getInstanceNode().isMissingNode() || walkEvent.getInstanceNode().isNull()) { - JsonSchema schema = walkEvent.getSchema(); - JsonSchemaRef schemaRef = JsonSchemaRefs.from(schema); + Schema schema = walkEvent.getSchema(); + SchemaRef schemaRef = SchemaRefs.from(schema); if (schemaRef != null) { schema = schemaRef.getSchema(); } @@ -607,16 +620,19 @@ public WalkFlow onWalkStart(WalkEvent walkEvent) { } @Override - public void onWalkEnd(WalkEvent walkEvent, List validationMessages) { + public void onWalkEnd(WalkEvent walkEvent, List errors) { } }) .build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, config); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12).getSchema(schemaData); + WalkConfig walkConfig = WalkConfig.builder() + .propertyWalkListenerRunner(propertyWalkListenerRunner) + .build(); JsonNode inputNode = JsonMapperFactory.getInstance().readTree("{}"); - ValidationResult result = schema.walk(inputNode, true); + Result result = schema.walk(inputNode, true, executionContext -> executionContext.setWalkConfig(walkConfig)); assertEquals("{\"s\":\"S\",\"ref\":\"REF\"}", inputNode.toString()); - assertTrue(result.getValidationMessages().isEmpty()); + assertTrue(result.getErrors().isEmpty()); } @Test @@ -642,14 +658,14 @@ void applyInvalidDefaultsWithWalker() throws JsonProcessingException { + " }\r\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder() - .propertyWalkListener(new JsonSchemaWalkListener() { + PropertyWalkListenerRunner propertyWalkListenerRunner = PropertyWalkListenerRunner.builder() + .propertyWalkListener(new WalkListener() { @Override public WalkFlow onWalkStart(WalkEvent walkEvent) { if (walkEvent.getInstanceNode() == null || walkEvent.getInstanceNode().isMissingNode() || walkEvent.getInstanceNode().isNull()) { - JsonSchema schema = walkEvent.getSchema(); - JsonSchemaRef schemaRef = JsonSchemaRefs.from(schema); + Schema schema = walkEvent.getSchema(); + SchemaRef schemaRef = SchemaRefs.from(schema); if (schemaRef != null) { schema = schemaRef.getSchema(); } @@ -664,21 +680,24 @@ public WalkFlow onWalkStart(WalkEvent walkEvent) { } @Override - public void onWalkEnd(WalkEvent walkEvent, List validationMessages) { + public void onWalkEnd(WalkEvent walkEvent, List errors) { } }) .build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, config); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12).getSchema(schemaData); JsonNode inputNode = JsonMapperFactory.getInstance().readTree("{}"); - ValidationResult result = schema.walk(inputNode, true); + WalkConfig walkConfig = WalkConfig.builder() + .propertyWalkListenerRunner(propertyWalkListenerRunner) + .build(); + Result result = schema.walk(inputNode, true, executionContext -> executionContext.setWalkConfig(walkConfig)); assertEquals("{\"s\":1,\"ref\":\"REF\"}", inputNode.toString()); - assertFalse(result.getValidationMessages().isEmpty()); + assertFalse(result.getErrors().isEmpty()); inputNode = JsonMapperFactory.getInstance().readTree("{}"); - result = schema.walk(inputNode, false); + result = schema.walk(inputNode, false, executionContext -> executionContext.setWalkConfig(walkConfig)); assertEquals("{\"s\":1,\"ref\":\"REF\"}", inputNode.toString()); - assertTrue(result.getValidationMessages().isEmpty()); + assertTrue(result.getErrors().isEmpty()); } @Test @@ -702,8 +721,8 @@ void missingRequired() throws JsonProcessingException { + " }\r\n" + "}"; Map missingSchemaNode = new LinkedHashMap<>(); - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder() - .keywordWalkListener(ValidatorTypeCode.PROPERTIES.getValue(), new JsonSchemaWalkListener() { + KeywordWalkListenerRunner keywordWalkListenerRunner = KeywordWalkListenerRunner.builder() + .keywordWalkListener(KeywordType.PROPERTIES.getValue(), new WalkListener() { @Override public WalkFlow onWalkStart(WalkEvent walkEvent) { JsonNode requiredNode = walkEvent.getSchema().getSchemaNode().get("required"); @@ -720,8 +739,8 @@ public WalkFlow onWalkStart(WalkEvent walkEvent) { if (propertyNode == null) { // Get the schema PropertiesValidator propertiesValidator = walkEvent.getValidator(); - JsonSchema propertySchema = propertiesValidator.getSchemas().get(requiredProperty); - JsonSchemaRef schemaRef = JsonSchemaRefs.from(propertySchema); + Schema propertySchema = propertiesValidator.getSchemas().get(requiredProperty); + SchemaRef schemaRef = SchemaRefs.from(propertySchema); if (schemaRef != null) { propertySchema = schemaRef.getSchema(); } @@ -732,15 +751,18 @@ public WalkFlow onWalkStart(WalkEvent walkEvent) { } @Override - public void onWalkEnd(WalkEvent walkEvent, List validationMessages) { + public void onWalkEnd(WalkEvent walkEvent, List errors) { } }) .build(); + WalkConfig walkConfig = WalkConfig.builder() + .keywordWalkListenerRunner(keywordWalkListenerRunner) + .build(); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12).getSchema(schemaData); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, config); JsonNode inputNode = JsonMapperFactory.getInstance().readTree("{}"); - ValidationResult result = schema.walk(inputNode, true); - assertFalse(result.getValidationMessages().isEmpty()); + Result result = schema.walk(inputNode, true, executionContext -> executionContext.setWalkConfig(walkConfig)); + assertFalse(result.getErrors().isEmpty()); assertEquals("{\"type\":\"integer\"}", missingSchemaNode.get("s").toString()); assertEquals("{\"type\":\"string\"}", missingSchemaNode.get("ref").toString()); } @@ -774,16 +796,16 @@ void generateDataWithWalker() throws JsonProcessingException { + " }\r\n" + "}"; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder() - .propertyWalkListener(new JsonSchemaWalkListener() { + PropertyWalkListenerRunner propertyWalkListenerRunner = PropertyWalkListenerRunner.builder() + .propertyWalkListener(new WalkListener() { @Override public WalkFlow onWalkStart(WalkEvent walkEvent) { if (walkEvent.getInstanceNode() == null || walkEvent.getInstanceNode().isMissingNode() || walkEvent.getInstanceNode().isNull()) { - JsonSchema schema = walkEvent.getSchema(); - JsonSchemaRef schemaRef = null; + Schema schema = walkEvent.getSchema(); + SchemaRef schemaRef = null; do { - schemaRef = JsonSchemaRefs.from(schema); + schemaRef = SchemaRefs.from(schema); if (schemaRef != null) { schema = schemaRef.getSchema(); } @@ -802,16 +824,19 @@ public WalkFlow onWalkStart(WalkEvent walkEvent) { } @Override - public void onWalkEnd(WalkEvent walkEvent, List validationMessages) { + public void onWalkEnd(WalkEvent walkEvent, List errors) { } }) .build(); + WalkConfig walkConfig = WalkConfig.builder() + .propertyWalkListenerRunner(propertyWalkListenerRunner) + .build(); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12).getSchema(schemaData); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, config); JsonNode inputNode = JsonMapperFactory.getInstance().readTree("{}"); - ValidationResult result = schema.walk(inputNode, true); + Result result = schema.walk(inputNode, true, executionContext -> executionContext.setWalkConfig(walkConfig)); assertEquals("{\"name\":\"John Doe\",\"email\":\"john.doe@gmail.com\"}", inputNode.toString()); - assertTrue(result.getValidationMessages().isEmpty()); + assertTrue(result.getErrors().isEmpty()); } /** @@ -838,28 +863,31 @@ void itemListenerDraft201909() { + " }\r\n" + " }\r\n" + " }"; - JsonSchemaWalkListener listener = new JsonSchemaWalkListener() { + WalkListener listener = new WalkListener() { @Override public WalkFlow onWalkStart(WalkEvent walkEvent) { return WalkFlow.CONTINUE; } @Override - public void onWalkEnd(WalkEvent walkEvent, List validationMessages) { + public void onWalkEnd(WalkEvent walkEvent, List errors) { @SuppressWarnings("unchecked") List items = (List) walkEvent.getExecutionContext() .getCollectorContext() - .getCollectorMap() - .computeIfAbsent("items", key -> new ArrayList()); + .getData() + .computeIfAbsent("items", key -> new ArrayList()); items.add(walkEvent); } }; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder() - .itemWalkListener(listener) - .propertyWalkListener(listener) + ItemWalkListenerRunner itemWalkListenerRunner = ItemWalkListenerRunner.builder().itemWalkListener(listener).build(); + PropertyWalkListenerRunner propertyWalkListenerRunner = PropertyWalkListenerRunner.builder().propertyWalkListener(listener).build(); + WalkConfig walkConfig = WalkConfig.builder() + .itemWalkListenerRunner(itemWalkListenerRunner) + .propertyWalkListenerRunner(propertyWalkListenerRunner) .build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V201909).getSchema(schemaData, config); - ValidationResult result = schema.walk(null, true); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2019_09).getSchema(schemaData); + + Result result = schema.walk(null, true, executionContext -> executionContext.setWalkConfig(walkConfig)); @SuppressWarnings("unchecked") List items = (List) result.getExecutionContext().getCollectorContext().get("items"); assertEquals(4, items.size()); @@ -901,30 +929,32 @@ void itemListenerDraft202012() { + " }\r\n" + " }\r\n" + " }"; - JsonSchemaWalkListener listener = new JsonSchemaWalkListener() { + WalkListener listener = new WalkListener() { @Override public WalkFlow onWalkStart(WalkEvent walkEvent) { return WalkFlow.CONTINUE; } @Override - public void onWalkEnd(WalkEvent walkEvent, List validationMessages) { + public void onWalkEnd(WalkEvent walkEvent, List errors) { @SuppressWarnings("unchecked") List items = (List) walkEvent.getExecutionContext() .getCollectorContext() - .getCollectorMap() - .computeIfAbsent("items", key -> new ArrayList()); + .getData() + .computeIfAbsent("items", key -> new ArrayList()); items.add(walkEvent); } }; - SchemaValidatorsConfig config = SchemaValidatorsConfig.builder() - .itemWalkListener(listener) - .propertyWalkListener(listener) + ItemWalkListenerRunner itemWalkListenerRunner = ItemWalkListenerRunner.builder().itemWalkListener(listener).build(); + PropertyWalkListenerRunner propertyWalkListenerRunner = PropertyWalkListenerRunner.builder().propertyWalkListener(listener).build(); + WalkConfig walkConfig = WalkConfig.builder() + .itemWalkListenerRunner(itemWalkListenerRunner) + .propertyWalkListenerRunner(propertyWalkListenerRunner) .build(); - JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData, config); - ValidationResult result = schema.walk(null, true); - @SuppressWarnings("unchecked") - List items = (List) result.getExecutionContext().getCollectorContext().get("items"); + Schema schema = SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12).getSchema(schemaData); + + Result result = schema.walk(null, true, executionContext -> executionContext.setWalkConfig(walkConfig)); + List items = result.getExecutionContext().getCollectorContext().get("items"); assertEquals(4, items.size()); assertEquals("/name", items.get(0).getInstanceLocation().toString()); assertEquals("properties", items.get(0).getKeyword()); diff --git a/src/test/resources/const-messages-override.properties b/src/test/resources/const-messages-override.properties index 247e95263..896237ecd 100644 --- a/src/test/resources/const-messages-override.properties +++ b/src/test/resources/const-messages-override.properties @@ -1 +1 @@ -const = {0}: must be the constant value ''{1}'' but is ''{2}'' \ No newline at end of file +const = must be the constant value ''{0}'' but is ''{1}'' \ No newline at end of file diff --git a/src/test/resources/draft2019-09/invalid-min-max-contains.json b/src/test/resources/draft2019-09/invalid-min-max-contains.json index 17fa59c3f..8acbb8664 100644 --- a/src/test/resources/draft2019-09/invalid-min-max-contains.json +++ b/src/test/resources/draft2019-09/invalid-min-max-contains.json @@ -10,7 +10,7 @@ "description": "should fail", "data": [], "valid": false, - "validationMessages": [ + "errors": [ ": must be a non-negative integer in {\"$schema\":\"https://json-schema.org/draft/2019-09/schema\",\"minContains\":\"1\"}" ] } @@ -27,7 +27,7 @@ "description": "should fail", "data": [], "valid": false, - "validationMessages": [ + "errors": [ ": must be a non-negative integer in {\"$schema\":\"https://json-schema.org/draft/2019-09/schema\",\"minContains\":0.5}" ] } @@ -44,7 +44,7 @@ "description": "should fail", "data": [], "valid": false, - "validationMessages": [ + "errors": [ ": must be a non-negative integer in {\"$schema\":\"https://json-schema.org/draft/2019-09/schema\",\"minContains\":-1}" ] } @@ -61,7 +61,7 @@ "description": "should fail", "data": [], "valid": false, - "validationMessages": [ + "errors": [ ": must be a non-negative integer in {\"$schema\":\"https://json-schema.org/draft/2019-09/schema\",\"maxContains\":\"1\"}" ] } @@ -78,7 +78,7 @@ "description": "should fail", "data": [], "valid": false, - "validationMessages": [ + "errors": [ ": must be a non-negative integer in {\"$schema\":\"https://json-schema.org/draft/2019-09/schema\",\"maxContains\":0.5}" ] } @@ -95,7 +95,7 @@ "description": "should fail", "data": [], "valid": false, - "validationMessages": [ + "errors": [ ": must be a non-negative integer in {\"$schema\":\"https://json-schema.org/draft/2019-09/schema\",\"maxContains\":-1}" ] } @@ -113,7 +113,7 @@ "description": "should fail", "data": [], "valid": false, - "validationMessages": [ + "errors": [ ": minContains must less than or equal to maxContains in {\"$schema\":\"https://json-schema.org/draft/2019-09/schema\",\"maxContains\":0,\"minContains\":1}", ": minContains must less than or equal to maxContains in {\"$schema\":\"https://json-schema.org/draft/2019-09/schema\",\"maxContains\":0,\"minContains\":1}" ] diff --git a/src/test/resources/draft2020-12/invalid-min-max-contains.json b/src/test/resources/draft2020-12/invalid-min-max-contains.json index 84fae3cec..8b35ce883 100644 --- a/src/test/resources/draft2020-12/invalid-min-max-contains.json +++ b/src/test/resources/draft2020-12/invalid-min-max-contains.json @@ -10,7 +10,7 @@ "description": "should fail", "data": [], "valid": false, - "validationMessages": [ + "errors": [ ": must be a non-negative integer in {\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"minContains\":\"1\"}" ] } @@ -27,7 +27,7 @@ "description": "should fail", "data": [], "valid": false, - "validationMessages": [ + "errors": [ ": must be a non-negative integer in {\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"minContains\":0.5}" ] } @@ -44,7 +44,7 @@ "description": "should fail", "data": [], "valid": false, - "validationMessages": [ + "errors": [ ": must be a non-negative integer in {\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"minContains\":-1}" ] } @@ -61,7 +61,7 @@ "description": "should fail", "data": [], "valid": false, - "validationMessages": [ + "errors": [ ": must be a non-negative integer in {\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"maxContains\":\"1\"}" ] } @@ -78,7 +78,7 @@ "description": "should fail", "data": [], "valid": false, - "validationMessages": [ + "errors": [ ": must be a non-negative integer in {\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"maxContains\":0.5}" ] } @@ -95,7 +95,7 @@ "description": "should fail", "data": [], "valid": false, - "validationMessages": [ + "errors": [ ": must be a non-negative integer in {\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"maxContains\":-1}" ] } @@ -113,7 +113,7 @@ "description": "should fail", "data": [], "valid": false, - "validationMessages": [ + "errors": [ ": minContains must less than or equal to maxContains in {\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"maxContains\":0,\"minContains\":1}", ": minContains must less than or equal to maxContains in {\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"maxContains\":0,\"minContains\":1}" ] diff --git a/src/test/resources/draft2020-12/issue656.json b/src/test/resources/draft2020-12/issue656.json index e46dd6cbd..fc012ce0f 100644 --- a/src/test/resources/draft2020-12/issue656.json +++ b/src/test/resources/draft2020-12/issue656.json @@ -154,7 +154,7 @@ "followup-treatments": [] }, "valid": false, - "validationMessages": [ + "errors": [ ": must be valid to one and only one schema, but 2 are valid with indexes '0, 1'" ] } diff --git a/src/test/resources/draft2020-12/issue798.json b/src/test/resources/draft2020-12/issue798.json index 20d500336..b5875ff29 100644 --- a/src/test/resources/draft2020-12/issue798.json +++ b/src/test/resources/draft2020-12/issue798.json @@ -22,21 +22,21 @@ "data": { "a": "a string", "b": "a string" }, "valid": false, "config": { "readOnly": true, "writeOnly": true }, - "validationMessages": [ "/b: is a readonly field, it cannot be changed" ] + "errors": [ "/b: is a readonly field, it cannot be changed" ] }, { "description": "write-only behavior", "data": { "a": "a string", "c": "a string" }, "valid": false, "config": { "readOnly": true, "writeOnly": true }, - "validationMessages": [ "/c: is a write-only field, it cannot appear in the data" ] + "errors": [ "/c: is a write-only field, it cannot appear in the data" ] }, { "description": "both behavior", "data": { "a": "a string", "d": "a string" }, "valid": false, "config": { "readOnly": true, "writeOnly": true }, - "validationMessages": [ + "errors": [ "/d: is a readonly field, it cannot be changed", "/d: is a write-only field, it cannot appear in the data" ] diff --git a/src/test/resources/draft4/issue425.json b/src/test/resources/draft4/issue425.json index c9c614337..20e1d6e91 100644 --- a/src/test/resources/draft4/issue425.json +++ b/src/test/resources/draft4/issue425.json @@ -34,7 +34,7 @@ "values": 3 }, "valid": false, - "validationMessages": [ + "errors": [ "/values: must be valid to one and only one schema, but 0 are valid", "/values: integer found, array expected", "/values: integer found, string expected" diff --git a/src/test/resources/draft7/issue470.json b/src/test/resources/draft7/issue470.json index d5ced20c4..7956a85f3 100644 --- a/src/test/resources/draft7/issue470.json +++ b/src/test/resources/draft7/issue470.json @@ -83,7 +83,7 @@ } }, "valid": false, - "validationMessages": [ + "errors": [ "/search: must be valid to one and only one schema, but 0 are valid", "/search: property 'byName' is not defined in the schema and the schema does not allow additional properties", "/search/byName/name: integer found, string expected" @@ -99,7 +99,7 @@ } }, "valid": false, - "validationMessages": [ + "errors": [ "/search: must be valid to one and only one schema, but 0 are valid", "/search: property 'byName' is not defined in the schema and the schema does not allow additional properties", "/search/byName/name: must be at most 20 characters long" @@ -115,7 +115,7 @@ } }, "valid": false, - "validationMessages": [ + "errors": [ "/search: must be valid to one and only one schema, but 0 are valid", "/search/byAge/age: string found, integer expected", "/search: property 'byAge' is not defined in the schema and the schema does not allow additional properties" @@ -131,7 +131,7 @@ } }, "valid": false, - "validationMessages": [ + "errors": [ "/search: must be valid to one and only one schema, but 0 are valid", "/search/byAge/age: must have a maximum value of 150", "/search: property 'byAge' is not defined in the schema and the schema does not allow additional properties" diff --git a/src/test/resources/draft7/issue491.json b/src/test/resources/draft7/issue491.json index 68562bdb5..f52f0334d 100644 --- a/src/test/resources/draft7/issue491.json +++ b/src/test/resources/draft7/issue491.json @@ -81,7 +81,7 @@ } }, "valid": false, - "validationMessages": [ + "errors": [ "/search: required property 'name' not found", "/search/searchAge/age: string found, integer expected", "/search: must be valid to one and only one schema, but 0 are valid" @@ -95,7 +95,7 @@ } }, "valid": false, - "validationMessages": [ + "errors": [ "/search/name: integer found, string expected", "/search: required property 'searchAge' not found", "/search: must be valid to one and only one schema, but 0 are valid" @@ -183,7 +183,7 @@ } }, "valid": false, - "validationMessages": [ + "errors": [ "/search: required property 'name' not found", "/search/byAge/age: string found, integer expected", "/search: must be valid to one and only one schema, but 0 are valid" @@ -197,7 +197,7 @@ } }, "valid": false, - "validationMessages": [ + "errors": [ "/search/name: integer found, string expected", "/search: required property 'byAge' not found", "/search: must be valid to one and only one schema, but 0 are valid" @@ -275,7 +275,7 @@ } }, "valid": false, - "validationMessages": [ + "errors": [ "/search: required property 'name' not found", "/search/age: string found, integer expected", "/search: must be valid to one and only one schema, but 0 are valid" @@ -289,7 +289,7 @@ } }, "valid": false, - "validationMessages": [ + "errors": [ "/search/name: integer found, string expected", "/search: required property 'age' not found", "/search: must be valid to one and only one schema, but 0 are valid" @@ -303,7 +303,7 @@ } }, "valid": false, - "validationMessages": [ + "errors": [ "/search: required property 'name' not found", "/search/age: must have a maximum value of 150", "/search: must be valid to one and only one schema, but 0 are valid" @@ -317,7 +317,7 @@ } }, "valid": false, - "validationMessages": [ + "errors": [ "/search/name: must be at most 20 characters long", "/search: required property 'age' not found", "/search: must be valid to one and only one schema, but 0 are valid" diff --git a/src/test/resources/draft7/issue516.json b/src/test/resources/draft7/issue516.json index 9556574b0..dd0a10c81 100644 --- a/src/test/resources/draft7/issue516.json +++ b/src/test/resources/draft7/issue516.json @@ -118,7 +118,7 @@ ] }, "valid": false, - "validationMessages": [ + "errors": [ "/activities/0: must be valid to one and only one schema, but 0 are valid", "/activities/0: property 'age' is not defined in the schema and the schema does not allow additional properties", "/activities/0: required property 'chemicalCharacteristic' not found", diff --git a/src/test/resources/draft7/issue653.json b/src/test/resources/draft7/issue653.json index 6e7f7180b..9d14f2717 100644 --- a/src/test/resources/draft7/issue653.json +++ b/src/test/resources/draft7/issue653.json @@ -79,7 +79,7 @@ ] }, "valid": false, - "validationMessages": [ + "errors": [ "/pets/0: must be valid to one and only one schema, but 0 are valid", "/pets/0: required property 'age' not found", "/pets/0: schema for 'else' is false" diff --git a/src/test/resources/draft7/issue678.json b/src/test/resources/draft7/issue678.json index d743f6263..08603efe6 100644 --- a/src/test/resources/draft7/issue678.json +++ b/src/test/resources/draft7/issue678.json @@ -48,7 +48,7 @@ } }, "valid": false, - "validationMessages": [ + "errors": [ "/outerObject/innerObject: object found, string expected", "/outerObject/innerObject: required property 'value' not found", "/outerObject/innerObject: required property 'unit' not found", diff --git a/src/test/resources/issue686/translations.properties b/src/test/resources/issue686/translations.properties index 4dfc094c0..b57350150 100644 --- a/src/test/resources/issue686/translations.properties +++ b/src/test/resources/issue686/translations.properties @@ -1 +1 @@ -type = {0}: {1} found, {2} expected (TEST) +type = {0} found, {1} expected (TEST) diff --git a/src/test/resources/issue686/translations_de.properties b/src/test/resources/issue686/translations_de.properties index f9df24408..5db69d10b 100644 --- a/src/test/resources/issue686/translations_de.properties +++ b/src/test/resources/issue686/translations_de.properties @@ -1 +1 @@ -type = {0}: {1} found, {2} expected (TEST) (DE) +type = {0} found, {1} expected (TEST) (DE) diff --git a/src/test/resources/issue686/translations_fr.properties b/src/test/resources/issue686/translations_fr.properties index d627e458d..518a44aef 100644 --- a/src/test/resources/issue686/translations_fr.properties +++ b/src/test/resources/issue686/translations_fr.properties @@ -1 +1 @@ -type = {0}: {1} found, {2} expected (TEST) (FR) +type = {0} found, {1} expected (TEST) (FR) diff --git a/src/test/resources/openapi3/discriminator.json b/src/test/resources/openapi3/discriminator.json index 6d55ece6c..f09912f8d 100644 --- a/src/test/resources/openapi3/discriminator.json +++ b/src/test/resources/openapi3/discriminator.json @@ -232,27 +232,27 @@ "valid": true }, { - "description": "mapped to Bedroom with missing number of beds", + "description": "mapped to Bedroom with missing number of beds but #/components/schemas/Room matches and discriminator cannot change the validation result", "data": { "@type": "bed" }, - "valid": false + "valid": true }, { - "description": "mapped to KidsBedroom with missing number of beds", + "description": "mapped to KidsBedroom with missing number of beds but #/components/schemas/Room matches and discriminator cannot change the validation result", "data": { "@type": "KidsBedRoom", "isTidy": true }, - "valid": false + "valid": true }, { - "description": "mapped to KidsBedroom with missing tidiness", + "description": "mapped to KidsBedroom with missing tidiness but #/components/schemas/Room matches and discriminator cannot change the validation result", "data": { "@type": "KidsBedRoom", "numberOfBeds": 1 }, - "valid": false + "valid": true }, { "description": "mapped to GuestRoom with correct @type (mapping override on BedRoom)", @@ -264,12 +264,12 @@ "valid": true }, { - "description": "mapped to GuestRoom with incorrect @type (mapping override on BedRoom)", + "description": "mapped to GuestRoom with incorrect @type (mapping override on BedRoom) but #/components/schemas/Room matches and discriminator cannot change the validation result", "data": { "@type": "GuestRoom", "guest": "Steve" }, - "valid": false + "valid": true }, { "description": "mapped to invalid Room", @@ -409,7 +409,7 @@ "valid": true }, { - "description": "schema with discriminator and recursion with invalid BedRoom", + "description": "schema with discriminator and recursion with invalid BedRoom but #/components/schemas/Room matches and discriminator cannot change the validation result", "data": { "@type": "can be ignored - discriminator not in use on root schema", "numberOfBeds": 42, @@ -418,7 +418,7 @@ "floor": 1 } }, - "valid": false + "valid": true } ] }, @@ -506,7 +506,7 @@ "valid": true }, { - "description": "schema with discriminator and recursion with invalid BedRoom", + "description": "schema with discriminator and recursion with invalid BedRoom but #/components/schemas/Room matches and discriminator cannot change the validation result", "data": { "@type": "can be ignored - discriminator not in use on root schema", "numberOfBeds": 42, @@ -515,7 +515,7 @@ "floor": 1 } }, - "valid": false + "valid": true } ] }, diff --git a/src/test/resources/schema/OverwritingCustomMessageBug.json b/src/test/resources/schema/OverwritingCustomMessageBug.json index 6ead21bc1..8eecb3bfb 100644 --- a/src/test/resources/schema/OverwritingCustomMessageBug.json +++ b/src/test/resources/schema/OverwritingCustomMessageBug.json @@ -10,7 +10,7 @@ "type": "string", "pattern": "(foo)+", "message": { - "pattern": "{0}: Must be a string with the a shape foofoofoofoo... with at least one foo" + "pattern": "Must be a string with the a shape foofoofoofoo... with at least one foo" } }, "Nope": { @@ -20,7 +20,7 @@ "type": "string", "pattern": "(bar)+", "message": { - "pattern": "{0}: Must be a string with the a shape barbarbar... with at least one bar" + "pattern": "Must be a string with the a shape barbarbar... with at least one bar" } } } diff --git a/src/test/resources/schema/customMessageTests/custom-message-disabled-tests.json b/src/test/resources/schema/customMessageTests/custom-message-disabled-tests.json index a8df5a767..9464fb320 100644 --- a/src/test/resources/schema/customMessageTests/custom-message-disabled-tests.json +++ b/src/test/resources/schema/customMessageTests/custom-message-disabled-tests.json @@ -56,7 +56,7 @@ "bar": 123 }, "valid": false, - "validationMessages": [ + "errors": [ "/bar: integer found, string expected" ] }, @@ -70,7 +70,7 @@ "bar": "Bar 1" }, "valid": false, - "validationMessages": [ + "errors": [ "/foo/2: string found, number expected" ] }, @@ -84,7 +84,7 @@ "bar": "Bar 1" }, "valid": false, - "validationMessages": [ + "errors": [ "/foo: must have at most 3 items but found 4" ] }, @@ -98,7 +98,7 @@ "bar": 123 }, "valid": false, - "validationMessages": [ + "errors": [ "/foo/2: string found, number expected", "/bar: integer found, string expected" ] @@ -113,7 +113,7 @@ "bar": 123 }, "valid": false, - "validationMessages": [ + "errors": [ "/foo: must have at most 3 items but found 4", "/foo/2: string found, number expected", "/bar: integer found, string expected" diff --git a/src/test/resources/schema/customMessageTests/custom-message-tests.json b/src/test/resources/schema/customMessageTests/custom-message-tests.json index 18e1ef138..1dd846514 100644 --- a/src/test/resources/schema/customMessageTests/custom-message-tests.json +++ b/src/test/resources/schema/customMessageTests/custom-message-tests.json @@ -50,8 +50,8 @@ "bar": 123 }, "valid": false, - "validationMessages": [ - "Custom Message: Invalid type provided" + "errors": [ + "/bar: Custom Message: Invalid type provided" ] }, { @@ -64,8 +64,8 @@ "bar": "Bar 1" }, "valid": false, - "validationMessages": [ - "Custom Message: Only numbers are supported in 'foo'" + "errors": [ + "/foo/2: Custom Message: Only numbers are supported in 'foo'" ] }, { @@ -78,8 +78,8 @@ "bar": "Bar 1" }, "valid": false, - "validationMessages": [ - "Custom Message: Maximum 3 numbers can be given in 'foo'" + "errors": [ + "/foo: Custom Message: Maximum 3 numbers can be given in 'foo'" ] }, { @@ -92,9 +92,9 @@ "bar": 123 }, "valid": false, - "validationMessages": [ - "Custom Message: Invalid type provided", - "Custom Message: Only numbers are supported in 'foo'" + "errors": [ + "/bar: Custom Message: Invalid type provided", + "/foo/2: Custom Message: Only numbers are supported in 'foo'" ] }, { @@ -107,10 +107,10 @@ "bar": 123 }, "valid": false, - "validationMessages": [ - "Custom Message: Invalid type provided", - "Custom Message: Only numbers are supported in 'foo'", - "Custom Message: Maximum 3 numbers can be given in 'foo'" + "errors": [ + "/bar: Custom Message: Invalid type provided", + "/foo/2: Custom Message: Only numbers are supported in 'foo'", + "/foo: Custom Message: Maximum 3 numbers can be given in 'foo'" ] } ] @@ -131,8 +131,8 @@ "message": { "type" : "should be an object", "required": { - "foo" : "{0}: ''foo'' is required", - "bar" : "{0}: ''bar'' is required" + "foo" : "'foo' is required", + "bar" : "'bar' is required" } } }, @@ -146,7 +146,7 @@ "foo": 1 }, "valid": false, - "validationMessages": [ + "errors": [ ": 'bar' is required" ] }, @@ -159,7 +159,7 @@ "bar": "bar" }, "valid": false, - "validationMessages": [ + "errors": [ ": 'foo' is required" ] }, @@ -171,7 +171,7 @@ "data": { }, "valid": false, - "validationMessages": [ + "errors": [ ": 'foo' is required", ": 'bar' is required" ] @@ -192,7 +192,7 @@ "type": "string", "minLength": 1, "message": { - "minLength": "{0}: Item should not be empty" + "minLength": "Item should not be empty" } } } @@ -214,7 +214,7 @@ ] }, "valid": false, - "validationMessages": [ + "errors": [ "/requestedItems/0/item: Item should not be empty" ] } diff --git a/src/test/resources/schema/unevaluatedTests/unevaluated-tests.json b/src/test/resources/schema/unevaluatedTests/unevaluated-tests.json index 277db639f..0c9099768 100644 --- a/src/test/resources/schema/unevaluatedTests/unevaluated-tests.json +++ b/src/test/resources/schema/unevaluatedTests/unevaluated-tests.json @@ -88,7 +88,7 @@ } }, "valid": false, - "validationMessages": [ + "errors": [ ": property 'invalid' is not evaluated and the schema does not allow unevaluated properties" ] }, @@ -105,7 +105,7 @@ } }, "valid": false, - "validationMessages": [ + "errors": [ "/address: property 'invalid' is not evaluated and the schema does not allow unevaluated properties" ] }, @@ -122,7 +122,7 @@ } }, "valid": false, - "validationMessages": [ + "errors": [ "/address: property 'invalid2' is not evaluated and the schema does not allow unevaluated properties" ] }, @@ -141,7 +141,7 @@ } }, "valid": false, - "validationMessages": [ + "errors": [ "/address/residence: property 'invalid' is not evaluated and the schema does not allow unevaluated properties" ] } @@ -236,7 +236,7 @@ } }, "valid": false, - "validationMessages": [ + "errors": [ "/vehicle: property 'wheels' is not evaluated and the schema does not allow unevaluated properties" ] }, @@ -252,7 +252,7 @@ } }, "valid": false, - "validationMessages": [ + "errors": [ "/vehicle: must be valid to one and only one schema, but 2 are valid with indexes '1, 2'", "/vehicle: required property 'wheels' not found", "/vehicle: required property 'headlights' not found" @@ -271,7 +271,7 @@ } }, "valid": false, - "validationMessages": [ + "errors": [ "/vehicle: must be valid to one and only one schema, but 2 are valid with indexes '1, 2'", "/vehicle: property 'invalid' is not evaluated and the schema does not allow unevaluated properties", "/vehicle: required property 'wheels' not found", @@ -289,7 +289,7 @@ } }, "valid": false, - "validationMessages": [ + "errors": [ "/vehicle: must be valid to one and only one schema, but 0 are valid", "/vehicle: property 'invalid' is not evaluated and the schema does not allow unevaluated properties" ] @@ -385,7 +385,7 @@ } }, "valid": false, - "validationMessages": [ + "errors": [ "/vehicle: property 'unevaluated' is not evaluated and the schema does not allow unevaluated properties" ] }, @@ -400,7 +400,7 @@ } }, "valid": false, - "validationMessages": [ + "errors": [ "/vehicle: property 'unevaluated' is not evaluated and the schema does not allow unevaluated properties" ] }, @@ -417,7 +417,7 @@ } }, "valid": false, - "validationMessages": [ + "errors": [ "/vehicle: property 'unevaluated' is not evaluated and the schema does not allow unevaluated properties" ] } @@ -514,7 +514,7 @@ } }, "valid": false, - "validationMessages": [ + "errors": [ "/vehicle: required property 'wings' not found", "/vehicle: property 'unevaluated' is not evaluated and the schema does not allow unevaluated properties" ] @@ -577,7 +577,7 @@ "unevaluated": true }, "valid": false, - "validationMessages": [ + "errors": [ ": property 'age' is not evaluated and the schema does not allow unevaluated properties", ": property 'unevaluated' is not evaluated and the schema does not allow unevaluated properties" ]