networknt / json-schema-validator

A fast Java JSON schema validator that supports draft V4, V6, V7, V2019-09 and V2020-12
Apache License 2.0
860 stars 325 forks source link

oneOf with discriminator does not verify json correctly #1087

Closed seveneves closed 4 months ago

seveneves commented 4 months ago

Given this schema to highlight the problem

$id: resource:/schema/issueXXX
$defs:
  TypeA:
    type: object
    required:
      - kind
    properties:
      kind:
        type: string
  TypeB:
    type: object
    required:
      - kind
    properties:
      kind:
        type: string
oneOf:
  - $ref: "#/$defs/TypeA"
  - $ref: "#/$defs/TypeB"
discriminator:
  propertyName: kind
  mapping:
    A: "#/$defs/TypeA"
    B: "#/$defs/TypeB"

TypeA and TypeB are essentially the same with the difference that there is discriminator kind is registered with given mapping A and B.

Then following json cannot be validated

{"kind": "A"}

Validator provides this error

must be valid to one and only one schema, but 2 are valid with indexes '0, 1'

justin-tay commented 4 months ago

The behavior looks correct to me as the discriminator doesn't affect the validation outcome of oneOf.

seveneves commented 4 months ago

@justin-tay

Thanks for looking into this.

I don't entirely agree that it shouldn't affect the validation. It should assist with validation and indicate which Ref to use for validation. Here are statements from the specification that, in my view, confirm this:

When used, the discriminator indicates the name of the property that hints which schema definition is expected to validate the structure of the model.

A discriminator object gives a hint about the expected schema of the document. It can be used to aid in serialization, deserialization, and validation.

In the example I posted, both types TypeA and TypeB successfully validate a JSON of {"kind": "XXX"}, and when used within oneOf, the validation will fail with must be valid to one and only one schema, but 2 are valid. In this case, the discriminator hint should be used to narrow down the matching schema to the correct type. Therefore, {"kind": "A"} should hint to use the schema TypeA for validation and reject validation with TypeB.

If this isn't happening, successful validation can only be achieved when the oneOf schemas are not subsets, meaning they define required but different fields compared to each other. oneOf can also be fixed by adding validation on the discriminator field, such as enum: [A], to indicate that the discriminator value can only hold a single value for a given type. However, this just duplicates the values already defined in the mapping and results in redundant information.

justin-tay commented 4 months ago

From the spec clarifications it doesn't appear that what you are asking for is compliant with the spec.

If you look at the current wording in https://github.com/OAI/OpenAPI-Specification/blob/v3.1.1-dev/versions/3.1.1.md it says

Note that discriminator MUST NOT change the validation outcome of the schema

You can ask in https://github.com/OAI/OpenAPI-Specification/issues if you think my interpretation is incorrect.

seveneves commented 4 months ago

@justin-tay

Found this discussion which seems to confirm that oneOf is behaving correctly in this case. I guess the solution is to force addition of enum for example to each discriminator. Will do just that.

Thanks for taking time to respond!