json-schema-validator icon indicating copy to clipboard operation
json-schema-validator copied to clipboard

V2019-09 not validating field type under properties

Open arandjel opened this issue 3 years ago • 9 comments

Hi,

First of all, this is really nice library, thanks for it.

I've discovered issue where V2019-09 is not validating json properly. Schema that I've tried using for validating json is:

{
    "$schema": "https://json-schema.org/draft/2019-09/schema",
    "$id": "https://json-schema.org/draft/2019-09/schema",
    "$vocabulary": {
        "https://json-schema.org/draft/2019-09/vocab/core": true,
        "https://json-schema.org/draft/2019-09/vocab/applicator": true,
        "https://json-schema.org/draft/2019-09/vocab/validation": true,
        "https://json-schema.org/draft/2019-09/vocab/meta-data": true,
        "https://json-schema.org/draft/2019-09/vocab/format": false,
        "https://json-schema.org/draft/2019-09/vocab/content": true
    },
    "$recursiveAnchor": true,
    "title": "Core and Validation specifications meta-schema",
    "allOf": [
        {"$ref": "meta/core"},
        {"$ref": "meta/applicator"},
        {"$ref": "meta/validation"},
        {"$ref": "meta/meta-data"},
        {"$ref": "meta/format"},
        {"$ref": "meta/content"}
    ],
    "type": ["object", "boolean"],
    "properties": {
        "definitions": {
            "$comment": "While no longer an official keyword as it is replaced by $defs, this keyword is retained in the meta-schema to prevent incompatible extensions as it remains in common use.",
            "type": "object",
            "additionalProperties": { "$recursiveRef": "#" },
            "default": {}
        },
        "dependencies": {
            "$comment": "\"dependencies\" is no longer a keyword, but schema authors should avoid redefining it to facilitate a smooth transition to \"dependentSchemas\" and \"dependentRequired\"",
            "type": "object",
            "additionalProperties": {
                "anyOf": [
                    { "$recursiveRef": "#" },
                    { "$ref": "meta/validation#/$defs/stringArray" }
                ]
            }
        }
    }
}

Json that I'm trying to validate is:

{
  "properties": {
    "field1": {
      "type": "invalid-type",
      "description": "string"
    }
  }
}

As you can see from my json, I've provided invalid type for the field I'm trying to define under properties object. I'm expecting for library to throw validation error, but that is not happening.

Error is thrown however if I switch to draft V7 (which I have), and expected error looks like $.properties.field1.type: does not have a value in the enumeration [array, boolean, integer, null, number, object, string],$.properties.field1.type: should be valid to any of the schemas array If you use online tool like https://www.jsonschemavalidator.net/, you can verify error being thrown with V2019-09.

Hope this provides you with enough information, if you need anything else, let me know.

Regards, Milos

arandjel avatar Jul 08 '20 16:07 arandjel

@arandjel Thanks a lot for raising this issue. It has enough information to create a test case to reproduce it. The difference between v7 and v2019-09 should be minimum and it should be easy to pinpoint the issue. BTW, there is another issue opened for the same root cause I guess. https://github.com/networknt/json-schema-validator/issues/285

stevehu avatar Jul 08 '20 16:07 stevehu

@arandjel Could you please provide a v7 schema file? I am having a hard time to figure out the vocabulary URLs for V7. I never use it before. LOL:)

stevehu avatar Jul 08 '20 18:07 stevehu

