[//]: # (Copyright 2021, Oracle and/or its affiliates.) ## OpenAPI 3.x discriminator support Starting with `1.0.51`, `json-schema-validator` partly supports the use of the [`discriminator`](https://github.com/OAI/OpenAPI-Specification/blob/7cc8f4c4e742a20687fa65ace54ed32fcb8c6df0/versions/3.1.0.md#discriminator-object) keyword. Note that the use of the `discriminator` keyword does not affect the validation of `anyOf` or `oneOf`. The use of `discriminator` is not equivalent to having a `if`/`then` with the `discriminator` propertyName. When a `discriminator` is used, the assertions generated by `anyOf` or `oneOf` will only be the assertions generated from the schema that the discriminator applies to. An assertion will be generated if a `discriminator` is used but there is no matching schema that maps to the value in the `propertyName`. ## How to use 1. Configure `SchemaValidatorsConfig` accordingly: ```java class Demo{ void demo() { SchemaValidatorsConfig config = new SchemaValidatorsConfig(); config.setOpenAPI3StyleDiscriminators(true); // defaults to false } } ``` 2. Use the configured `SchemaValidatorsConfig` with the `JsonSchemaFactory` when creating the `JsonSchema` ```java class Demo{ void demo() { SchemaValidatorsConfig config = new SchemaValidatorsConfig(); config.setOpenAPI3StyleDiscriminators(true); // defaults to false JsonSchemaFactory factory = JsonSchemaFactory.getInstance(VersionFlag.V202012); JsonSchema schema = factory.getSchema(schemaURI, schemaJacksonJsonNode, config); } } ``` 3. Ensure that the type field that you want to use as discriminator `propertyName` is required in your schema ## Scope of Support Discriminators are unfortunately somewhat vague in their definition, especially in regard to JSON Schema validation. So, only those parts that are indisputable are considered at this moment. ### Supported: * Polymorphism using `allOf` and `anyOf` with implicit and explicit `mapping` * `discriminator` on base types and types derived thereof `A(with base discriminator) -> B(with optional additive discriminator) -> C(with optional additive discriminator)` ### Not supported: * `propertyName` redefinition is prohibited on additive discriminators * `mapping` key redefinition is also prohibited on additive discriminators * the specification indicates that inline properties should be ignored. So, this example would respect `foo` ```yaml allOf: - $ref: otherSchema - type: object properties: foo: type: string required: ["foo"] ``` while ```yaml properties: foo: type: string required: ["foo"] allOf: - $ref: otherSchema ``` should ignore `foo`. **Ignoring `foo` in the second example is currently not implemented** * You won't get a warning if your `discriminator` uses a field for `propertyName` that is not `required` ## Schema Examples More examples in https://github.com/networknt/json-schema-validator/blob/master/src/test/resources/openapi3/discriminator.json ### Base type and extended type (the `anyOf` forward references are required) #### Example: ```json { "anyOf": [ { "$ref": "#/components/schemas/Room" }, { "$ref": "#/components/schemas/BedRoom" } ], "components": { "schemas": { "Room": { "type": "object", "properties": { "@type": { "type": "string" }, "floor": { "type": "integer" } }, "required": [ "@type" ], "discriminator": { "propertyName": "@type" } }, "BedRoom": { "type": "object", "allOf": [ { "$ref": "#/components/schemas/Room" }, { "type": "object", "properties": { "numberOfBeds": { "type": "integer" } }, "required": [ "numberOfBeds" ] } ] } } } } ``` #### Here the default mapping key for `BedRoom` is overridden with `bed` from `Room` ```json { "anyOf": [ { "$ref": "#/components/schemas/Room" }, { "$ref": "#/components/schemas/BedRoom" } ], "components": { "schemas": { "Room": { "type": "object", "properties": { "@type": { "type": "string" }, "floor": { "type": "integer" } }, "required": [ "@type" ], "discriminator": { "propertyName": "@type", "mapping": { "bed": "#/components/schemas/BedRoom" } } }, "BedRoom": { "type": "object", "allOf": [ { "$ref": "#/components/schemas/Room" }, { "type": "object", "properties": { "numberOfBeds": { "type": "integer" } }, "required": [ "numberOfBeds" ] } ] } } } } ```