NJsonSchema
NJsonSchema copied to clipboard
oneOf validation failing with valid data
I have discovered an interesting problem in NJsonSchema validation.
For some context, I am using NJsonSchema to validate data coming in from a json-forms implementation. I won't include my exact schema and data here, but I wrote a unit test and managed to replicate this behavior with some test data, please see below:
Schema:
{
"type": "object",
"required": [
"USER"
],
"properties": {
"$schema": {
"type": "string"
},
"USER": {
"type": "string"
},
"PASSWORD": {
"type": "string"
},
"SINGLE_CHOICE": {
"type": "string",
"title": "Single choice",
"description": "Some description",
"oneOf": [
{
"const": "Yes",
"title": "Yes"
},
{
"const": "No",
"title": "No"
}
]
},
"MULTI_CHOICE": {
"type": "array",
"title": "Multi choice",
"description": "Some description",
"uniqueItems": true,
"items": {
"type": "string",
"oneOf": [
{
"const": "A",
"title": "A"
},
{
"const": "B",
"title": "B"
},
{
"const": "C",
"title": "C"
}
]
}
}
},
"additionalProperties": false
}
Data:
{
"$schema": "./schema.json",
"USER": "value",
"SINGLE_CHOICE": "Yes",
"MULTI_CHOICE": ["A", "C"]
}
Using NJsonSchema fails to validate this data, specifically on the oneOf properties. Each time I get an error back from the validator saying that the provided data is not oneOf the available options. Json validation failed: NotOneOf: #/SINGLE_CHOICE
I have run the above example through NewtonSoft's own validator, and it passes validation. However, the nuget package (10.9.0), fails.
I stepped through the validation code in order to try diagnosing this and I noticed that the oneOf options in the Schema object are stored in the ExtensionData property, which is never checked during validation, so every provided option matches, this, then causes a failure in the oneOf validator, since it's not getting any fails (the oneOf validation code returns valid only if there are n-1 errors, where n is the number of oneOf options)
private void ValidateOneOf(JToken token, JsonSchema schema, string propertyName, string propertyPath, List<ValidationError> errors)
{
if (schema._oneOf.Count > 0)
{
var propertyErrors = schema._oneOf.ToDictionary(s => s, s => Validate(token, s)); <--- In my example, validate always has 0 errors
if (propertyErrors.Count(s => s.Value.Count == 0) != 1)
{
errors.Add(new ChildSchemaValidationError(ValidationErrorKind.NotOneOf, propertyName, propertyPath, propertyErrors, token, schema));
}
}
}
I believe this is a bug in the nuget package, since I have validated this data online using newtonsoft. JsonSchema.Net also correctly validates this data.
Are there any news regarding this issue?
From react-json-schema-forms V5 the enumName
will be taken on a depreciation path (https://rjsf-team.github.io/react-jsonschema-form/docs/migration-guides/v5.x%20upgrade%20guide/#non-standard-enumnames-property).
The oneOf
will be the new way of defining Enum values and names. Thus, this bug becomes blocker for future react-json-schema-forms upgrades.
Unfortunately due to this issue being a blocker, I had to migrate my software over to JsonSchema.net. So I have not investigated any further.
A walkaround seem to be to use anyOf
when defining constants
"anyOf": [
{
"const": "A",
"title": "A"
},
{
"const": "B",
"title": "B"
},
{
"const": "C",
"title": "C"
}
According to react-json-schema-forms documentation it is also a viable option and produces same result. At least it worked for me and the validation worked. Well, at least it seems so, for now.