From 707b37f9038e627a50598e35b7b013b24ea4ffae Mon Sep 17 00:00:00 2001 From: frantuma Date: Fri, 16 Oct 2020 12:22:53 +0200 Subject: [PATCH] improved error reporting in result messages --- .../io/swagger/parser/Swagger20Parser.java | 20 ++++--- .../java/io/swagger/parser/SwaggerParser.java | 6 +- .../parser/util/DeserializationUtils.java | 58 ++++++++++++++----- .../io/swagger/parser/SwaggerReaderTest.java | 3 +- 4 files changed, 57 insertions(+), 30 deletions(-) diff --git a/modules/swagger-parser/src/main/java/io/swagger/parser/Swagger20Parser.java b/modules/swagger-parser/src/main/java/io/swagger/parser/Swagger20Parser.java index a2825b5a0e..475291cf78 100644 --- a/modules/swagger-parser/src/main/java/io/swagger/parser/Swagger20Parser.java +++ b/modules/swagger-parser/src/main/java/io/swagger/parser/Swagger20Parser.java @@ -37,7 +37,7 @@ public SwaggerDeserializationResult readWithInfo(JsonNode node) { @Override public SwaggerDeserializationResult readWithInfo(String location, List auths) { String data; - + SwaggerDeserializationResult errorOutput = new SwaggerDeserializationResult(); try { location = location.replaceAll("\\\\","/"); if (location.toLowerCase().startsWith("http")) { @@ -61,26 +61,28 @@ public SwaggerDeserializationResult readWithInfo(String location, List getExtensions() { } return output; } -} \ No newline at end of file +} diff --git a/modules/swagger-parser/src/main/java/io/swagger/parser/util/DeserializationUtils.java b/modules/swagger-parser/src/main/java/io/swagger/parser/util/DeserializationUtils.java index e1ce03dd9e..6c537e8a11 100644 --- a/modules/swagger-parser/src/main/java/io/swagger/parser/util/DeserializationUtils.java +++ b/modules/swagger-parser/src/main/java/io/swagger/parser/util/DeserializationUtils.java @@ -114,13 +114,17 @@ public static Options getOptions() { } public static JsonNode deserializeIntoTree(String contents, String fileOrHost) { + return deserializeIntoTree(contents, fileOrHost, null); + } + + public static JsonNode deserializeIntoTree(String contents, String fileOrHost, SwaggerDeserializationResult errorOutput) { JsonNode result; try { if (isJson(contents)) { result = Json.mapper().readTree(contents); } else { - result = readYamlTree(contents); + result = readYamlTree(contents, errorOutput); } } catch (IOException e) { throw new RuntimeException("An exception was thrown while trying to deserialize the contents of " + fileOrHost + " into a JsonNode tree", e); @@ -130,6 +134,9 @@ public static JsonNode deserializeIntoTree(String contents, String fileOrHost) { } public static T deserialize(Object contents, String fileOrHost, Class expectedType) { + return deserialize(contents, fileOrHost, expectedType, null); + } + public static T deserialize(Object contents, String fileOrHost, Class expectedType, SwaggerDeserializationResult errorOutput) { T result; boolean isJson = false; @@ -143,7 +150,7 @@ public static T deserialize(Object contents, String fileOrHost, Class exp if (isJson) { result = Json.mapper().readValue((String) contents, expectedType); } else { - result = Yaml.mapper().convertValue(readYamlTree((String) contents), expectedType); + result = Yaml.mapper().convertValue(readYamlTree((String) contents, errorOutput), expectedType); } } else { result = Json.mapper().convertValue(contents, expectedType); @@ -182,7 +189,7 @@ public static org.yaml.snakeyaml.Yaml buildSnakeYaml(BaseConstructor constructor } - public static JsonNode readYamlTree(String contents) throws IOException { + public static JsonNode readYamlTree(String contents, SwaggerDeserializationResult errorOutput) throws IOException { if (!options.isSupportYamlAnchors()) { return Yaml.mapper().readTree(contents); @@ -197,7 +204,7 @@ public static JsonNode readYamlTree(String contents) throws IOException { Object o = yaml.load(contents); if (options.isValidateYamlInput()) { - boolean res = exceedsLimits(o, null, new Integer(0), new IdentityHashMap()); + boolean res = exceedsLimits(o, null, new Integer(0), new IdentityHashMap(), errorOutput); if (res) { LOGGER.warn("Error converting snake-parsed yaml to JsonNode"); return Yaml.mapper().readTree(contents); @@ -207,16 +214,23 @@ public static JsonNode readYamlTree(String contents) throws IOException { return n; } catch (Throwable e) { LOGGER.warn("Error snake-parsing yaml content", e); + if (errorOutput != null) { + errorOutput.message(e.getMessage()); + } return Yaml.mapper().readTree(contents); } } - private static boolean exceedsLimits(Object o, Object parent, Integer depth, Map visited) { + private static boolean exceedsLimits(Object o, Object parent, Integer depth, Map visited, SwaggerDeserializationResult errorOutput) { if (o == null) return false; if (!(o instanceof List) && !(o instanceof Map)) return false; if (depth > options.getMaxYamlDepth()) { - LOGGER.warn("snake-yaml result exceeds max depth {}; threshold can be increased if needed by setting system property `maxYamlDepth` to a higher value.", options.getMaxYamlDepth()); + String msg = String.format("snake-yaml result exceeds max depth %d; threshold can be increased if needed by setting system property `maxYamlDepth` to a higher value.", options.getMaxYamlDepth()); + LOGGER.warn(msg); + if (errorOutput != null) { + errorOutput.message(msg); + } return true; } int currentDepth = depth; @@ -226,13 +240,17 @@ private static boolean exceedsLimits(Object o, Object parent, Integer depth, Map target = o; } if (options.isYamlCycleCheck()) { - boolean res = hasReference(o, target, new Integer(0), new IdentityHashMap()); + boolean res = hasReference(o, target, new Integer(0), new IdentityHashMap(), errorOutput); if (res) { return true; } } if (visited.get(o) > options.getMaxYamlReferences()) { - LOGGER.warn("snake-yaml result exceeds max references {}; threshold can be increased if needed by setting system property `maxYamlReferences` to a higher value.", options.getMaxYamlReferences()); + String msg = String.format("snake-yaml result exceeds max references %d; threshold can be increased if needed by setting system property `maxYamlReferences` to a higher value.", options.getMaxYamlReferences()); + LOGGER.warn(msg); + if (errorOutput != null) { + errorOutput.message(msg); + } return true; } visited.put(o, visited.get(o) + 1); @@ -243,13 +261,13 @@ private static boolean exceedsLimits(Object o, Object parent, Integer depth, Map if (o instanceof Map) { for (Object k : ((Map) o).keySet()) { - boolean res = exceedsLimits(k, o, currentDepth + 1, visited); + boolean res = exceedsLimits(k, o, currentDepth + 1, visited, errorOutput); if (res) { return true; } } for (Object v : ((Map) o).values()) { - boolean res = exceedsLimits(v, o, currentDepth + 1, visited); + boolean res = exceedsLimits(v, o, currentDepth + 1, visited, errorOutput); if (res) { return true; } @@ -257,7 +275,7 @@ private static boolean exceedsLimits(Object o, Object parent, Integer depth, Map } else if (o instanceof List) { for (Object v: ((List)o)) { - boolean res = exceedsLimits(v, o, currentDepth + 1, visited); + boolean res = exceedsLimits(v, o, currentDepth + 1, visited, errorOutput); if (res) { return true; } @@ -266,13 +284,17 @@ private static boolean exceedsLimits(Object o, Object parent, Integer depth, Map return false; } - private static boolean hasReference(Object o, Object target, Integer depth, Map visited) { + private static boolean hasReference(Object o, Object target, Integer depth, Map visited, SwaggerDeserializationResult errorOutput) { if (o == null || target == null) return false; if (!(o instanceof List) && !(o instanceof Map)) return false; if (!(target instanceof List) && !(target instanceof Map)) return false; if (depth > options.getMaxYamlDepth()) { - LOGGER.warn("snake-yaml result exceeds max depth {}; threshold can be increased if needed by setting system property `maxYamlDepth` to a higher value.", options.getMaxYamlDepth()); + String msg = String.format("snake-yaml result exceeds max depth %d; threshold can be increased if needed by setting system property `maxYamlDepth` to a higher value.", options.getMaxYamlDepth()); + LOGGER.warn(msg); + if (errorOutput != null) { + errorOutput.message(msg); + } return true; } int currentDepth = depth; @@ -290,10 +312,14 @@ private static boolean hasReference(Object o, Object target, Integer depth, Map< } for (Object v : children) { if (v == target) { - LOGGER.warn("detected cycle in snake-yaml result; cycle check can be disabled by setting system property `yamlCycleCheck` to false."); - return true; + String msg = "detected cycle in snake-yaml result; cycle check can be disabled by setting system property `yamlCycleCheck` to false."; + LOGGER.warn(msg); + if (errorOutput != null) { + errorOutput.message(msg); + } + return true; } - boolean res = hasReference(v, target, currentDepth + 1, visited); + boolean res = hasReference(v, target, currentDepth + 1, visited, errorOutput); if (res) { return true; } diff --git a/modules/swagger-parser/src/test/java/io/swagger/parser/SwaggerReaderTest.java b/modules/swagger-parser/src/test/java/io/swagger/parser/SwaggerReaderTest.java index 6d6592f6f7..503187855d 100644 --- a/modules/swagger-parser/src/test/java/io/swagger/parser/SwaggerReaderTest.java +++ b/modules/swagger-parser/src/test/java/io/swagger/parser/SwaggerReaderTest.java @@ -1,6 +1,5 @@ package io.swagger.parser; -import com.fasterxml.jackson.databind.node.ObjectNode; import io.swagger.matchers.SerializationMatchers; import io.swagger.models.*; import io.swagger.models.parameters.Parameter; @@ -266,7 +265,7 @@ public void testIssue205() { assertNotNull(definition); assertTrue(definition instanceof ModelImpl); } - + @Test public void testIssue136() { String spec =