Discriminator not working with arrays
It seems that when the anyOf is an array item, the validation is correct for the first item but for the remaining items, it validates against the first schema of the anyOf instead of using the discriminator.
To reproduce:
- schema.json
{
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/components/schemas/Kitchen"
},
{
"$ref": "#/components/schemas/BedRoom"
}
]
},
"components": {
"schemas": {
"Room": {
"type": "object",
"properties": {
"@type": {
"type": "string"
}
},
"required": [
"@type"
],
"discriminator": {
"propertyName": "@type"
}
},
"BedRoom": {
"type": "object",
"allOf": [
{
"$ref": "#/components/schemas/Room"
},
{
"type": "object",
"properties": {
"numberOfBeds": {
"type": "integer"
}
},
"required": [
"numberOfBeds"
]
}
]
},
"Kitchen": {
"type": "object",
"allOf": [
{
"$ref": "#/components/schemas/Room"
},
{
"type": "object",
"properties": {
"hasMicrowaveOven": {
"type": "boolean"
}
},
"required": [
"hasMicrowaveOven"
]
}
]
}
}
}
}
- input.json
[
{
"@type": "Kitchen",
"hasMicrowaveOven": true
},
{
"@type": "BedRoom",
"numberOfBeds": 4
}
]
- test case
@Test
void test() throws Exception {
JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V4);
InputStream schemaStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("schema.json");
InputStream jsonStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("input.json");
SchemaValidatorsConfig config = new SchemaValidatorsConfig();
config.setOpenAPI3StyleDiscriminators(true);
JsonSchema schema = factory.getSchema(schemaStream, config);
JsonNode jsonNode = new ObjectMapper().readTree(jsonStream);
Set<ValidationMessage> errors = schema.validate(jsonNode);
assertEquals(errors.size(), 0);
}
Note: if we reverse order of the kitchen and the bedroom in the json input, then the test passes.
@cbornet Thanks for open this issue. I will put your test case in and try to replicate and fix it.
I believe we've hit this issue too. In the structure we have:
supplies:
type: array
items:
oneOf:
- $ref: '#/components/schemas/Gas'
- $ref: '#/components/schemas/Electricity'
Supply:
type: object
required:
- energyType
properties:
energyType:
type: string
discriminator:
propertyName: energyType
mapping:
electricity: '#/components/schemas/Gas'
gas: '#/components/schemas/Electricity'
Gas:
allOf:
- $ref: '#/components/schemas/Supply'
- type: object
required:
.....gas specific items
Electricity:
allOf:
- $ref: '#/components/schemas/Supply'
- type: object
required:
.....electricity specific items
energyType is what we use to determine if it's "Gas" or "Electricity". The two schemas are different but share "Supply". It will only validate against the "Gas" schema. Furthermore it also doesn't capture if I enter "water" or anything else other than "Gas" or "Electricity". Instead it will just pass through. What I see in the logs though is:
2022-12-09 23:32:46.571 WARN 15504 --- [nio-9010-exec-6] com.networknt.schema.JsonMetaSchema : Unknown keyword components - you should define your own Meta Schema. If the keyword is irrelevant for validation, just use a NonValidationKeyword
2022-12-09 23:32:46.573 WARN 15504 --- [nio-9010-exec-6] com.networknt.schema.JsonMetaSchema : Unknown keyword example - you should define your own Meta Schema. If the keyword is irrelevant for validation, just use a NonValidationKeyword
2022-12-09 23:32:46.578 WARN 15504 --- [nio-9010-exec-6] com.networknt.schema.JsonMetaSchema : Unknown keyword discriminator - you should define your own Meta Schema. If the keyword is irrelevant for validation, just use a NonValidationKeyword
I'm under the impression that in my example "gas" or "electricity" should be provided to validate against their retrospective schema. Any other value should fail validation:
https://spec.openapis.org/oas/v3.1.0#discriminator-object
If the discriminator value does not match an implicit or explicit mapping, no schema can be determined and validation SHOULD fail.
I'm pretty new to this so happy to be corrected but wanted to share what I'd found - hopefully it's useful.