validate(ExecutionContext executionContext, Jso
// Restore flag
executionContext.setFailFast(failFast);
- if (this.validationContext.getConfig().isOpenAPI3StyleDiscriminators()) {
+ if (this.validationContext.getConfig().isDiscriminatorKeywordEnabled()) {
executionContext.leaveDiscriminatorContextImmediately(instanceLocation);
}
}
diff --git a/src/main/java/com/networknt/schema/SchemaValidatorsConfig.java b/src/main/java/com/networknt/schema/SchemaValidatorsConfig.java
index 75e5ff87c..bb6242fa0 100644
--- a/src/main/java/com/networknt/schema/SchemaValidatorsConfig.java
+++ b/src/main/java/com/networknt/schema/SchemaValidatorsConfig.java
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2016 Network New Technologies Inc.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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
*
@@ -34,23 +34,35 @@
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;
/**
- * Used to validate the acceptable $id values.
+ * 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 JsonSchemaIdValidator schemaIdValidator = JsonSchemaIdValidator.DEFAULT;
+ private ApplyDefaultsStrategy applyDefaultsStrategy = ApplyDefaultsStrategy.EMPTY_APPLY_DEFAULTS_STRATEGY;
/**
- * when validate type, if TYPE_LOOSE = true, will try to convert string to
- * different types to match the type defined in schema.
+ * Controls if schemas loaded from refs will be cached and reused for subsequent runs.
*/
- private boolean typeLoose;
+ 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
@@ -59,15 +71,25 @@ public class SchemaValidatorsConfig {
private boolean failFast;
/**
- * When set to true, walker sets nodes that are missing or NullNode to the
- * default value, if any, and mutate the input json.
+ * Since Draft 2019-09 format assertions are not enabled by default.
*/
- private ApplyDefaultsStrategy applyDefaultsStrategy = ApplyDefaultsStrategy.EMPTY_APPLY_DEFAULTS_STRATEGY;
+ private Boolean formatAssertionsEnabled = null;
/**
- * Used to create {@link com.networknt.schema.regex.RegularExpression}.
+ * 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 RegularExpressionFactory regularExpressionFactory = JDKRegularExpressionFactory.getInstance();
+ private boolean nullableKeywordEnabled = true;
+
+ private final WalkListenerRunner itemWalkListenerRunner;
+
+ private final List itemWalkListeners;
/**
* When set to true, use Java-specific semantics rather than native JavaScript
@@ -75,533 +97,540 @@ public class SchemaValidatorsConfig {
*/
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;
/**
- * When set to true, "messages" provided in schema are used for forming validation errors
- * else default messages are used
+ * The message source to use for generating localised messages.
*/
- private boolean customMessageSupported = true;
+ 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 openAPI3StyleDiscriminators = false;
+ private boolean discriminatorKeywordEnabled = false;
/**
- * 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.
+ * The approach used to generate paths in reported messages, logs and errors. Default is the legacy "JSONPath-like" approach.
*/
- private final Map strictness = new HashMap<>(0);
+ private PathType pathType = PathType.DEFAULT;
/**
- * 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.
+ * Controls if the schema will automatically be preloaded.
*/
- private boolean handleNullableField = true;
+ private boolean preloadJsonSchema = true;
/**
- * When set to true assumes that schema is used to validate incoming data from an API.
+ * Controls the max depth of the evaluation path to preload when preloading refs.
*/
- private Boolean readOnly = null;
+ private int preloadJsonSchemaRefMaxNestingDepth = DEFAULT_PRELOAD_JSON_SCHEMA_REF_MAX_NESTING_DEPTH;
- /**
- * When set to true assumes that schema is used to to validate outgoing data from an API.
- */
- private Boolean writeOnly = null;
+ private final WalkListenerRunner propertyWalkListenerRunner;
+
+ private final List propertyWalkListeners;
/**
- * The approach used to generate paths in reported messages, logs and errors. Default is the legacy "JSONPath-like" approach.
+ * When set to true assumes that schema is used to validate incoming data from an API.
*/
- private PathType pathType = PathType.DEFAULT;
+ private Boolean readOnly = null;
/**
- * Controls if the schema will automatically be preloaded.
+ * Used to create {@link com.networknt.schema.regex.RegularExpression}.
*/
- private boolean preloadJsonSchema = true;
+ private RegularExpressionFactory regularExpressionFactory = JDKRegularExpressionFactory.getInstance();
/**
- * Controls the max depth of the evaluation path to preload when preloading refs.
+ * Used to validate the acceptable $id values.
*/
- private int preloadJsonSchemaRefMaxNestingDepth = DEFAULT_PRELOAD_JSON_SCHEMA_REF_MAX_NESTING_DEPTH;
-
+ private JsonSchemaIdValidator schemaIdValidator = JsonSchemaIdValidator.DEFAULT;
+
/**
- * Controls if schemas loaded from refs will be cached and reused for subsequent runs.
+ * 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 boolean cacheRefs = true;
-
- // This is just a constant for listening to all Keywords.
- public static final String ALL_KEYWORD_WALK_LISTENER_KEY = "com.networknt.AllKeywordWalkListener";
-
- private final Map> keywordWalkListenersMap = new HashMap<>();
-
- private final List propertyWalkListeners = new ArrayList<>();
-
- private final List itemWalkListeners = new ArrayList<>();
-
- private ExecutionContextCustomizer executionContextCustomizer;
-
- @Deprecated
- private boolean loadCollectors = true;
+ private final Map strictness;
/**
- * The Locale to consider when loading validation messages from the default resource bundle.
+ * when validate type, if TYPE_LOOSE = true, will try to convert string to
+ * different types to match the type defined in schema.
*/
- private Locale locale;
+ private boolean typeLoose;
/**
- * The message source to use for generating localised messages.
+ * When set to true assumes that schema is used to to validate outgoing data from an API.
*/
- private MessageSource messageSource;
+ private Boolean writeOnly = null;
/**
- * Since Draft 2019-09 format assertions are not enabled by default.
+ * 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
+ *
*/
- private Boolean formatAssertionsEnabled = null;
-
- /************************ START OF UNEVALUATED CHECKS **********************************/
-
@Deprecated
- public SchemaValidatorsConfig disableUnevaluatedAnalysis() {
- return this;
- }
+ 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;
- @Deprecated
- public SchemaValidatorsConfig disableUnevaluatedItems() {
- return this;
+ this.itemWalkListenerRunner = new DefaultItemWalkListenerRunner(getArrayItemWalkListeners());
+ this.keywordWalkListenerRunner = new DefaultKeywordWalkListenerRunner(getKeywordWalkListenersMap());
+ this.propertyWalkListenerRunner = new DefaultPropertyWalkListenerRunner(getPropertyWalkListeners());
}
- @Deprecated
- public SchemaValidatorsConfig disableUnevaluatedProperties() {
- return this;
+ public void addItemWalkListener(JsonSchemaWalkListener itemWalkListener) {
+ this.itemWalkListeners.add(itemWalkListener);
}
- @Deprecated
- public SchemaValidatorsConfig enableUnevaluatedAnalysis() {
- return this;
+ public void addItemWalkListeners(List itemWalkListeners) {
+ this.itemWalkListeners.addAll(itemWalkListeners);
}
- @Deprecated
- public SchemaValidatorsConfig enableUnevaluatedItems() {
- return this;
+ 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);
}
- @Deprecated
- public SchemaValidatorsConfig enableUnevaluatedProperties() {
- return this;
+ 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);
}
- @Deprecated
- public boolean isUnevaluatedItemsAnalysisDisabled() {
- return false;
+ 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);
}
- @Deprecated
- public boolean isUnevaluatedItemsAnalysisEnabled() {
- return !isUnevaluatedItemsAnalysisDisabled();
+ 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);
}
- @Deprecated
- public boolean isUnevaluatedPropertiesAnalysisDisabled() {
- return false;
+ public void addPropertyWalkListener(JsonSchemaWalkListener propertyWalkListener) {
+ this.propertyWalkListeners.add(propertyWalkListener);
}
- @Deprecated
- public boolean isUnevaluatedPropertiesAnalysisEnabled() {
- return !isUnevaluatedPropertiesAnalysisDisabled();
+ public void addPropertyWalkListeners(List propertyWalkListeners) {
+ this.propertyWalkListeners.addAll(propertyWalkListeners);
}
- /************************ END OF UNEVALUATED CHECKS **********************************/
+ public ApplyDefaultsStrategy getApplyDefaultsStrategy() {
+ return this.applyDefaultsStrategy;
+ }
- /**
- *
- * @return true if type loose is used.
- */
- public boolean isTypeLoose() {
- return this.typeLoose;
+ public List getArrayItemWalkListeners() {
+ return this.itemWalkListeners;
}
- public void setTypeLoose(boolean typeLoose) {
- this.typeLoose = typeLoose;
+ public ExecutionContextCustomizer getExecutionContextCustomizer() {
+ return this.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
+ * 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 void setFailFast(final boolean failFast) {
- this.failFast = failFast;
- }
-
- public boolean isFailFast() {
- return this.failFast;
- }
-
- public void setApplyDefaultsStrategy(ApplyDefaultsStrategy applyDefaultsStrategy) {
- this.applyDefaultsStrategy = applyDefaultsStrategy != null ? applyDefaultsStrategy
- : ApplyDefaultsStrategy.EMPTY_APPLY_DEFAULTS_STRATEGY;
+ public Boolean getFormatAssertionsEnabled() {
+ return formatAssertionsEnabled;
}
- public ApplyDefaultsStrategy getApplyDefaultsStrategy() {
- return this.applyDefaultsStrategy;
+ WalkListenerRunner getItemWalkListenerRunner() {
+ return this.itemWalkListenerRunner;
}
- public boolean isHandleNullableField() {
- return this.handleNullableField;
+ WalkListenerRunner getKeywordWalkListenerRunner() {
+ return this.keywordWalkListenerRunner;
}
- public void setHandleNullableField(boolean handleNullableField) {
- this.handleNullableField = handleNullableField;
+ public Map> getKeywordWalkListenersMap() {
+ return this.keywordWalkListenersMap;
}
/**
- * Gets whether to use a ECMA-262 compliant regular expression validator.
+ * Get the locale to consider when generating localised messages (default is the
+ * JVM default).
*
- * This defaults to the false and setting true require inclusion of optional
- * org.jruby.joni:joni or org.graalvm.js:js dependencies.
+ * This locale is on a schema basis and will be used as the default locale for
+ * {@link com.networknt.schema.ExecutionConfig}.
*
- * @return true if ECMA-262 compliant
+ * @return The locale.
*/
- public boolean isEcma262Validator() {
- return !(this.regularExpressionFactory instanceof JDKRegularExpressionFactory);
+ 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;
}
/**
- * 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
+ * Get the message source to use for generating localised messages.
+ *
+ * @return the message source
*/
- public void setEcma262Validator(boolean ecma262Validator) {
- this.regularExpressionFactory = ecma262Validator ? ECMAScriptRegularExpressionFactory.getInstance()
- : JDKRegularExpressionFactory.getInstance();
+ public MessageSource getMessageSource() {
+ if (this.messageSource == null) {
+ return DefaultMessageSource.getInstance();
+ }
+ return this.messageSource;
}
/**
- * 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.
+ * Get the approach used to generate paths in messages, logs and errors.
*
- * @return the factory
+ * @return The path generation approach.
*/
- public RegularExpressionFactory getRegularExpressionFactory() {
- return regularExpressionFactory;
+ public PathType getPathType() {
+ return this.pathType;
}
/**
- * 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.
+ * Gets the max depth of the evaluation path to preload when preloading refs.
*
- * @see JDKRegularExpressionFactory
- * @see ECMAScriptRegularExpressionFactory
- * @param regularExpressionFactory the factory
+ * @return the max depth to preload
*/
- public void setRegularExpressionFactory(RegularExpressionFactory regularExpressionFactory) {
- this.regularExpressionFactory = regularExpressionFactory;
- }
-
- public boolean isJavaSemantics() {
- return this.javaSemantics;
- }
-
- public void setJavaSemantics(boolean javaSemantics) {
- this.javaSemantics = javaSemantics;
- }
-
- public boolean isCustomMessageSupported() {
- return customMessageSupported;
- }
-
- public void setCustomMessageSupported(boolean customMessageSupported) {
- this.customMessageSupported = customMessageSupported;
- }
-
- 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 int getPreloadJsonSchemaRefMaxNestingDepth() {
+ return preloadJsonSchemaRefMaxNestingDepth;
}
- public void addPropertyWalkListeners(List propertyWalkListeners) {
- this.propertyWalkListeners.addAll(propertyWalkListeners);
+ WalkListenerRunner getPropertyWalkListenerRunner() {
+ return this.propertyWalkListenerRunner;
}
- public void addPropertyWalkListener(JsonSchemaWalkListener propertyWalkListener) {
- this.propertyWalkListeners.add(propertyWalkListener);
+ public List getPropertyWalkListeners() {
+ return this.propertyWalkListeners;
}
- public void addItemWalkListener(JsonSchemaWalkListener itemWalkListener) {
- this.itemWalkListeners.add(itemWalkListener);
+ /**
+ * 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;
}
- public void addItemWalkListeners(List itemWalkListeners) {
- this.itemWalkListeners.addAll(itemWalkListeners);
+ /**
+ * Gets the schema id validator to validate $id.
+ *
+ * @return the validator
+ */
+ public JsonSchemaIdValidator getSchemaIdValidator() {
+ return schemaIdValidator;
}
- public List getPropertyWalkListeners() {
- return this.propertyWalkListeners;
+ /**
+ * 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 Map> getKeywordWalkListenersMap() {
- return this.keywordWalkListenersMap;
+ @Deprecated
+ public boolean isCustomMessageSupported() {
+ return this.errorMessageKeyword != null;
}
- public List getArrayItemWalkListeners() {
- return this.itemWalkListeners;
+ public String getErrorMessageKeyword() {
+ return this.errorMessageKeyword;
}
- private final WalkListenerRunner itemWalkListenerRunner = new DefaultItemWalkListenerRunner(getArrayItemWalkListeners());
-
- WalkListenerRunner getItemWalkListenerRunner() {
- return this.itemWalkListenerRunner;
+ /**
+ * 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);
}
- private final WalkListenerRunner keywordWalkListenerRunner = new DefaultKeywordWalkListenerRunner(getKeywordWalkListenersMap());
-
- WalkListenerRunner getKeywordWalkListenerRunner() {
- return this.keywordWalkListenerRunner;
- }
-
- private final WalkListenerRunner propertyWalkListenerRunner = new DefaultPropertyWalkListenerRunner(getPropertyWalkListeners());
-
- WalkListenerRunner getPropertyWalkListenerRunner() {
- return this.propertyWalkListenerRunner;
+ public boolean isFailFast() {
+ return this.failFast;
}
- public SchemaValidatorsConfig() {
+ /**
+ * Deprecated use {{@link #isNullableKeywordEnabled()} instead.
+ *
+ * @return true if the nullable keyword is enabled
+ */
+ @Deprecated
+ public boolean isHandleNullableField() {
+ return isNullableKeywordEnabled();
}
- public ExecutionContextCustomizer getExecutionContextCustomizer() {
- return this.executionContextCustomizer;
+ /**
+ * Gets if the nullable keyword is enabled.
+ *
+ * @return true if the nullable keyword is enabled
+ */
+ public boolean isNullableKeywordEnabled() {
+ return this.nullableKeywordEnabled;
}
- public void setExecutionContextCustomizer(ExecutionContextCustomizer executionContextCustomizer) {
- this.executionContextCustomizer = executionContextCustomizer;
+ public boolean isJavaSemantics() {
+ return this.javaSemantics;
}
public boolean isLosslessNarrowing() {
return this.losslessNarrowing;
}
- public void setLosslessNarrowing(boolean losslessNarrowing) {
- this.losslessNarrowing = 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 this.openAPI3StyleDiscriminators;
- }
-
- /**
- * 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 or not discriminators should be
- * used. Defaults to false
- * @since 1.0.51
- */
- public void setOpenAPI3StyleDiscriminators(boolean openAPI3StyleDiscriminators) {
- this.openAPI3StyleDiscriminators = openAPI3StyleDiscriminators;
+ return isDiscriminatorKeywordEnabled();
}
/**
- * Sets if collectors are to be loaded.
- *
- * This is deprecated in favor of the caller calling {@link CollectorContext#loadCollectors()} manually.
+ * Gets if the discriminator keyword is enabled.
*
- * @param loadCollectors to load collectors
+ * @return true if the discriminator keyword is enabled
*/
- @Deprecated
- public void setLoadCollectors(boolean loadCollectors) {
- this.loadCollectors = loadCollectors;
+ public boolean isDiscriminatorKeywordEnabled() {
+ return this.discriminatorKeywordEnabled;
}
/**
- * Gets if collectors are to be loaded.
+ * Gets if the schema should be preloaded.
*
- * @return if collectors are to be loader
+ * @return true if it should be preloaded
*/
- @Deprecated
- public boolean doLoadCollectors() {
- return this.loadCollectors;
+ public boolean isPreloadJsonSchema() {
+ return preloadJsonSchema;
}
public boolean isReadOnly() {
return null != this.readOnly && this.readOnly;
}
- public void setReadOnly(boolean readOnly) {
- this.readOnly = readOnly;
- }
-
- public boolean isWriteOnly() {
- return null != this.writeOnly && this.writeOnly;
- }
-
- public void setWriteOnly(boolean writeOnly) {
- this.writeOnly = writeOnly;
+ /**
+ * 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);
}
/**
- * Use {@code isReadOnly} or {@code isWriteOnly}
- * @return true if schema is used to write data
+ * Determines if the validator should perform strict checking.
+ *
+ * @param keyword the keyword
+ * @param defaultValue the default value
+ * @return whether to perform a strict validation
*/
- @Deprecated
- public boolean isWriteMode() {
- return null == this.writeOnly || this.writeOnly;
+ public boolean isStrict(String keyword, Boolean defaultValue) {
+ return this.strictness.getOrDefault(Objects.requireNonNull(keyword, "keyword cannot be null"), defaultValue);
}
/**
- * Set the approach used to generate paths in messages, logs and errors (default is PathType.LEGACY).
*
- * @param pathType The path generation approach.
+ * @return true if type loose is used.
*/
- public void setPathType(PathType pathType) {
- this.pathType = pathType;
+ public boolean isTypeLoose() {
+ return this.typeLoose;
+ }
+
+ public boolean isWriteOnly() {
+ return null != this.writeOnly && this.writeOnly;
+ }
+
+ public void setApplyDefaultsStrategy(ApplyDefaultsStrategy applyDefaultsStrategy) {
+ this.applyDefaultsStrategy = applyDefaultsStrategy != null ? applyDefaultsStrategy
+ : ApplyDefaultsStrategy.EMPTY_APPLY_DEFAULTS_STRATEGY;
}
/**
- * Get the approach used to generate paths in messages, logs and errors.
- *
- * @return The path generation approach.
+ * 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 PathType getPathType() {
- return this.pathType;
+ public void setCacheRefs(boolean cacheRefs) {
+ this.cacheRefs = cacheRefs;
}
/**
- * 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.
+ * Sets whether custom error messages in the schema are used.
*
- * 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.
+ * This is deprecated in favor of setting the error message keyword to use.
+ *
+ * @param customMessageSupported true to use message as the error message keyword
*/
- public boolean isStrict(String keyword) {
- return isStrict(keyword, Boolean.TRUE);
+ @Deprecated
+ public void setCustomMessageSupported(boolean customMessageSupported) {
+ this.errorMessageKeyword = customMessageSupported ? "message" : null;
}
/**
- * Determines if the validator should perform strict checking.
+ * 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 keyword the keyword
- * @param defaultValue the default value
- * @return whether to perform a strict validation
+ * @param ecma262Validator true if ECMA-262 compliant
*/
- public boolean isStrict(String keyword, Boolean defaultValue) {
- return this.strictness.getOrDefault(Objects.requireNonNull(keyword, "keyword cannot be null"), defaultValue);
+ public void setEcma262Validator(boolean ecma262Validator) {
+ this.regularExpressionFactory = ecma262Validator ? ECMAScriptRegularExpressionFactory.getInstance()
+ : JDKRegularExpressionFactory.getInstance();
+ }
+
+ public void setExecutionContextCustomizer(ExecutionContextCustomizer executionContextCustomizer) {
+ this.executionContextCustomizer = executionContextCustomizer;
}
/**
- * 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
+ * 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 setStrict(String keyword, boolean strict) {
- this.strictness.put(Objects.requireNonNull(keyword, "keyword cannot be null"), strict);
+ public void setFailFast(final boolean failFast) {
+ this.failFast = failFast;
}
/**
- * Get the locale to consider when generating localised messages (default is the
- * JVM default).
+ * Sets the format assertion enabled flag.
*
- * This locale is on a schema basis and will be used as the default locale for
- * {@link com.networknt.schema.ExecutionConfig}.
- *
- * @return The locale.
+ * 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
*/
- 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;
+ @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;
}
/**
@@ -610,23 +639,20 @@ public Locale getLocale() {
* 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;
}
- /**
- * 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;
+ public void setLosslessNarrowing(boolean losslessNarrowing) {
+ this.losslessNarrowing = losslessNarrowing;
}
/**
@@ -639,36 +665,85 @@ public void setMessageSource(MessageSource messageSource) {
}
/**
- * 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.
+ * 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
+ *
*
- * @return the format assertions enabled flag
+ * @param openAPI3StyleDiscriminators whether or not discriminators should be
+ * used. Defaults to false
+ * @since 1.0.51
*/
- public Boolean getFormatAssertionsEnabled() {
- return formatAssertionsEnabled;
+ public void setOpenAPI3StyleDiscriminators(boolean openAPI3StyleDiscriminators) {
+ this.discriminatorKeywordEnabled = openAPI3StyleDiscriminators;
}
/**
- * Sets the format assertion enabled flag.
- *
- * @param formatAssertionsEnabled the format assertions enabled flag
+ * Set the approach used to generate paths in messages, logs and errors (default is PathType.LEGACY).
+ *
+ * @param pathType The path generation approach.
*/
- public void setFormatAssertionsEnabled(Boolean formatAssertionsEnabled) {
- this.formatAssertionsEnabled = formatAssertionsEnabled;
+ public void setPathType(PathType pathType) {
+ this.pathType = pathType;
}
/**
- * Gets the schema id validator to validate $id.
+ * Sets if the schema should be preloaded.
*
- * @return the validator
+ * @param preloadJsonSchema true to preload
*/
- public JsonSchemaIdValidator getSchemaIdValidator() {
- return schemaIdValidator;
+ 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;
}
/**
@@ -681,63 +756,646 @@ public void setSchemaIdValidator(JsonSchemaIdValidator schemaIdValidator) {
}
/**
- * Gets if the schema should be preloaded.
+ * 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.
*
- * @return true if it should be preloaded
+ * @param keyword The keyword to adjust (not null)
+ * @param strict Whether to perform strict validations
*/
- public boolean isPreloadJsonSchema() {
- return preloadJsonSchema;
+ 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;
}
/**
- * Sets if the schema should be preloaded.
- *
- * @param preloadJsonSchema true to preload
+ * Builder for {@link SchemaValidatorsConfig}.
*/
- public void setPreloadJsonSchema(boolean preloadJsonSchema) {
- this.preloadJsonSchema = preloadJsonSchema;
+ 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 = false;
+ 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 a 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.
+ */
+ 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