From bde2804fbece18df132bd912888339770673d039 Mon Sep 17 00:00:00 2001 From: Anton Lobov Date: Fri, 1 Mar 2019 18:23:41 +0100 Subject: [PATCH] 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 --- .../impl/JsonSchemaAnnotatorChecker.java | 4 +- .../jsonSchema/impl/JsonSchemaObject.java | 27 +++++++++++- .../JsonSchemaHighlightingTest.java | 30 +++++++++++++ .../prohibitedAlternateBranchesSchema.json | 42 +++++++++++++++++++ 4 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 json/tests/testData/jsonSchema/highlighting/prohibitedAlternateBranchesSchema.json diff --git a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaAnnotatorChecker.java b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaAnnotatorChecker.java index 5cb99f70401f..1e5dd51b2ec1 100644 --- a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaAnnotatorChecker.java +++ b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaAnnotatorChecker.java @@ -97,7 +97,9 @@ class JsonSchemaAnnotatorChecker { String propertyName = ((JsonValidationError.ProhibitedPropertyIssueData)error.getIssueData()).propertyName; boolean skip = false; for (Collection objects : excludingSchemas) { - Set keys = objects.stream().map(o -> o.getProperties().keySet()).flatMap(Set::stream).collect(Collectors.toSet()); + Set 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; diff --git a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaObject.java b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaObject.java index 2ae2e4011b44..aea101dfa23d 100644 --- a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaObject.java +++ b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaObject.java @@ -78,6 +78,7 @@ public class JsonSchemaObject { @Nullable private Integer myMinLength; @Nullable private Boolean myAdditionalPropertiesAllowed; + @Nullable private Set 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 newSet = myAdditionalPropertiesNotAllowedFor == null + ? ContainerUtil.newHashSet() + : ContainerUtil.newHashSet(myAdditionalPropertiesNotAllowedFor); + newSet.add(url + pointer); + myAdditionalPropertiesNotAllowedFor = newSet; } @Nullable diff --git a/json/tests/test/com/jetbrains/jsonSchema/JsonSchemaHighlightingTest.java b/json/tests/test/com/jetbrains/jsonSchema/JsonSchemaHighlightingTest.java index 1b9d02522146..9799341bd57e 100644 --- a/json/tests/test/com/jetbrains/jsonSchema/JsonSchemaHighlightingTest.java +++ b/json/tests/test/com/jetbrains/jsonSchema/JsonSchemaHighlightingTest.java @@ -1110,4 +1110,34 @@ public class JsonSchemaHighlightingTest extends JsonSchemaHighlightingTestBase { " \"postal_code\": \"1-1111-1111\"\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" + + " \"second\": false\n" + + " }\n" + + "}"); + doTest(schemaText, "{\n" + + " \"subject\": {\n" + + " \"discriminator\": \"second\",\n" + + " \"first\": false,\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" + + "}"); + } } diff --git a/json/tests/testData/jsonSchema/highlighting/prohibitedAlternateBranchesSchema.json b/json/tests/testData/jsonSchema/highlighting/prohibitedAlternateBranchesSchema.json new file mode 100644 index 000000000000..f257504c979a --- /dev/null +++ b/json/tests/testData/jsonSchema/highlighting/prohibitedAlternateBranchesSchema.json @@ -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 + } + } +} +