Repository: networknt/json-schema-validator
Pull request #437 (2021-08-18 12:45:50)

Implementation of #436
Implementation of #436 


Patch:
diff --git a/src/main/java/com/networknt/schema/AllOfValidator.java b/src/main/java/com/networknt/schema/AllOfValidator.java
index 0219e39..f1312bf 100644
--- a/src/main/java/com/networknt/schema/AllOfValidator.java
+++ b/src/main/java/com/networknt/schema/AllOfValidator.java
@@ -70,7 +70,10 @@ public class AllOfValidator extends BaseJsonValidator implements JsonValidator {
                                 registerAndMergeDiscriminator(currentDiscriminatorContext, discriminator, parentSchema, at);
                                 // now we have to check whether we have hit the right target
                                 final String discriminatorPropertyName = discriminator.get("propertyName").asText();
-                                final String discriminatorPropertyValue = node.get(discriminatorPropertyName).textValue();
+                                final JsonNode discriminatorNode = node.get(discriminatorPropertyName);
+                                final String discriminatorPropertyValue = discriminatorNode == null
+                                        ? null
+                                        : discriminatorNode.textValue();
 
                                 final JsonSchema jsonSchema = parentSchema;
                                 checkDiscriminatorMatch(
diff --git a/src/main/java/com/networknt/schema/AnyOfValidator.java b/src/main/java/com/networknt/schema/AnyOfValidator.java
index 72f7a6b..5b1a471 100644
--- a/src/main/java/com/networknt/schema/AnyOfValidator.java
+++ b/src/main/java/com/networknt/schema/AnyOfValidator.java
@@ -65,7 +65,7 @@ public class AnyOfValidator extends BaseJsonValidator implements JsonValidator {
                 if (schema.getValidators().containsKey(typeValidatorName)) {
                     TypeValidator typeValidator = ((TypeValidator) schema.getValidators().get(typeValidatorName));
                     //If schema has type validator and node type doesn't match with schemaType then ignore it
-                    //For union type, it is must to call TypeValidator
+                    //For union type, it is a must to call TypeValidator
                     if (typeValidator.getSchemaType() != JsonType.UNION && !typeValidator.equalsToSchemaType(node)) {
                         allErrors.add(buildValidationMessage(at, typeValidator.getSchemaType().toString()));
                         continue;
diff --git a/src/main/java/com/networknt/schema/BaseJsonValidator.java b/src/main/java/com/networknt/schema/BaseJsonValidator.java
index 81f4317..9ad401b 100644
--- a/src/main/java/com/networknt/schema/BaseJsonValidator.java
+++ b/src/main/java/com/networknt/schema/BaseJsonValidator.java
@@ -195,6 +195,11 @@ public abstract class BaseJsonValidator implements JsonValidator {
                                                   final ObjectNode discriminator,
                                                   final String discriminatorPropertyValue,
                                                   final JsonSchema jsonSchema) {
+        if (discriminatorPropertyValue == null) {
+            currentDiscriminatorContext.markMatch();
+            return;
+        }
+
         final JsonNode discriminatorMapping = discriminator.get("mapping");
         if (null == discriminatorMapping) {
             checkForImplicitDiscriminatorMappingMatch(currentDiscriminatorContext,
diff --git a/src/main/java/com/networknt/schema/I18nSupport.java b/src/main/java/com/networknt/schema/I18nSupport.java
new file mode 100644
index 0000000..0f22352
--- /dev/null
+++ b/src/main/java/com/networknt/schema/I18nSupport.java
@@ -0,0 +1,17 @@
+package com.networknt.schema;
+
+import java.util.ResourceBundle;
+
+/**
+ * Created by leaves chen leaves615@gmail.com on 2021/8/23.
+ *
+ * @Author leaves chen leaves615@gmail.com
+ */
+public class I18nSupport {
+    private static final String BASE_NAME = "jsv-messages";
+    private static ResourceBundle bundle = ResourceBundle.getBundle(BASE_NAME);
+
+    public static String getString(String key) {
+        return bundle.getString(key);
+    }
+}
diff --git a/src/main/java/com/networknt/schema/JsonMetaSchema.java b/src/main/java/com/networknt/schema/JsonMetaSchema.java
index c9877b9..0a87929 100644
--- a/src/main/java/com/networknt/schema/JsonMetaSchema.java
+++ b/src/main/java/com/networknt/schema/JsonMetaSchema.java
@@ -117,7 +117,8 @@ public class JsonMetaSchema {
                             new NonValidationKeyword("title"),
                             new NonValidationKeyword("description"),
                             new NonValidationKeyword("default"),
-                            new NonValidationKeyword("definitions")
+                            new NonValidationKeyword("definitions"),
+                            new NonValidationKeyword("exampleSetFlag")
                     ))
                     .build();
         }
diff --git a/src/main/java/com/networknt/schema/JsonSchema.java b/src/main/java/com/networknt/schema/JsonSchema.java
index 1050c95..3a6ad43 100644
--- a/src/main/java/com/networknt/schema/JsonSchema.java
+++ b/src/main/java/com/networknt/schema/JsonSchema.java
@@ -264,7 +264,8 @@ public class JsonSchema extends BaseJsonValidator {
                     }
 
                     final String discriminatorPropertyName = discriminatorToUse.get("propertyName").asText();
-                    final String discriminatorPropertyValue = jsonNode.get(discriminatorPropertyName).asText();
+                    final JsonNode discriminatorNode = jsonNode.get(discriminatorPropertyName);
+                    final String discriminatorPropertyValue = discriminatorNode == null ? null : discriminatorNode.asText();
                     checkDiscriminatorMatch(discriminatorContext,
                                             discriminatorToUse,
                                             discriminatorPropertyValue,
diff --git a/src/main/java/com/networknt/schema/ValidatorTypeCode.java b/src/main/java/com/networknt/schema/ValidatorTypeCode.java
index 1a9c313..cb9748e 100644
--- a/src/main/java/com/networknt/schema/ValidatorTypeCode.java
+++ b/src/main/java/com/networknt/schema/ValidatorTypeCode.java
@@ -26,54 +26,53 @@ import java.util.List;
 import java.util.Map;
 
 public enum ValidatorTypeCode implements Keyword, ErrorMessageType {
-    ADDITIONAL_PROPERTIES("additionalProperties", "1001", new MessageFormat(
-            "{0}.{1}: is not defined in the schema and the schema does not allow additional properties"), AdditionalPropertiesValidator.class, 15), // v4|v6|v7|v201909
-    ALL_OF("allOf", "1002", new MessageFormat("{0}: should be valid to all the schemas {1}"), AllOfValidator.class, 15),
-    ANY_OF("anyOf", "1003", new MessageFormat("{0}: should be valid to any of the schemas {1}"), AnyOfValidator.class, 15),
-    CROSS_EDITS("crossEdits", "1004", new MessageFormat("{0}: has an error with 'cross edits'"), null, 15),
-    DEPENDENCIES("dependencies", "1007", new MessageFormat("{0}: has an error with dependencies {1}"), DependenciesValidator.class, 15),
-    EDITS("edits", "1005", new MessageFormat("{0}: has an error with 'edits'"), null, 15),
-    ENUM("enum", "1008", new MessageFormat("{0}: does not have a value in the enumeration {1}"), EnumValidator.class, 15),
-    FORMAT("format", "1009", new MessageFormat("{0}: does not match the {1} pattern {2}"), null, 15) {
+    ADDITIONAL_PROPERTIES("additionalProperties", "1001", new MessageFormat(I18nSupport.getString("additionalProperties")), AdditionalPropertiesValidator.class, 15), // v4|v6|v7|v201909
+    ALL_OF("allOf", "1002", new MessageFormat(I18nSupport.getString("allOf")), AllOfValidator.class, 15),
+    ANY_OF("anyOf", "1003", new MessageFormat(I18nSupport.getString("anyOf")), AnyOfValidator.class, 15),
+    CROSS_EDITS("crossEdits", "1004", new MessageFormat(I18nSupport.getString("crossEdits")), null, 15),
+    DEPENDENCIES("dependencies", "1007", new MessageFormat(I18nSupport.getString("dependencies")), DependenciesValidator.class, 15),
+    EDITS("edits", "1005", new MessageFormat(I18nSupport.getString("edits")), null, 15),
+    ENUM("enum", "1008", new MessageFormat(I18nSupport.getString("enum")), EnumValidator.class, 15),
+    FORMAT("format", "1009", new MessageFormat(I18nSupport.getString("format")), null, 15) {
         @Override
         public JsonValidator newValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext)
                 throws Exception {
             throw new UnsupportedOperationException("Use FormatKeyword instead");
         }
     },
-    ITEMS("items", "1010", new MessageFormat("{0}[{1}]: no validator found at this index"), ItemsValidator.class, 15),
-    MAXIMUM("maximum", "1011", new MessageFormat("{0}: must have a maximum value of {1}"), MaximumValidator.class, 15),
-    MAX_ITEMS("maxItems", "1012", new MessageFormat("{0}: there must be a maximum of {1} items in the array"), MaxItemsValidator.class, 15),
-    MAX_LENGTH("maxLength", "1013", new MessageFormat("{0}: may only be {1} characters long"), MaxLengthValidator.class, 15),
-    MAX_PROPERTIES("maxProperties", "1014", new MessageFormat("{0}: may only have a maximum of {1} properties"), MaxPropertiesValidator.class, 15),
-    MINIMUM("minimum", "1015", new MessageFormat("{0}: must have a minimum value of {1}"), MinimumValidator.class, 15),
-    MIN_ITEMS("minItems", "1016", new MessageFormat("{0}: there must be a minimum of {1} items in the array"), MinItemsValidator.class, 15),
-    MIN_LENGTH("minLength", "1017", new MessageFormat("{0}: must be at least {1} characters long"), MinLengthValidator.class, 15),
-    MIN_PROPERTIES("minProperties", "1018", new MessageFormat("{0}: should have a minimum of {1} properties"), MinPropertiesValidator.class, 15),
-    MULTIPLE_OF("multipleOf", "1019", new MessageFormat("{0}: must be multiple of {1}"), MultipleOfValidator.class, 15),
-    NOT_ALLOWED("notAllowed", "1033", new MessageFormat("{0}.{1}: is not allowed but it is in the data"), NotAllowedValidator.class, 15),
-    NOT("not", "1020", new MessageFormat("{0}: should not be valid to the schema {1}"), NotValidator.class, 15),
-    ONE_OF("oneOf", "1022", new MessageFormat("{0}: should be valid to one and only one of the schemas {1}"), OneOfValidator.class, 15),
-    PATTERN_PROPERTIES("patternProperties", "1024", new MessageFormat("{0}: has some error with 'pattern properties'"), PatternPropertiesValidator.class, 15),
-    PATTERN("pattern", "1023", new MessageFormat("{0}: does not match the regex pattern {1}"), PatternValidator.class, 15),
-    PROPERTIES("properties", "1025", new MessageFormat("{0}: has an error with 'properties'"), PropertiesValidator.class, 15),
-    READ_ONLY("readOnly", "1032", new MessageFormat("{0}: is a readonly field, it cannot be changed"), ReadOnlyValidator.class, 15),
-    REF("$ref", "1026", new MessageFormat("{0}: has an error with 'refs'"), RefValidator.class, 15),
-    REQUIRED("required", "1028", new MessageFormat("{0}.{1}: is missing but it is required"), RequiredValidator.class, 15),
-    TYPE("type", "1029", new MessageFormat("{0}: {1} found, {2} expected"), TypeValidator.class, 15),
-    UNION_TYPE("unionType", "1030", new MessageFormat("{0}: {1} found, but {2} is required"), UnionTypeValidator.class, 15),
-    UNIQUE_ITEMS("uniqueItems", "1031", new MessageFormat("{0}: the items in the array must be unique"), UniqueItemsValidator.class, 15),
+    ITEMS("items", "1010", new MessageFormat(I18nSupport.getString("items")), ItemsValidator.class, 15),
+    MAXIMUM("maximum", "1011", new MessageFormat(I18nSupport.getString("maximum")), MaximumValidator.class, 15),
+    MAX_ITEMS("maxItems", "1012", new MessageFormat(I18nSupport.getString("maxItems")), MaxItemsValidator.class, 15),
+    MAX_LENGTH("maxLength", "1013", new MessageFormat(I18nSupport.getString("maxLength")), MaxLengthValidator.class, 15),
+    MAX_PROPERTIES("maxProperties", "1014", new MessageFormat(I18nSupport.getString("maxProperties")), MaxPropertiesValidator.class, 15),
+    MINIMUM("minimum", "1015", new MessageFormat(I18nSupport.getString("minimum")), MinimumValidator.class, 15),
+    MIN_ITEMS("minItems", "1016", new MessageFormat(I18nSupport.getString("minItems")), MinItemsValidator.class, 15),
+    MIN_LENGTH("minLength", "1017", new MessageFormat(I18nSupport.getString("minLength")), MinLengthValidator.class, 15),
+    MIN_PROPERTIES("minProperties", "1018", new MessageFormat(I18nSupport.getString("minProperties")), MinPropertiesValidator.class, 15),
+    MULTIPLE_OF("multipleOf", "1019", new MessageFormat(I18nSupport.getString("multipleOf")), MultipleOfValidator.class, 15),
+    NOT_ALLOWED("notAllowed", "1033", new MessageFormat(I18nSupport.getString("notAllowed")), NotAllowedValidator.class, 15),
+    NOT("not", "1020", new MessageFormat(I18nSupport.getString("not")), NotValidator.class, 15),
+    ONE_OF("oneOf", "1022", new MessageFormat(I18nSupport.getString("oneOf")), OneOfValidator.class, 15),
+    PATTERN_PROPERTIES("patternProperties", "1024", new MessageFormat(I18nSupport.getString("patternProperties")), PatternPropertiesValidator.class, 15),
+    PATTERN("pattern", "1023", new MessageFormat(I18nSupport.getString("pattern")), PatternValidator.class, 15),
+    PROPERTIES("properties", "1025", new MessageFormat(I18nSupport.getString("properties")), PropertiesValidator.class, 15),
+    READ_ONLY("readOnly", "1032", new MessageFormat(I18nSupport.getString("readOnly")), ReadOnlyValidator.class, 15),
+    REF("$ref", "1026", new MessageFormat(I18nSupport.getString("$ref")), RefValidator.class, 15),
+    REQUIRED("required", "1028", new MessageFormat(I18nSupport.getString("required")), RequiredValidator.class, 15),
+    TYPE("type", "1029", new MessageFormat(I18nSupport.getString("type")), TypeValidator.class, 15),
+    UNION_TYPE("unionType", "1030", new MessageFormat(I18nSupport.getString("unionType")), UnionTypeValidator.class, 15),
+    UNIQUE_ITEMS("uniqueItems", "1031", new MessageFormat(I18nSupport.getString("uniqueItems")), UniqueItemsValidator.class, 15),
     DATETIME("date-time", "1034", new MessageFormat("{0}: {1} is an invalid {2}"), null, 15),
-    UUID("uuid", "1035", new MessageFormat("{0}: {1} is an invalid {2}"), null, 15),
-    ID("id", "1036", new MessageFormat("{0}: {1} is an invalid segment for URI {2}"), null, 15),
+    UUID("uuid", "1035", new MessageFormat(I18nSupport.getString("uuid")), null, 15),
+    ID("id", "1036", new MessageFormat(I18nSupport.getString("id")), null, 15),
     IF_THEN_ELSE("if", "1037", null, IfValidator.class, 12),  // V7|V201909
-    EXCLUSIVE_MAXIMUM("exclusiveMaximum", "1038", new MessageFormat("{0}: must have a exclusive maximum value of {1}"), ExclusiveMaximumValidator.class, 14),  // V6|V7|V201909
-    EXCLUSIVE_MINIMUM("exclusiveMinimum", "1039", new MessageFormat("{0}: must have a exclusive minimum value of {1}"), ExclusiveMinimumValidator.class, 14),
+    EXCLUSIVE_MAXIMUM("exclusiveMaximum", "1038", new MessageFormat(I18nSupport.getString("exclusiveMaximum")), ExclusiveMaximumValidator.class, 14),  // V6|V7|V201909
+    EXCLUSIVE_MINIMUM("exclusiveMinimum", "1039", new MessageFormat(I18nSupport.getString("exclusiveMinimum")), ExclusiveMinimumValidator.class, 14),
     TRUE("true", "1040", null, TrueValidator.class, 14),
-    FALSE("false", "1041", new MessageFormat("Boolean schema false is not valid"), FalseValidator.class, 14),
-    CONST("const", "1042", new MessageFormat("{0}: must be a constant value {1}"), ConstValidator.class, 14),
-    CONTAINS("contains", "1043", new MessageFormat("{0}: does not contain an element that passes these validations: {1}"), ContainsValidator.class, 14),
-    PROPERTYNAMES("propertyNames", "1044", new MessageFormat("Property name {0} is not valid for validation: {1}"), PropertyNamesValidator.class, 14);
+    FALSE("false", "1041", new MessageFormat(I18nSupport.getString("false")), FalseValidator.class, 14),
+    CONST("const", "1042", new MessageFormat(I18nSupport.getString("const")), ConstValidator.class, 14),
+    CONTAINS("contains", "1043", new MessageFormat(I18nSupport.getString("contains")), ContainsValidator.class, 14),
+    PROPERTYNAMES("propertyNames", "1044", new MessageFormat(I18nSupport.getString("propertyNames")), PropertyNamesValidator.class, 14);
 
     private static Map<String, ValidatorTypeCode> constants = new HashMap<String, ValidatorTypeCode>();
     private static SpecVersion specVersion = new SpecVersion();
diff --git a/src/main/resources/jsv-messages.properties b/src/main/resources/jsv-messages.properties
new file mode 100644
index 0000000..e2352a0
--- /dev/null
+++ b/src/main/resources/jsv-messages.properties
@@ -0,0 +1,38 @@
+additionalProperties = {0}.{1}: is not defined in the schema and the schema does not allow additional properties
+allOf = {0}: should be valid to all the schemas {1}
+anyOf = {0}: should be valid to any of the schemas {1}
+crossEdits = {0}: has an error with 'cross edits'
+dependencies = {0}: has an error with dependencies {1}
+edits = {0}: has an error with 'edits'
+enum = {0}: does not have a value in the enumeration {1}
+format = {0}: does not match the {1} pattern {2}
+items = {0}[{1}]: no validator found at this index
+maximum = {0}: must have a maximum value of {1}
+maxItems = {0}: there must be a maximum of {1} items in the array
+maxLength = {0}: may only be {1} characters long
+maxProperties = {0}: may only have a maximum of {1} properties
+minimum = {0}: must have a minimum value of {1}
+minItems = {0}: there must be a minimum of {1} items in the array
+minLength = {0}: must be at least {1} characters long
+minProperties = {0}: should have a minimum of {1} properties
+multipleOf = {0}: must be multiple of {1}
+notAllowed = {0}.{1}: is not allowed but it is in the data
+not = {0}: should not be valid to the schema {1}
+oneOf = {0}: should be valid to one and only one of the schemas {1}
+patternProperties = {0}: has some error with 'pattern properties'
+pattern = {0}: does not match the regex pattern {1}
+properties = {0}: has an error with 'properties'
+readOnly = {0}: is a readonly field, it cannot be changed
+$ref = {0}: has an error with 'refs'
+required = {0}.{1}: is missing but it is required
+type = {0}: {1} found, {2} expected
+unionType = {0}: {1} found, but {2} is required
+uniqueItems = {0}: the items in the array must be unique
+uuid = {0}: {1} is an invalid {2}
+id = {0}: {1} is an invalid segment for URI {2}
+exclusiveMaximum = {0}: must have a exclusive maximum value of {1}
+exclusiveMinimum = {0}: must have a exclusive minimum value of {1}
+false = Boolean schema false is not valid
+const = {0}: must be a constant value {1}
+contains = {0}: does not contain an element that passes these validations: {1}
+propertyNames = Property name {0} is not valid for validation: {1}
diff --git a/src/main/resources/jsv-messages_zh_cn.properties b/src/main/resources/jsv-messages_zh_cn.properties
new file mode 100644
index 0000000..1dde79c
--- /dev/null
+++ b/src/main/resources/jsv-messages_zh_cn.properties
@@ -0,0 +1,38 @@
+additionalProperties = {0}.{1}\uFF1A\u672A\u5728\u67B6\u6784\u4E2D\u5B9A\u4E49\u4E14\u67B6\u6784\u4E0D\u5141\u8BB8\u9644\u52A0\u5C5E\u6027
+allOf = {0}\uFF1A\u5E94\u8BE5\u5BF9\u6240\u6709\u6A21\u5F0F {1} \u90FD\u6709\u6548
+anyOf = {0}\uFF1A\u5E94\u8BE5\u5BF9\u4EFB\u4F55\u67B6\u6784 {1} \u90FD\u6709\u6548
+crossEdits = {0}\uFF1A\u201C\u4EA4\u53C9\u7F16\u8F91\u201D\u6709\u9519\u8BEF
+dependencies = {0}\uFF1A\u4F9D\u8D56\u9879 {1} \u6709\u9519\u8BEF
+edits = {0}\uFF1A\u201C\u7F16\u8F91\u201D\u6709\u9519\u8BEF
+enum = {0}\uFF1A\u679A\u4E3E {1} \u4E2D\u6CA1\u6709\u503C
+format = {0}\uFF1A\u4E0E {1} \u6A21\u5F0F {2} \u4E0D\u5339\u914D
+items = {0}[{1}]\uFF1A\u5728\u6B64\u7D22\u5F15\u4E2D\u627E\u4E0D\u5230\u9A8C\u8BC1\u5668
+maximum = {0}\uFF1A\u6700\u5927\u503C\u5FC5\u987B\u4E3A {1}
+maxItems = {0}\uFF1A\u6570\u7EC4\u4E2D\u6700\u591A\u5FC5\u987B\u6709 {1} \u4E2A\u9879\u76EE
+maxLength = {0}\uFF1A\u53EF\u80FD\u53EA\u6709 {1} \u4E2A\u5B57\u7B26\u957F
+maxProperties = {0}\uFF1A\u6700\u591A\u53EA\u80FD\u6709 {1} \u4E2A\u5C5E\u6027
+minimum = {0}\uFF1A\u6700\u5C0F\u503C\u5FC5\u987B\u4E3A {1}
+minItems = {0}\uFF1A\u6570\u7EC4\u4E2D\u5FC5\u987B\u81F3\u5C11\u6709 {1} \u4E2A\u9879\u76EE
+minLength = {0}\uFF1A\u5FC5\u987B\u81F3\u5C11\u4E3A {1} \u4E2A\u5B57\u7B26\u957F
+minProperties = {0}\uFF1A\u5E94\u8BE5\u81F3\u5C11\u6709 {1} \u4E2A\u5C5E\u6027
+multipleOf = {0}\uFF1A\u5FC5\u987B\u662F {1} \u7684\u500D\u6570
+notAllowed = {0}.{1}\uFF1A\u4E0D\u88AB\u5141\u8BB8\u4F46\u5728\u6570\u636E\u4E2D
+not = {0}\uFF1A\u4E0D\u5E94\u5BF9\u67B6\u6784 {1} \u6709\u6548
+oneOf = {0}\uFF1A\u5E94\u8BE5\u5BF9\u4E00\u79CD\u4E14\u4EC5\u4E00\u79CD\u6A21\u5F0F\u6709\u6548 {1}
+patternProperties = {0}\uFF1A\u201C\u6A21\u5F0F\u5C5E\u6027\u201D\u6709\u4E00\u4E9B\u9519\u8BEF
+pattern = {0}\uFF1A\u4E0E\u6B63\u5219\u8868\u8FBE\u5F0F\u6A21\u5F0F {1} \u4E0D\u5339\u914D
+properties = {0}\uFF1A\u201C\u5C5E\u6027\u201D\u6709\u9519\u8BEF
+readOnly = {0}\uFF1A\u662F\u53EA\u8BFB\u5B57\u6BB5\uFF0C\u4E0D\u80FD\u66F4\u6539
+$ref = {0}\uFF1A'refs' \u6709\u9519\u8BEF
+required = {0}.{1}\uFF1A\u7F3A\u5C11\u4F46\u5B83\u662F\u5FC5\u9700\u7684
+type = {0}\uFF1A\u627E\u5230 {1}\uFF0C\u9884\u671F\u4E3A {2}
+unionType = {0}\uFF1A\u627E\u5230 {1}\uFF0C\u4F46\u9700\u8981 {2}
+uniqueItems = {0}\uFF1A\u6570\u7EC4\u4E2D\u7684\u9879\u76EE\u5FC5\u987B\u662F\u552F\u4E00\u7684
+uuid = {0}\uFF1A{1} \u662F\u65E0\u6548\u7684 {2}
+id = {0}\uFF1A{1} \u662F URI {2} \u7684\u65E0\u6548\u6BB5
+exclusiveMaximum = {0}\uFF1A\u5FC5\u987B\u5177\u6709 {1} \u7684\u72EC\u5360\u6700\u5927\u503C
+exclusiveMinimum = {0}\uFF1A\u5FC5\u987B\u5177\u6709 {1} \u7684\u552F\u4E00\u6700\u5C0F\u503C
+false = \u5E03\u5C14\u67B6\u6784 false \u65E0\u6548
+const = {0}\uFF1A\u5FC5\u987B\u662F\u5E38\u91CF\u503C {1}
+contains = {0}\uFF1A\u4E0D\u5305\u542B\u901A\u8FC7\u8FD9\u4E9B\u9A8C\u8BC1\u7684\u5143\u7D20\uFF1A{1}
+propertyNames = \u5C5E\u6027\u540D\u79F0 {0} \u5BF9\u9A8C\u8BC1\u65E0\u6548\uFF1A{1}


Test patch:
diff --git a/src/test/resources/openapi3/discriminator.json b/src/test/resources/openapi3/discriminator.json
index 2e32b70..6d55ece 100644
--- a/src/test/resources/openapi3/discriminator.json
+++ b/src/test/resources/openapi3/discriminator.json
@@ -277,6 +277,75 @@
                     "@type": "Bathroom"
                 },
                 "valid": false
+            },
+            {
+                "description": "discriminator missing - falling back to default validation with failure as @type is mandatory",
+                "data": {
+                },
+                "valid": false
+            }
+        ]
+    },
+    {
+        "description": "absent discriminator value as discriminator marked as non-mandatory (which is against OAS3 recommendations)",
+        "schema": {
+            "anyOf": [
+                {
+                    "$ref": "#/components/schemas/Room"
+                },
+                {
+                    "$ref": "#/components/schemas/BedRoom"
+                }
+            ],
+            "components": {
+                "schemas": {
+                    "Room": {
+                        "type": "object",
+                        "properties": {
+                            "intOrStringType": {
+                                "type": "integer"
+                            }
+                        },
+                        "discriminator": {
+                            "propertyName": "@type",
+                            "mapping": {
+                                "bed": "#/components/schemas/BedRoom"
+                            }
+                        }
+                    },
+                    "BedRoom": {
+                        "type": "object",
+                        "allOf": [
+                            {
+                                "$ref": "#/components/schemas/Room"
+                            },
+                            {
+                                "type": "object",
+                                "properties": {
+                                    "intOrStringType": {
+                                        "type": "string"
+                                    }
+                                }
+                            }
+                        ]
+                    }
+                }
+            }
+        },
+        "tests": [
+            {
+                "description": "discriminator missing - falling back to default anyOf behavior",
+                "data": {
+                    "intOrStringType": 4
+                },
+                "valid": true
+            },
+            {
+                "description": "discriminator missing - with constructed schema conflict",
+                "data": {
+                    "intOrStringType": "cannot match due to allOf"
+                },
+                "valid": false
             }
         ]
     },