WEB-37571 json schema oneOf not validating correctly

preserve pointers for schemas for which alternate branches having 'additionalProperties'=false are collected
ignore corresponding properties from merged results, but only when additionalProperties=false is specified directly
This commit is contained in:
Anton Lobov
2019-03-01 18:24:50 +01:00
parent e3ed226a60
commit bde2804fbe
4 changed files with 101 additions and 2 deletions
@@ -97,7 +97,9 @@ class JsonSchemaAnnotatorChecker {
String propertyName = ((JsonValidationError.ProhibitedPropertyIssueData)error.getIssueData()).propertyName;
boolean skip = false;
for (Collection<? extends JsonSchemaObject> objects : excludingSchemas) {
Set<String> keys = objects.stream().map(o -> o.getProperties().keySet()).flatMap(Set::stream).collect(Collectors.toSet());
Set<String> keys = objects.stream()
.filter(o -> !o.hasOwnExtraPropertyProhibition())
.map(o -> o.getProperties().keySet()).flatMap(Set::stream).collect(Collectors.toSet());
if (keys.contains(propertyName)) skip = true;
}
if (skip) continue;
@@ -78,6 +78,7 @@ public class JsonSchemaObject {
@Nullable private Integer myMinLength;
@Nullable private Boolean myAdditionalPropertiesAllowed;
@Nullable private Set<String> myAdditionalPropertiesNotAllowedFor;
@Nullable private JsonSchemaObject myAdditionalPropertiesSchema;
@Nullable private JsonSchemaObject myPropertyNamesSchema;
@@ -288,7 +289,12 @@ public class JsonSchemaObject {
if (other.myMaxLength != null) myMaxLength = other.myMaxLength;
if (other.myMinLength != null) myMinLength = other.myMinLength;
if (other.myPattern != null) myPattern = other.myPattern;
if (other.myAdditionalPropertiesAllowed != null) myAdditionalPropertiesAllowed = other.myAdditionalPropertiesAllowed;
if (other.myAdditionalPropertiesAllowed != null) {
myAdditionalPropertiesAllowed = other.myAdditionalPropertiesAllowed;
if (other.myAdditionalPropertiesAllowed == Boolean.FALSE) {
addAdditionalPropsNotAllowedFor(other.myFileUrl, other.myPointer);
}
}
if (other.myAdditionalPropertiesSchema != null) myAdditionalPropertiesSchema = other.myAdditionalPropertiesSchema;
if (other.myPropertyNamesSchema != null) myPropertyNamesSchema = other.myPropertyNamesSchema;
if (other.myAdditionalItemsAllowed != null) myAdditionalItemsAllowed = other.myAdditionalItemsAllowed;
@@ -489,6 +495,25 @@ public class JsonSchemaObject {
public void setAdditionalPropertiesAllowed(@Nullable Boolean additionalPropertiesAllowed) {
myAdditionalPropertiesAllowed = additionalPropertiesAllowed;
if (additionalPropertiesAllowed == Boolean.FALSE) {
addAdditionalPropsNotAllowedFor(myFileUrl, myPointer);
}
}
// for the sake of merging validation results, we need to know if this schema prohibits additional properties itself,
// or if it inherits this prohibition flag from the merge result, as the behavior differs in these cases
public boolean hasOwnExtraPropertyProhibition() {
return getAdditionalPropertiesAllowed() == Boolean.FALSE &&
(myAdditionalPropertiesNotAllowedFor == null ||
myAdditionalPropertiesNotAllowedFor.contains(myFileUrl + myPointer));
}
private void addAdditionalPropsNotAllowedFor(String url, String pointer) {
Set<String> newSet = myAdditionalPropertiesNotAllowedFor == null
? ContainerUtil.newHashSet()
: ContainerUtil.newHashSet(myAdditionalPropertiesNotAllowedFor);
newSet.add(url + pointer);
myAdditionalPropertiesNotAllowedFor = newSet;
}
@Nullable
@@ -1110,4 +1110,34 @@ public class JsonSchemaHighlightingTest extends JsonSchemaHighlightingTestBase {
" \"postal_code\": <warning descr=\"String is violating the pattern: '[0-9]{5}(-[0-9]{4})?'\">\"1-1111-1111\"</warning>\n" +
"}");
}
public void testProhibitAdditionalPropsAlternateBranches() throws Exception {
@Language("JSON") String schemaText = FileUtil.loadFile(new File(getTestDataPath() + "/prohibitedAlternateBranchesSchema.json"));
doTest(schemaText, "{\n" +
" \"subject\": {\n" +
" \"discriminator\": \"first\",\n" +
" \"first\": false,\n" +
" <warning descr=\"Property 'second' is not allowed\">\"second\": false</warning>\n" +
" }\n" +
"}");
doTest(schemaText, "{\n" +
" \"subject\": {\n" +
" \"discriminator\": \"second\",\n" +
" <warning descr=\"Property 'first' is not allowed\">\"first\": false</warning>,\n" +
" \"second\": false\n" +
" }\n" +
"}");
doTest(schemaText, "{\n" +
" \"subject\": {\n" +
" \"discriminator\": \"second\",\n" +
" \"second\": false\n" +
" }\n" +
"}");
doTest(schemaText, "{\n" +
" \"subject\": {\n" +
" \"discriminator\": \"first\",\n" +
" \"first\": false\n" +
" }\n" +
"}");
}
}
@@ -0,0 +1,42 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"subject": {
"oneOf": [
{
"$ref": "#/definitions/first"
},
{
"$ref": "#/definitions/second"
}
]
}
},
"definitions": {
"first": {
"type": "object",
"properties": {
"discriminator": {
"const": "first"
},
"first": {
"type": "boolean"
}
},
"additionalProperties": false
},
"second": {
"type": "object",
"properties": {
"discriminator": {
"const": "second"
},
"second": {
"type": "boolean"
}
},
"additionalProperties": false
}
}
}