1 /* 2 * Copyright (c) 2016 Network New Technologies Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.networknt.schema; 18 19 import com.fasterxml.jackson.databind.JsonNode; 20 import com.networknt.schema.i18n.DefaultMessageSource; 21 import com.networknt.schema.i18n.MessageSource; 22 import com.networknt.schema.walk.DefaultItemWalkListenerRunner; 23 import com.networknt.schema.walk.DefaultKeywordWalkListenerRunner; 24 import com.networknt.schema.walk.DefaultPropertyWalkListenerRunner; 25 import com.networknt.schema.walk.JsonSchemaWalkListener; 26 import com.networknt.schema.walk.WalkListenerRunner; 27 28 import java.util.ArrayList; 29 import java.util.HashMap; 30 import java.util.List; 31 import java.util.Locale; 32 import java.util.Map; 33 import java.util.Objects; 34 35 public class SchemaValidatorsConfig { 36 /** 37 * Used to validate the acceptable $id values. 38 */ 39 private JsonSchemaIdValidator schemaIdValidator = JsonSchemaIdValidator.DEFAULT; 40 41 /** 42 * when validate type, if TYPE_LOOSE = true, will try to convert string to 43 * different types to match the type defined in schema. 44 */ 45 private boolean typeLoose; 46 47 /** 48 * When set to true, validator process is stop immediately when a very first 49 * validation error is discovered. 50 */ 51 private boolean failFast; 52 53 /** 54 * When set to true, walker sets nodes that are missing or NullNode to the 55 * default value, if any, and mutate the input json. 56 */ 57 private ApplyDefaultsStrategy applyDefaultsStrategy = ApplyDefaultsStrategy.EMPTY_APPLY_DEFAULTS_STRATEGY; 58 59 /** 60 * When set to true, use ECMA-262 compatible validator 61 */ 62 private boolean ecma262Validator; 63 64 /** 65 * When set to true, use Java-specific semantics rather than native JavaScript 66 * semantics 67 */ 68 private boolean javaSemantics; 69 70 /** 71 * When set to true, can interpret round doubles as integers 72 */ 73 private boolean losslessNarrowing; 74 75 /** 76 * When set to true, "messages" provided in schema are used for forming validation errors 77 * else default messages are used 78 */ 79 private boolean isCustomMessageSupported = true; 80 81 /** 82 * When set to true, support for discriminators is enabled for validations of 83 * oneOf, anyOf and allOf as described on <a href= 84 * "https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.3.md#discriminatorObject">GitHub</a>. 85 */ 86 private boolean openAPI3StyleDiscriminators = false; 87 88 /** 89 * Contains a mapping of how strict a keyword's validators should be. 90 * Defaults to {@literal true}. 91 * <p> 92 * Each validator has its own understanding of what constitutes strict 93 * and permissive. 94 */ 95 private final Map<String, Boolean> strictness = new HashMap<>(0); 96 97 /** 98 * When a field is set as nullable in the OpenAPI specification, the schema 99 * validator validates that it is nullable however continues with validation 100 * against the nullable field 101 * <p> 102 * If handleNullableField is set to true && incoming field is nullable && value 103 * is field: null --> succeed If handleNullableField is set to false && incoming 104 * field is nullable && value is field: null --> it is up to the type validator 105 * using the SchemaValidator to handle it. 106 */ 107 private boolean handleNullableField = true; 108 109 /** 110 * When set to true assumes that schema is used to validate incoming data from an API. 111 */ 112 private Boolean readOnly = null; 113 114 /** 115 * When set to true assumes that schema is used to to validate outgoing data from an API. 116 */ 117 private Boolean writeOnly = null; 118 119 /** 120 * The approach used to generate paths in reported messages, logs and errors. Default is the legacy "JSONPath-like" approach. 121 */ 122 private PathType pathType = PathType.DEFAULT; 123 124 /** 125 * Controls if the schema will automatically be preloaded. 126 */ 127 private boolean preloadJsonSchema = true; 128 129 // This is just a constant for listening to all Keywords. 130 public static final String ALL_KEYWORD_WALK_LISTENER_KEY = "com.networknt.AllKeywordWalkListener"; 131 132 private final Map<String, List<JsonSchemaWalkListener>> keywordWalkListenersMap = new HashMap<>(); 133 134 private final List<JsonSchemaWalkListener> propertyWalkListeners = new ArrayList<>(); 135 136 private final List<JsonSchemaWalkListener> itemWalkListeners = new ArrayList<>(); 137 138 private ExecutionContextCustomizer executionContextCustomizer; 139 140 private boolean loadCollectors = true; 141 142 /** 143 * The Locale to consider when loading validation messages from the default resource bundle. 144 */ 145 private Locale locale; 146 147 /** 148 * The message source to use for generating localised messages. 149 */ 150 private MessageSource messageSource; 151 152 /** 153 * Since Draft 2019-09 format assertions are not enabled by default. 154 */ 155 private Boolean formatAssertionsEnabled = null; 156 157 /************************ START OF UNEVALUATED CHECKS **********************************/ 158 159 // These are costly in terms of performance so we provide a way to disable them. 160 private boolean disableUnevaluatedItems = false; 161 private boolean disableUnevaluatedProperties = false; 162 disableUnevaluatedAnalysis()163 public SchemaValidatorsConfig disableUnevaluatedAnalysis() { 164 disableUnevaluatedItems(); 165 disableUnevaluatedProperties(); 166 return this; 167 } 168 disableUnevaluatedItems()169 public SchemaValidatorsConfig disableUnevaluatedItems() { 170 this.disableUnevaluatedItems = true; 171 return this; 172 } 173 disableUnevaluatedProperties()174 public SchemaValidatorsConfig disableUnevaluatedProperties() { 175 this.disableUnevaluatedProperties = true; 176 return this; 177 } 178 enableUnevaluatedAnalysis()179 public SchemaValidatorsConfig enableUnevaluatedAnalysis() { 180 enableUnevaluatedItems(); 181 enableUnevaluatedProperties(); 182 return this; 183 } 184 enableUnevaluatedItems()185 public SchemaValidatorsConfig enableUnevaluatedItems() { 186 this.disableUnevaluatedItems = false; 187 return this; 188 } 189 enableUnevaluatedProperties()190 public SchemaValidatorsConfig enableUnevaluatedProperties() { 191 this.disableUnevaluatedProperties = false; 192 return this; 193 } 194 isUnevaluatedItemsAnalysisDisabled()195 public boolean isUnevaluatedItemsAnalysisDisabled() { 196 return this.disableUnevaluatedItems; 197 } 198 isUnevaluatedItemsAnalysisEnabled()199 public boolean isUnevaluatedItemsAnalysisEnabled() { 200 return !isUnevaluatedItemsAnalysisDisabled(); 201 } 202 isUnevaluatedPropertiesAnalysisDisabled()203 public boolean isUnevaluatedPropertiesAnalysisDisabled() { 204 return this.disableUnevaluatedProperties; 205 } 206 isUnevaluatedPropertiesAnalysisEnabled()207 public boolean isUnevaluatedPropertiesAnalysisEnabled() { 208 return !isUnevaluatedPropertiesAnalysisDisabled(); 209 } 210 211 /************************ END OF UNEVALUATED CHECKS **********************************/ 212 213 /** 214 * 215 * @return true if type loose is used. 216 */ isTypeLoose()217 public boolean isTypeLoose() { 218 return this.typeLoose; 219 } 220 setTypeLoose(boolean typeLoose)221 public void setTypeLoose(boolean typeLoose) { 222 this.typeLoose = typeLoose; 223 } 224 225 /** 226 * When enabled, 227 * {@link JsonValidator#validate(ExecutionContext, JsonNode, JsonNode, JsonNodePath)} 228 * doesn't return any {@link java.util.Set}<{@link ValidationMessage}>, 229 * instead a {@link JsonSchemaException} is thrown as soon as a validation 230 * errors is discovered. 231 * 232 * @param failFast boolean 233 */ setFailFast(final boolean failFast)234 public void setFailFast(final boolean failFast) { 235 this.failFast = failFast; 236 } 237 isFailFast()238 public boolean isFailFast() { 239 return this.failFast; 240 } 241 setApplyDefaultsStrategy(ApplyDefaultsStrategy applyDefaultsStrategy)242 public void setApplyDefaultsStrategy(ApplyDefaultsStrategy applyDefaultsStrategy) { 243 this.applyDefaultsStrategy = applyDefaultsStrategy != null ? applyDefaultsStrategy 244 : ApplyDefaultsStrategy.EMPTY_APPLY_DEFAULTS_STRATEGY; 245 } 246 getApplyDefaultsStrategy()247 public ApplyDefaultsStrategy getApplyDefaultsStrategy() { 248 return this.applyDefaultsStrategy; 249 } 250 isHandleNullableField()251 public boolean isHandleNullableField() { 252 return this.handleNullableField; 253 } 254 setHandleNullableField(boolean handleNullableField)255 public void setHandleNullableField(boolean handleNullableField) { 256 this.handleNullableField = handleNullableField; 257 } 258 isEcma262Validator()259 public boolean isEcma262Validator() { 260 return this.ecma262Validator; 261 } 262 setEcma262Validator(boolean ecma262Validator)263 public void setEcma262Validator(boolean ecma262Validator) { 264 this.ecma262Validator = ecma262Validator; 265 } 266 isJavaSemantics()267 public boolean isJavaSemantics() { 268 return this.javaSemantics; 269 } 270 setJavaSemantics(boolean javaSemantics)271 public void setJavaSemantics(boolean javaSemantics) { 272 this.javaSemantics = javaSemantics; 273 } 274 isCustomMessageSupported()275 public boolean isCustomMessageSupported() { 276 return isCustomMessageSupported; 277 } 278 setCustomMessageSupported(boolean customMessageSupported)279 public void setCustomMessageSupported(boolean customMessageSupported) { 280 this.isCustomMessageSupported = customMessageSupported; 281 } 282 addKeywordWalkListener(JsonSchemaWalkListener keywordWalkListener)283 public void addKeywordWalkListener(JsonSchemaWalkListener keywordWalkListener) { 284 if (this.keywordWalkListenersMap.get(ALL_KEYWORD_WALK_LISTENER_KEY) == null) { 285 List<JsonSchemaWalkListener> keywordWalkListeners = new ArrayList<>(); 286 this.keywordWalkListenersMap.put(ALL_KEYWORD_WALK_LISTENER_KEY, keywordWalkListeners); 287 } 288 this.keywordWalkListenersMap.get(ALL_KEYWORD_WALK_LISTENER_KEY).add(keywordWalkListener); 289 } 290 addKeywordWalkListener(String keyword, JsonSchemaWalkListener keywordWalkListener)291 public void addKeywordWalkListener(String keyword, JsonSchemaWalkListener keywordWalkListener) { 292 if (this.keywordWalkListenersMap.get(keyword) == null) { 293 List<JsonSchemaWalkListener> keywordWalkListeners = new ArrayList<>(); 294 this.keywordWalkListenersMap.put(keyword, keywordWalkListeners); 295 } 296 this.keywordWalkListenersMap.get(keyword).add(keywordWalkListener); 297 } 298 addKeywordWalkListeners(List<JsonSchemaWalkListener> keywordWalkListeners)299 public void addKeywordWalkListeners(List<JsonSchemaWalkListener> keywordWalkListeners) { 300 if (this.keywordWalkListenersMap.get(ALL_KEYWORD_WALK_LISTENER_KEY) == null) { 301 List<JsonSchemaWalkListener> ikeywordWalkListeners = new ArrayList<>(); 302 this.keywordWalkListenersMap.put(ALL_KEYWORD_WALK_LISTENER_KEY, ikeywordWalkListeners); 303 } 304 this.keywordWalkListenersMap.get(ALL_KEYWORD_WALK_LISTENER_KEY).addAll(keywordWalkListeners); 305 } 306 addKeywordWalkListeners(String keyword, List<JsonSchemaWalkListener> keywordWalkListeners)307 public void addKeywordWalkListeners(String keyword, List<JsonSchemaWalkListener> keywordWalkListeners) { 308 if (this.keywordWalkListenersMap.get(keyword) == null) { 309 List<JsonSchemaWalkListener> ikeywordWalkListeners = new ArrayList<>(); 310 this.keywordWalkListenersMap.put(keyword, ikeywordWalkListeners); 311 } 312 this.keywordWalkListenersMap.get(keyword).addAll(keywordWalkListeners); 313 } 314 addPropertyWalkListeners(List<JsonSchemaWalkListener> propertyWalkListeners)315 public void addPropertyWalkListeners(List<JsonSchemaWalkListener> propertyWalkListeners) { 316 this.propertyWalkListeners.addAll(propertyWalkListeners); 317 } 318 addPropertyWalkListener(JsonSchemaWalkListener propertyWalkListener)319 public void addPropertyWalkListener(JsonSchemaWalkListener propertyWalkListener) { 320 this.propertyWalkListeners.add(propertyWalkListener); 321 } 322 addItemWalkListener(JsonSchemaWalkListener itemWalkListener)323 public void addItemWalkListener(JsonSchemaWalkListener itemWalkListener) { 324 this.itemWalkListeners.add(itemWalkListener); 325 } 326 addItemWalkListeners(List<JsonSchemaWalkListener> itemWalkListeners)327 public void addItemWalkListeners(List<JsonSchemaWalkListener> itemWalkListeners) { 328 this.itemWalkListeners.addAll(itemWalkListeners); 329 } 330 getPropertyWalkListeners()331 public List<JsonSchemaWalkListener> getPropertyWalkListeners() { 332 return this.propertyWalkListeners; 333 } 334 getKeywordWalkListenersMap()335 public Map<String, List<JsonSchemaWalkListener>> getKeywordWalkListenersMap() { 336 return this.keywordWalkListenersMap; 337 } 338 getArrayItemWalkListeners()339 public List<JsonSchemaWalkListener> getArrayItemWalkListeners() { 340 return this.itemWalkListeners; 341 } 342 343 private final WalkListenerRunner itemWalkListenerRunner = new DefaultItemWalkListenerRunner(getArrayItemWalkListeners()); 344 getItemWalkListenerRunner()345 WalkListenerRunner getItemWalkListenerRunner() { 346 return this.itemWalkListenerRunner; 347 } 348 349 private WalkListenerRunner keywordWalkListenerRunner = new DefaultKeywordWalkListenerRunner(getKeywordWalkListenersMap()); 350 getKeywordWalkListenerRunner()351 WalkListenerRunner getKeywordWalkListenerRunner() { 352 return this.keywordWalkListenerRunner; 353 } 354 355 private WalkListenerRunner propertyWalkListenerRunner = new DefaultPropertyWalkListenerRunner(getPropertyWalkListeners()); 356 getPropertyWalkListenerRunner()357 WalkListenerRunner getPropertyWalkListenerRunner() { 358 return this.propertyWalkListenerRunner; 359 } 360 SchemaValidatorsConfig()361 public SchemaValidatorsConfig() { 362 } 363 getExecutionContextCustomizer()364 public ExecutionContextCustomizer getExecutionContextCustomizer() { 365 return this.executionContextCustomizer; 366 } 367 setExecutionContextCustomizer(ExecutionContextCustomizer executionContextCustomizer)368 public void setExecutionContextCustomizer(ExecutionContextCustomizer executionContextCustomizer) { 369 this.executionContextCustomizer = executionContextCustomizer; 370 } 371 isLosslessNarrowing()372 public boolean isLosslessNarrowing() { 373 return this.losslessNarrowing; 374 } 375 setLosslessNarrowing(boolean losslessNarrowing)376 public void setLosslessNarrowing(boolean losslessNarrowing) { 377 this.losslessNarrowing = losslessNarrowing; 378 } 379 380 /** 381 * Indicates whether OpenAPI 3 style discriminators should be supported 382 * 383 * @return true in case discriminators are enabled 384 * @since 1.0.51 385 */ isOpenAPI3StyleDiscriminators()386 public boolean isOpenAPI3StyleDiscriminators() { 387 return this.openAPI3StyleDiscriminators; 388 } 389 390 /** 391 * When enabled, the validation of <code>anyOf</code> and <code>allOf</code> in 392 * polymorphism will respect OpenAPI 3 style discriminators as described in the 393 * <a href= 394 * "https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.3.md#discriminatorObject">OpenAPI 395 * 3.0.3 spec</a>. The presence of a discriminator configuration on the schema 396 * will lead to the following changes in the behavior: 397 * <ul> 398 * <li>for <code>oneOf</code> the spec is unfortunately very vague. Whether 399 * <code>oneOf</code> semantics should be affected by discriminators or not is 400 * not even 100% clear within the members of the OAS steering committee. 401 * Therefore <code>oneOf</code> at the moment ignores discriminators</li> 402 * <li>for <code>anyOf</code> the validation will choose one of the candidate 403 * schemas for validation based on the discriminator property value and will 404 * pass validation when this specific schema passes. This is in particular 405 * useful when the payload could match multiple candidates in the 406 * <code>anyOf</code> list and could lead to ambiguity. Example: type B has all 407 * mandatory properties of A and adds more mandatory ones. Whether the payload 408 * is an A or B is determined via the discriminator property name. A payload 409 * indicating it is an instance of B then requires passing the validation of B 410 * and passing the validation of A would not be sufficient anymore.</li> 411 * <li>for <code>allOf</code> use cases with discriminators defined on the 412 * copied-in parent type, it is possible to automatically validate against a 413 * subtype. Example: some schema specifies that there is a field of type A. A 414 * carries a discriminator field and B inherits from A. Then B is automatically 415 * a candidate for validation as well and will be chosen in case the 416 * discriminator property matches</li> 417 * </ul> 418 * 419 * @param openAPI3StyleDiscriminators whether or not discriminators should be 420 * used. Defaults to <code>false</code> 421 * @since 1.0.51 422 */ setOpenAPI3StyleDiscriminators(boolean openAPI3StyleDiscriminators)423 public void setOpenAPI3StyleDiscriminators(boolean openAPI3StyleDiscriminators) { 424 this.openAPI3StyleDiscriminators = openAPI3StyleDiscriminators; 425 } 426 setLoadCollectors(boolean loadCollectors)427 public void setLoadCollectors(boolean loadCollectors) { 428 this.loadCollectors = loadCollectors; 429 } 430 doLoadCollectors()431 public boolean doLoadCollectors() { 432 return this.loadCollectors; 433 } 434 isReadOnly()435 public boolean isReadOnly() { 436 return null != this.readOnly && this.readOnly; 437 } 438 setReadOnly(boolean readOnly)439 public void setReadOnly(boolean readOnly) { 440 this.readOnly = readOnly; 441 } 442 isWriteOnly()443 public boolean isWriteOnly() { 444 return null != this.writeOnly && this.writeOnly; 445 } 446 setWriteOnly(boolean writeOnly)447 public void setWriteOnly(boolean writeOnly) { 448 this.writeOnly = writeOnly; 449 } 450 451 /** 452 * Use {@code isReadOnly} or {@code isWriteOnly} 453 * @return true if schema is used to write data 454 */ 455 @Deprecated isWriteMode()456 public boolean isWriteMode() { 457 return null == this.writeOnly || this.writeOnly; 458 } 459 460 /** 461 * Set the approach used to generate paths in messages, logs and errors (default is PathType.LEGACY). 462 * 463 * @param pathType The path generation approach. 464 */ setPathType(PathType pathType)465 public void setPathType(PathType pathType) { 466 this.pathType = pathType; 467 } 468 469 /** 470 * Get the approach used to generate paths in messages, logs and errors. 471 * 472 * @return The path generation approach. 473 */ getPathType()474 public PathType getPathType() { 475 return this.pathType; 476 } 477 478 /** 479 * Answers whether a keyword's validators may relax their analysis. The 480 * default is to perform strict checking. One must explicitly allow a 481 * validator to be more permissive. 482 * <p> 483 * Each validator has its own understanding of what is permissive and 484 * strict. Consult the keyword's documentation for details. 485 * 486 * @param keyword the keyword to adjust (not null) 487 * @return Whether to perform a strict validation. 488 */ isStrict(String keyword)489 public boolean isStrict(String keyword) { 490 return isStrict(keyword, Boolean.TRUE); 491 } 492 493 /** 494 * Determines if the validator should perform strict checking. 495 * 496 * @param keyword the keyword 497 * @param defaultValue the default value 498 * @return whether to perform a strict validation 499 */ isStrict(String keyword, Boolean defaultValue)500 public boolean isStrict(String keyword, Boolean defaultValue) { 501 return this.strictness.getOrDefault(Objects.requireNonNull(keyword, "keyword cannot be null"), defaultValue); 502 } 503 504 /** 505 * Alters the strictness of validations for a specific keyword. When set to 506 * {@literal true}, instructs the keyword's validators to perform strict 507 * validation. Otherwise, a validator may perform a more permissive check. 508 * 509 * @param keyword The keyword to adjust (not null) 510 * @param strict Whether to perform strict validations 511 */ setStrict(String keyword, boolean strict)512 public void setStrict(String keyword, boolean strict) { 513 this.strictness.put(Objects.requireNonNull(keyword, "keyword cannot be null"), strict); 514 } 515 516 /** 517 * Get the locale to consider when generating localised messages (default is the 518 * JVM default). 519 * <p> 520 * This locale is on a schema basis and will be used as the default locale for 521 * {@link com.networknt.schema.ExecutionConfig}. 522 * 523 * @return The locale. 524 */ getLocale()525 public Locale getLocale() { 526 if (this.locale == null) { 527 // This should not be cached as it can be changed using Locale#setDefault(Locale) 528 return Locale.getDefault(); 529 } 530 return this.locale; 531 } 532 533 /** 534 * Set the locale to consider when generating localised messages. 535 * <p> 536 * Note that this locale is set on a schema basis. To configure the schema on a 537 * per execution basis use 538 * {@link com.networknt.schema.ExecutionConfig#setLocale(Locale)}. 539 * 540 * @param locale The locale. 541 */ setLocale(Locale locale)542 public void setLocale(Locale locale) { 543 this.locale = locale; 544 } 545 546 /** 547 * Get the message source to use for generating localised messages. 548 * 549 * @return the message source 550 */ getMessageSource()551 public MessageSource getMessageSource() { 552 if (this.messageSource == null) { 553 return DefaultMessageSource.getInstance(); 554 } 555 return this.messageSource; 556 } 557 558 /** 559 * Set the message source to use for generating localised messages. 560 * 561 * @param messageSource the message source 562 */ setMessageSource(MessageSource messageSource)563 public void setMessageSource(MessageSource messageSource) { 564 this.messageSource = messageSource; 565 } 566 567 /** 568 * Gets the format assertion enabled flag. 569 * <p> 570 * This defaults to null meaning that it will follow the defaults of the 571 * specification. 572 * <p> 573 * Since draft 2019-09 this will default to false unless enabled by using the 574 * $vocabulary keyword. 575 * 576 * @return the format assertions enabled flag 577 */ getFormatAssertionsEnabled()578 public Boolean getFormatAssertionsEnabled() { 579 return formatAssertionsEnabled; 580 } 581 582 /** 583 * Sets the format assertion enabled flag. 584 * 585 * @param formatAssertionsEnabled the format assertions enabled flag 586 */ setFormatAssertionsEnabled(Boolean formatAssertionsEnabled)587 public void setFormatAssertionsEnabled(Boolean formatAssertionsEnabled) { 588 this.formatAssertionsEnabled = formatAssertionsEnabled; 589 } 590 591 /** 592 * Gets the schema id validator to validate $id. 593 * 594 * @return the validator 595 */ getSchemaIdValidator()596 public JsonSchemaIdValidator getSchemaIdValidator() { 597 return schemaIdValidator; 598 } 599 600 /** 601 * Sets the schema id validator to validate $id. 602 * 603 * @param schemaIdValidator the validator 604 */ setSchemaIdValidator(JsonSchemaIdValidator schemaIdValidator)605 public void setSchemaIdValidator(JsonSchemaIdValidator schemaIdValidator) { 606 this.schemaIdValidator = schemaIdValidator; 607 } 608 609 /** 610 * Gets if the schema should be preloaded. 611 * 612 * @return true if it should be preloaded 613 */ isPreloadJsonSchema()614 public boolean isPreloadJsonSchema() { 615 return preloadJsonSchema; 616 } 617 618 /** 619 * Sets if the schema should be preloaded. 620 * 621 * @param preloadJsonSchema true to preload 622 */ setPreloadJsonSchema(boolean preloadJsonSchema)623 public void setPreloadJsonSchema(boolean preloadJsonSchema) { 624 this.preloadJsonSchema = preloadJsonSchema; 625 } 626 } 627