Yeah, sure. URL is http://json-schema.org/draft-07/schema, and here is the whole v7 schema:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "http://json-schema.org/draft-07/schema#",
  "title": "Core schema meta-schema",
  "definitions": {
    "schemaArray": {
      "type": "array",
      "minItems": 1,
      "items": { "$ref": "#" }
    },
    "nonNegativeInteger": {
      "type": "integer",
      "minimum": 0
    },
    "nonNegativeIntegerDefault0": {
      "allOf": [
        { "$ref": "#/definitions/nonNegativeInteger" },
        { "default": 0 }
      ]
    },
    "simpleTypes": {
      "enum": [
        "array",
        "boolean",
        "integer",
        "null",
        "number",
        "object",
        "string"
      ]
    },
    "stringArray": {
      "type": "array",
      "items": { "type": "string" },
      "uniqueItems": true,
      "default": []
    }
  },
  "type": ["object", "boolean"],
  "properties": {
    "$id": {
      "type": "string",
      "format": "uri-reference"
    },
    "$schema": {
      "type": "string",
      "format": "uri"
    },
    "$ref": {
      "type": "string",
      "format": "uri-reference"
    },
    "$comment": {
      "type": "string"
    },
    "title": {
      "type": "string"
    },
    "description": {
      "type": "string"
    },
    "default": true,
    "readOnly": {
      "type": "boolean",
      "default": false
    },
    "writeOnly": {
      "type": "boolean",
      "default": false
    },
    "examples": {
      "type": "array",
      "items": true
    },
    "multipleOf": {
      "type": "number",
      "exclusiveMinimum": 0
    },
    "maximum": {
      "type": "number"
    },
    "exclusiveMaximum": {
      "type": "number"
    },
    "minimum": {
      "type": "number"
    },
    "exclusiveMinimum": {
      "type": "number"
    },
    "maxLength": { "$ref": "#/definitions/nonNegativeInteger" },
    "minLength": { "$ref": "#/definitions/nonNegativeIntegerDefault0" },
    "pattern": {
      "type": "string",
      "format": "regex"
    },
    "additionalItems": { "$ref": "#" },
    "items": {
      "anyOf": [
        { "$ref": "#" },
        { "$ref": "#/definitions/schemaArray" }
      ],
      "default": true
    },
    "maxItems": { "$ref": "#/definitions/nonNegativeInteger" },
    "minItems": { "$ref": "#/definitions/nonNegativeIntegerDefault0" },
    "uniqueItems": {
      "type": "boolean",
      "default": false
    },
    "contains": { "$ref": "#" },
    "maxProperties": { "$ref": "#/definitions/nonNegativeInteger" },
    "minProperties": { "$ref": "#/definitions/nonNegativeIntegerDefault0" },
    "required": { "$ref": "#/definitions/stringArray" },
    "additionalProperties": { "$ref": "#" },
    "definitions": {
      "type": "object",
      "additionalProperties": { "$ref": "#" },
      "default": {}
    },
    "properties": {
      "type": "object",
      "additionalProperties": { "$ref": "#" },
      "default": {}
    },
    "patternProperties": {
      "type": "object",
      "additionalProperties": { "$ref": "#" },
      "propertyNames": { "format": "regex" },
      "default": {}
    },
    "dependencies": {
      "type": "object",
      "additionalProperties": {
        "anyOf": [
          { "$ref": "#" },
          { "$ref": "#/definitions/stringArray" }
        ]
      }
    },
    "propertyNames": { "$ref": "#" },
    "const": true,
    "enum": {
      "type": "array",
      "items": true,
      "minItems": 1,
      "uniqueItems": true
    },
    "type": {
      "anyOf": [
        { "$ref": "#/definitions/simpleTypes" },
        {
          "type": "array",
          "items": { "$ref": "#/definitions/simpleTypes" },
          "minItems": 1,
          "uniqueItems": true
        }
      ]
    },
    "format": { "type": "string" },
    "contentMediaType": { "type": "string" },
    "contentEncoding": { "type": "string" },
    "if": { "$ref": "#" },
    "then": { "$ref": "#" },
    "else": { "$ref": "#" },
    "allOf": { "$ref": "#/definitions/schemaArray" },
    "anyOf": { "$ref": "#/definitions/schemaArray" },
    "oneOf": { "$ref": "#/definitions/schemaArray" },
    "not": { "$ref": "#" }
  },
  "default": true
}

arandjel avatar Jul 08 '20 18:07 arandjel

I just realized it is the meta schema and the v2019-09 is significantly different. I am guessing v2019-09 is not parse correctly due to unknown keywords. Need to debug into it to find out the root cause. Thanks.

stevehu avatar Jul 08 '20 20:07 stevehu

I have just added two test cases to reproduce the issue. The v2019-09 test case is marked as ignored as there is an issue. I am wondering if anyone can help to debug into both cases and find out what is wrong.

stevehu avatar Jul 21 '20 02:07 stevehu

This issue and #285 occurs because of https://github.com/networknt/json-schema-validator/blob/d5a861affba41159f1c4187662144297fe7cf8c8/src/main/java/com/networknt/schema/PropertiesValidator.java#L33. This assumes that all field names are in the schema file. This is not the case for the 2019 Meta-Schemas where the field names are declared in the vocabulary keyword and those references. To be more precise https://github.com/networknt/json-schema-validator/blob/d5a861affba41159f1c4187662144297fe7cf8c8/src/main/java/com/networknt/schema/PropertiesValidator.java#L35 can't generate the right JsonSchemas.

SirMoM avatar Jul 23 '20 08:07 SirMoM

Fantastic findings!!! I don't know why the 2019-09 version is changed dramatically. Maybe we should have another version of the properties validator for 2019-09 to handle the scenario or to check the version before reading the properties. What do you think?

stevehu avatar Jul 23 '20 14:07 stevehu

@stevehu - Do we have any plan to fix this issue? I am also having same issue. Please suggest if we have any alternative ?

@arandjel - As you faced this issue earlier. Have you found any alternative for this issue?

abhikt48 avatar Mar 08 '22 18:03 abhikt48

@abhikt48, yeah, we've used V7 schema instead.

arandjel avatar Mar 08 '22 20:03 arandjel

Notes on my investigation so I don't forget what I've learned.

The reason this fails under Drafts 2019-09 and 2020-12 is that type validation is defined in meta/validation while properties validation is defined in meta/applicators. The specification implies that these vocabularies should work together by placing them in a allOf applicator. However, there are tests in the JSON Schema Test Suite checking that children of applicators cannot "see" each other and thus, do not interact.

fdutton avatar Jun 13 '23 14:06 fdutton

I think this issue has already been resolved in the latest release, 1.3.1. Thanks.

stevehu avatar Feb 01 '24 17:02 stevehu