From db30681e700652e0e29f8046c8a01e5cf20091be Mon Sep 17 00:00:00 2001 From: Anton Lobov Date: Wed, 18 Apr 2018 16:04:13 +0200 Subject: [PATCH] WEB-32243 JSON schema: JSON pointer refs with array items are ignored --- .../impl/JsonSchemaAnnotatorChecker.java | 13 ++++---- .../jsonSchema/impl/JsonSchemaObject.java | 10 +++---- .../jsonSchema/impl/JsonSchemaReader.java | 30 +++++++++++++------ .../jsonSchema/impl/JsonSchemaResolver.java | 7 ++--- .../impl/JsonSchemaVariantsTreeBuilder.java | 30 ++++++++++++------- .../JsonSchemaHighlightingTest.java | 29 ++++++++++++++++++ 6 files changed, 84 insertions(+), 35 deletions(-) diff --git a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaAnnotatorChecker.java b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaAnnotatorChecker.java index f71f183c6990..bed907fbe097 100644 --- a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaAnnotatorChecker.java +++ b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaAnnotatorChecker.java @@ -3,6 +3,7 @@ package com.jetbrains.jsonSchema.impl; import com.google.common.base.Predicates; import com.intellij.json.JsonBundle; +import com.intellij.json.psi.JsonContainer; import com.intellij.json.psi.JsonObject; import com.intellij.json.psi.JsonProperty; import com.intellij.openapi.util.Pair; @@ -344,12 +345,12 @@ class JsonSchemaAnnotatorChecker { continue; } - final JsonObject element = prop.getJsonObject(); - if (!element.isValid()) { + final JsonContainer element = prop.getJsonObject(); + if (!(element instanceof JsonObject) || !element.isValid()) { continue; } - final JsonProperty pattern = element.findProperty("pattern"); + final JsonProperty pattern = ((JsonObject)element).findProperty("pattern"); if (pattern != null) { error(StringUtil.convertLineSeparators(patternError), pattern.getValue()); } @@ -357,11 +358,11 @@ class JsonSchemaAnnotatorChecker { } private void reportInvalidPatternProperties(JsonSchemaObject schema) { - final Map invalidPatternProperties = schema.getInvalidPatternProperties(); + final Map invalidPatternProperties = schema.getInvalidPatternProperties(); if (invalidPatternProperties == null) return; - for (Map.Entry entry : invalidPatternProperties.entrySet()) { - final JsonObject element = entry.getKey(); + for (Map.Entry entry : invalidPatternProperties.entrySet()) { + final JsonContainer element = entry.getKey(); if (element == null || !element.isValid()) continue; final PsiElement parent = element.getParent(); if (parent instanceof JsonProperty) { diff --git a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaObject.java b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaObject.java index ddb912afaa0b..31b271f89d86 100644 --- a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaObject.java +++ b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaObject.java @@ -3,7 +3,7 @@ package com.jetbrains.jsonSchema.impl; import com.google.gson.Gson; import com.google.gson.JsonParseException; -import com.intellij.json.psi.JsonObject; +import com.intellij.json.psi.JsonContainer; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.util.Pair; @@ -31,7 +31,7 @@ public class JsonSchemaObject { @NonNls public static final String ITEMS = "items"; @NonNls public static final String ADDITIONAL_ITEMS = "additionalItems"; @NonNls public static final String X_INTELLIJ_HTML_DESCRIPTION = "x-intellij-html-description"; - @NotNull private final JsonObject myJsonObject; + @NotNull private final JsonContainer myJsonObject; @Nullable private Map myDefinitionsMap; @NotNull private Map myProperties; @@ -94,7 +94,7 @@ public class JsonSchemaObject { @Nullable private JsonSchemaObject myElse; private boolean myShouldValidateAgainstJSType; - public JsonSchemaObject(@NotNull JsonObject object) { + public JsonSchemaObject(@NotNull JsonContainer object) { myJsonObject = object; myProperties = new HashMap<>(); } @@ -191,7 +191,7 @@ public class JsonSchemaObject { } @NotNull - public JsonObject getJsonObject() { + public JsonContainer getJsonObject() { return myJsonObject; } @@ -640,7 +640,7 @@ public class JsonSchemaObject { } @Nullable - public Map getInvalidPatternProperties() { + public Map getInvalidPatternProperties() { if (myPatternProperties != null) { final Map patterns = myPatternProperties.getInvalidPatterns(); diff --git a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaReader.java b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaReader.java index ae4f47c76b96..cecc57f234e2 100644 --- a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaReader.java +++ b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaReader.java @@ -76,13 +76,25 @@ public class JsonSchemaReader { while (!myQueue.isEmpty()) { final JsonSchemaObject currentSchema = myQueue.removeFirst(); - final JsonObject jsonObject = currentSchema.getJsonObject(); - final List list = jsonObject.getPropertyList(); - for (JsonProperty property : list) { - if (StringUtil.isEmptyOrSpaces(property.getName()) || property.getValue() == null) continue; - final MyReader reader = READERS_MAP.get(property.getName()); - if (reader != null) reader.read(property.getValue(), currentSchema, myQueue); - else readSingleDefinition(property.getName(), property.getValue(), currentSchema); + final JsonContainer jsonObject = currentSchema.getJsonObject(); + if (jsonObject instanceof JsonObject) { + final List list = ((JsonObject)jsonObject).getPropertyList(); + for (JsonProperty property : list) { + if (StringUtil.isEmptyOrSpaces(property.getName()) || property.getValue() == null) continue; + final MyReader reader = READERS_MAP.get(property.getName()); + if (reader != null) { + reader.read(property.getValue(), currentSchema, myQueue); + } + else { + readSingleDefinition(property.getName(), property.getValue(), currentSchema); + } + } + } + else if (jsonObject instanceof JsonArray) { + List values = ((JsonArray)jsonObject).getValueList(); + for (int i = 0; i < values.size(); i++) { + readSingleDefinition(String.valueOf(i), values.get(i), currentSchema); + } } if (currentSchema.getId() != null) myIds.put(currentSchema.getId(), currentSchema); @@ -95,8 +107,8 @@ public class JsonSchemaReader { } private void readSingleDefinition(@NotNull String name, @NotNull JsonValue value, @NotNull JsonSchemaObject schema) { - if (value instanceof JsonObject) { - final JsonSchemaObject defined = new JsonSchemaObject((JsonObject)value); + if (value instanceof JsonContainer) { + final JsonSchemaObject defined = new JsonSchemaObject((JsonContainer)value); myQueue.add(defined); Map definitions = schema.getDefinitionsMap(); if (definitions == null) schema.setDefinitionsMap(definitions = new HashMap<>()); diff --git a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaResolver.java b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaResolver.java index 103cedb1b4b8..bf5f031060d7 100644 --- a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaResolver.java +++ b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaResolver.java @@ -15,10 +15,7 @@ */ package com.jetbrains.jsonSchema.impl; -import com.intellij.json.psi.JsonArray; -import com.intellij.json.psi.JsonObject; -import com.intellij.json.psi.JsonProperty; -import com.intellij.json.psi.JsonValue; +import com.intellij.json.psi.*; import com.intellij.openapi.util.Ref; import com.intellij.psi.PsiElement; import com.intellij.psi.util.PsiTreeUtil; @@ -135,7 +132,7 @@ public class JsonSchemaResolver { @Nullable private static JsonValue getSchemaNavigationItem(@Nullable final JsonSchemaObject schema) { if (schema == null) return null; - final JsonObject jsonObject = schema.getJsonObject(); + final JsonContainer jsonObject = schema.getJsonObject(); if (jsonObject.getParent() instanceof JsonProperty) { return ((JsonProperty)jsonObject.getParent()).getNameElement(); } diff --git a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaVariantsTreeBuilder.java b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaVariantsTreeBuilder.java index 96f26dce2960..f3bea308a3b1 100644 --- a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaVariantsTreeBuilder.java +++ b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaVariantsTreeBuilder.java @@ -15,6 +15,7 @@ */ package com.jetbrains.jsonSchema.impl; +import com.intellij.json.psi.JsonContainer; import com.intellij.json.psi.JsonObject; import com.intellij.json.psi.JsonProperty; import com.intellij.openapi.diagnostic.Logger; @@ -95,7 +96,7 @@ public class JsonSchemaVariantsTreeBuilder { } private static void expandChildSchema(@NotNull JsonSchemaTreeNode node, @NotNull JsonSchemaObject childSchema, @NotNull JsonSchemaService service) { - final JsonObject element = childSchema.getJsonObject(); + final JsonContainer element = childSchema.getJsonObject(); if (interestingSchema(childSchema)) { final Operation operation = CachedValuesManager.getManager(element.getProject()) @@ -115,9 +116,18 @@ public class JsonSchemaVariantsTreeBuilder { public static List buildSteps(@NotNull String nameInSchema) { final List chain = StringUtil.split(JsonSchemaService.normalizeId(nameInSchema).replace("\\", "/"), "/"); - return chain.stream().filter(s -> !s.isEmpty()) - .map(item -> Step.createPropertyStep(item)) - .collect(Collectors.toList()); + List steps = ContainerUtil.newArrayListWithCapacity(chain.size()); + for (String s: chain) { + if (!StringUtil.isEmpty(s)) { + try { + steps.add(Step.createArrayElementStep(Integer.parseInt(s))); + } + catch (NumberFormatException e) { + steps.add(Step.createPropertyStep(s)); + } + } + } + return steps; } static abstract class Operation { @@ -132,10 +142,10 @@ public class JsonSchemaVariantsTreeBuilder { myChildOperations = new ArrayList<>(); } - protected abstract void map(@NotNull Set visited); + protected abstract void map(@NotNull Set visited); protected abstract void reduce(); - public void doMap(@NotNull final Set visited) { + public void doMap(@NotNull final Set visited) { map(visited); for (Operation operation : myChildOperations) { operation.doMap(visited); @@ -197,7 +207,7 @@ public class JsonSchemaVariantsTreeBuilder { } @Override - public void map(@NotNull final Set visited) { + public void map(@NotNull final Set visited) { JsonSchemaObject current = mySourceNode; while (!StringUtil.isEmptyOrSpaces(current.getRef())) { final JsonSchemaObject definition = getSchemaFromDefinition(current, myService); @@ -234,7 +244,7 @@ public class JsonSchemaVariantsTreeBuilder { } @Override - public void map(@NotNull final Set visited) { + public void map(@NotNull final Set visited) { assert mySourceNode.getAllOf() != null; myChildOperations.addAll(mySourceNode.getAllOf().stream() .map(sourceNode -> new ProcessDefinitionsOperation(sourceNode, myService)).collect(Collectors.toList())); @@ -313,7 +323,7 @@ public class JsonSchemaVariantsTreeBuilder { } @Override - public void map(@NotNull final Set visited) { + public void map(@NotNull final Set visited) { assert mySourceNode.getOneOf() != null; myChildOperations.addAll(mySourceNode.getOneOf().stream() .map(sourceNode -> new ProcessDefinitionsOperation(sourceNode, myService)).collect(Collectors.toList())); @@ -342,7 +352,7 @@ public class JsonSchemaVariantsTreeBuilder { } @Override - public void map(@NotNull final Set visited) { + public void map(@NotNull final Set visited) { assert mySourceNode.getAnyOf() != null; myChildOperations.addAll(mySourceNode.getAnyOf().stream() .map(sourceNode -> new ProcessDefinitionsOperation(sourceNode, myService)).collect(Collectors.toList())); diff --git a/json/tests/test/com/jetbrains/jsonSchema/JsonSchemaHighlightingTest.java b/json/tests/test/com/jetbrains/jsonSchema/JsonSchemaHighlightingTest.java index 8f6a9730bb1c..c798927fac4b 100644 --- a/json/tests/test/com/jetbrains/jsonSchema/JsonSchemaHighlightingTest.java +++ b/json/tests/test/com/jetbrains/jsonSchema/JsonSchemaHighlightingTest.java @@ -779,4 +779,33 @@ public class JsonSchemaHighlightingTest extends DaemonAnalyzerTestCase { doTest(schema, "{\"type\": \"doog\"}"); doTest(schema, "{\"type\": \"ko\"}"); } + + public void testArrayRefs() throws Exception { + @Language("JSON") String schema = "{\n" + + " \"myDefs\": {\n" + + " \"myArray\": [\n" + + " {\n" + + " \"type\": \"number\"\n" + + " },\n" + + " {\n" + + " \"type\": \"string\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"type\": \"array\",\n" + + " \"items\": [\n" + + " {\n" + + " \"$ref\": \"#/myDefs/myArray/0\"\n" + + " },\n" + + " {\n" + + " \"$ref\": \"#/myDefs/myArray/1\"\n" + + " }\n" + + " ]\n" + + "}"; + + doTest(schema, "[1, 2]"); + doTest(schema, "[\"1\", 2]"); + doTest(schema, "[\"1\", \"2\"]"); + doTest(schema, "[1, \"2\"]"); + } }