diff --git a/modules/swagger-parser/pom.xml b/modules/swagger-parser/pom.xml index 064b9d3b6b..b1593e013c 100644 --- a/modules/swagger-parser/pom.xml +++ b/modules/swagger-parser/pom.xml @@ -28,23 +28,38 @@ + + io.swagger + swagger-core + ${swagger-core-version} + org.testng testng ${testng-version} test + + org.slf4j + slf4j-ext + ${slf4j-version} + + + org.slf4j + slf4j-api + ${slf4j-version} + + + commons-io + commons-io + ${commons-io-version} + org.jmockit jmockit ${jmockit-version} test - - io.swagger - swagger-core - ${swagger-core-version} - ${project.parent.groupId} swagger-core @@ -58,21 +73,6 @@ ${junit-version} test - - org.slf4j - slf4j-ext - ${slf4j-version} - - - org.slf4j - slf4j-api - ${slf4j-version} - - - commons-io - commons-io - ${commons-io-version} - org.slf4j slf4j-simple diff --git a/modules/swagger-parser/src/main/java/io/swagger/parser/ResolverCache.java b/modules/swagger-parser/src/main/java/io/swagger/parser/ResolverCache.java index fc4dab93c5..7db72c0309 100644 --- a/modules/swagger-parser/src/main/java/io/swagger/parser/ResolverCache.java +++ b/modules/swagger-parser/src/main/java/io/swagger/parser/ResolverCache.java @@ -129,7 +129,7 @@ else if(rootPath != null) { } //a definition path is defined, meaning we need to "dig down" through the JSON tree and get the desired entity - JsonNode tree = DeserializationUtils.deserializeIntoTree(contents, file); + JsonNode tree = deserialize(contents, file); String[] jsonPathElements = definitionPath.split("/"); for (String jsonPathElement : jsonPathElements) { @@ -155,6 +155,10 @@ else if(rootPath != null) { return result; } + protected JsonNode deserialize(String contents, String file) { + return DeserializationUtils.deserializeIntoTree(contents, file); + } + protected void updateLocalRefs(String file, T result) { if(result instanceof Response) { Response response = (Response) result; 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 b5b845565d..f36920b5a7 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 @@ -61,7 +61,7 @@ public SwaggerDeserializationResult readWithInfo(String location, List auths) throws IOException { LOGGER.info("reading from " + location); @@ -118,7 +122,7 @@ private Swagger convertToSwagger(String data) throws IOException { ObjectMapper mapper = Json.mapper(); rootNode = mapper.readTree(data); } else { - rootNode = DeserializationUtils.readYamlTree(data); + rootNode = deserializeYaml(data); } if (System.getProperty("debugParser") != null) { diff --git a/modules/swagger-parser/src/main/java/io/swagger/parser/SwaggerParser.java b/modules/swagger-parser/src/main/java/io/swagger/parser/SwaggerParser.java index 5041c0cfb2..9a68e9dbfa 100644 --- a/modules/swagger-parser/src/main/java/io/swagger/parser/SwaggerParser.java +++ b/modules/swagger-parser/src/main/java/io/swagger/parser/SwaggerParser.java @@ -94,6 +94,10 @@ public SwaggerDeserializationResult readWithInfo(String swaggerAsString) { return readWithInfo(swaggerAsString, Boolean.TRUE); } + protected JsonNode deserializeYaml(String data) throws IOException{ + return DeserializationUtils.readYamlTree(data); + } + public SwaggerDeserializationResult readWithInfo(String swaggerAsString, boolean resolve) { if (swaggerAsString == null || swaggerAsString.trim().isEmpty()) { return new SwaggerDeserializationResult().message("empty or null swagger supplied"); @@ -104,7 +108,7 @@ public SwaggerDeserializationResult readWithInfo(String swaggerAsString, boolean ObjectMapper mapper = Json.mapper(); node = mapper.readTree(swaggerAsString); } else { - node = DeserializationUtils.readYamlTree(swaggerAsString); + node = deserializeYaml(swaggerAsString); } SwaggerDeserializationResult result = new Swagger20Parser().readWithInfo(node); 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 dd665edb41..87f01f6ca7 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 @@ -1,20 +1,80 @@ package io.swagger.parser.util; import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import io.swagger.models.Swagger; import io.swagger.util.Json; import io.swagger.util.Yaml; -import org.apache.commons.lang3.builder.ReflectionToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.yaml.snakeyaml.constructor.SafeConstructor; +import org.yaml.snakeyaml.nodes.MappingNode; +import org.yaml.snakeyaml.nodes.Node; +import org.yaml.snakeyaml.nodes.NodeTuple; +import org.yaml.snakeyaml.nodes.Tag; import java.io.IOException; +import java.util.ArrayList; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Map; -/** - * Created by russellb337 on 7/14/15. - */ public class DeserializationUtils { + + public static class Options { + private Integer maxYamlDepth = System.getProperty("maxYamlDepth") == null ? 2000 : Integer.valueOf(System.getProperty("maxYamlDepth")); + private Long maxYamlReferences = System.getProperty("maxYamlReferences") == null ? 10000000L : Long.valueOf(System.getProperty("maxYamlReferences")); + private boolean validateYamlInput = System.getProperty("validateYamlInput") == null ? true : Boolean.valueOf(System.getProperty("validateYamlInput")); + private boolean supportYamlAnchors = System.getProperty("supportYamlAnchors") == null ? true : Boolean.valueOf(System.getProperty("supportYamlAnchors")); + private boolean yamlCycleCheck = System.getProperty("yamlCycleCheck") == null ? true : Boolean.valueOf(System.getProperty("yamlCycleCheck")); + + public Integer getMaxYamlDepth() { + return maxYamlDepth; + } + + public void setMaxYamlDepth(Integer maxYamlDepth) { + this.maxYamlDepth = maxYamlDepth; + } + + public Long getMaxYamlReferences() { + return maxYamlReferences; + } + + public void setMaxYamlReferences(Long maxYamlReferences) { + this.maxYamlReferences = maxYamlReferences; + } + + public boolean isValidateYamlInput() { + return validateYamlInput; + } + + public void setValidateYamlInput(boolean validateYamlInput) { + this.validateYamlInput = validateYamlInput; + } + + public boolean isSupportYamlAnchors() { + return supportYamlAnchors; + } + + public void setSupportYamlAnchors(boolean supportYamlAnchors) { + this.supportYamlAnchors = supportYamlAnchors; + } + + public boolean isYamlCycleCheck() { + return yamlCycleCheck; + } + + public void setYamlCycleCheck(boolean yamlCycleCheck) { + this.yamlCycleCheck = yamlCycleCheck; + } + } + + private static Options options = new Options(); + + private static final Logger LOGGER = LoggerFactory.getLogger(DeserializationUtils.class); + + public static Options getOptions() { + return options; + } + public static JsonNode deserializeIntoTree(String contents, String fileOrHost) { JsonNode result; @@ -61,13 +121,184 @@ private static boolean isJson(String contents) { return contents.toString().trim().startsWith("{"); } - public static JsonNode readYamlTree(String contents) { - org.yaml.snakeyaml.Yaml yaml = new org.yaml.snakeyaml.Yaml(new SafeConstructor()); - return Json.mapper().convertValue(yaml.load(contents), JsonNode.class); + public static JsonNode readYamlTree(String contents) throws IOException { + + if (!options.isSupportYamlAnchors()) { + return Yaml.mapper().readTree(contents); + } + try { + org.yaml.snakeyaml.Yaml yaml = null; + if (options.isValidateYamlInput()) { + yaml = new org.yaml.snakeyaml.Yaml(new CustomSnakeYamlConstructor()); + } else { + yaml = new org.yaml.snakeyaml.Yaml(new SafeConstructor()); + } + + Object o = yaml.load(contents); + if (options.isValidateYamlInput()) { + boolean res = exceedsLimits(o, null, new Integer(0), new IdentityHashMap()); + if (res) { + LOGGER.error("Error converting snake-parsed yaml to JsonNode"); + return Yaml.mapper().readTree(contents); + } + } + JsonNode n = Json.mapper().convertValue(o, JsonNode.class); + return n; + } catch (Throwable e) { + LOGGER.error("Error snake-parsing yaml content", e); + return Yaml.mapper().readTree(contents); + } + } + + private static boolean exceedsLimits(Object o, Object parent, Integer depth, Map visited) { + + if (o == null) return false; + if (!(o instanceof List) && !(o instanceof Map)) return false; + if (depth > options.getMaxYamlDepth()) { + LOGGER.error("snake-yaml result exceeds max depth {}; threshold can be increased if needed by setting system property `maxYamlDepth` to a higher value.", options.getMaxYamlDepth()); + return true; + } + int currentDepth = depth; + if (visited.containsKey(o)) { + Object target = parent; + if (target == null) { + target = o; + } + if (options.isYamlCycleCheck()) { + boolean res = hasReference(o, target, new Integer(0), new IdentityHashMap()); + if (res) { + return true; + } + } + if (visited.get(o) > options.getMaxYamlReferences()) { + LOGGER.error("snake-yaml result exceeds max references {}; threshold can be increased if needed by setting system property `maxYamlReferences` to a higher value.", options.getMaxYamlReferences()); + return true; + } + visited.put(o, visited.get(o) + 1); + + } else { + visited.put(o, 1L); + } + + if (o instanceof Map) { + for (Object k : ((Map) o).keySet()) { + boolean res = exceedsLimits(k, o, currentDepth + 1, visited); + if (res) { + return true; + } + } + for (Object v : ((Map) o).values()) { + boolean res = exceedsLimits(v, o, currentDepth + 1, visited); + if (res) { + return true; + } + } + + } else if (o instanceof List) { + for (Object v: ((List)o)) { + boolean res = exceedsLimits(v, o, currentDepth + 1, visited); + if (res) { + return true; + } + } + } + return false; + } + + private static boolean hasReference(Object o, Object target, Integer depth, Map visited) { + + 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.error("snake-yaml result exceeds max depth {}; threshold can be increased if needed by setting system property `maxYamlDepth` to a higher value.", options.getMaxYamlDepth()); + return true; + } + int currentDepth = depth; + if (visited.containsKey(target)) { + return false; + } + visited.put(o, 1L); + ArrayList children = new ArrayList(); + if (o instanceof Map) { + children.addAll(((Map)o).keySet()); + children.addAll(((Map)o).values()); + + } else if (o instanceof List) { + children.addAll((List)o); + } + for (Object v : children) { + if (v == target) { + LOGGER.error("detected cycle in snake-yaml result; cycle check can be disabled by setting system property `yamlCycleCheck` to false."); + return true; + } + boolean res = hasReference(v, target, currentDepth + 1, visited); + if (res) { + return true; + } + } + return false; + } + + static class SnakeException extends RuntimeException { + public SnakeException() { + super(); + } + public SnakeException(String msg) { + super(msg); + } + + public SnakeException(String message, Throwable cause) { + super(message, cause); + } + } - public static T readYamlValue(String contents, Class expectedType) { - org.yaml.snakeyaml.Yaml yaml = new org.yaml.snakeyaml.Yaml(new SafeConstructor()); - return Json.mapper().convertValue(yaml.load(contents), expectedType); + static class CustomSnakeYamlConstructor extends SafeConstructor { + + private boolean checkNode(MappingNode node, Integer depth) { + if (node.getValue() == null) return true; + if (depth > options.getMaxYamlDepth()) return false; + int currentDepth = depth; + List list = node.getValue(); + for (NodeTuple t : list) { + Node n = t.getKeyNode(); + if (n instanceof MappingNode) { + boolean res = checkNode((MappingNode) n, currentDepth + 1); + if (!res) { + return false; + } + } + } + return true; + } + + @Override + public Object getSingleData(Class type) { + try { + Node node = this.composer.getSingleNode(); + if (node != null) { + if (node instanceof MappingNode) { + if (!checkNode((MappingNode) node, new Integer(0))) { + LOGGER.error("yaml tree depth exceeds max depth {}; threshold can be increased if needed by setting system property `maxYamlDepth` to a higher value.", options.getMaxYamlDepth()); + throw new SnakeException("yaml tree depth exceeds max " + options.getMaxYamlDepth()); + } + } + if (Object.class != type) { + node.setTag(new Tag(type)); + } else if (this.rootTag != null) { + node.setTag(this.rootTag); + } + + return this.constructDocument(node); + } else { + return null; + } + } catch (StackOverflowError e) { + throw new SnakeException("StackOverflow safe-checking yaml content (maxDepth " + options.getMaxYamlDepth() + ")", e); + } catch (Throwable e) { + throw new SnakeException("Exception safe-checking yaml content (maxDepth " + options.getMaxYamlDepth() + ")", e); + } + } } } diff --git a/modules/swagger-parser/src/test/java/io/swagger/parser/AnchorTest.java b/modules/swagger-parser/src/test/java/io/swagger/parser/AnchorTest.java index c48a61811a..b08562fb57 100644 --- a/modules/swagger-parser/src/test/java/io/swagger/parser/AnchorTest.java +++ b/modules/swagger-parser/src/test/java/io/swagger/parser/AnchorTest.java @@ -1,14 +1,19 @@ package io.swagger.parser; import io.swagger.models.ModelImpl; +import io.swagger.models.Swagger; +import io.swagger.parser.util.DeserializationUtils; import io.swagger.parser.util.SwaggerDeserializationResult; -import org.testng.annotations.Test; +import io.swagger.util.Json; +import org.junit.Test; import java.util.Arrays; import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNull; public class AnchorTest { + @Test public void testIssue146() { String yaml = "swagger: '2.0'\n" + @@ -47,4 +52,63 @@ public void testIssue146() { ModelImpl model = (ModelImpl) result.getSwagger().getDefinitions().get("OperationType"); assertEquals(model.getEnum(), Arrays.asList("registration")); } + + @Test + public void testCycle() { + + String yaml = "a:\n" + + " a1: &a1\n" + + " a2: \n" + + " - a3\n" + + " - a4\n" + + " a5: \n" + + " - *a1"; + + SwaggerDeserializationResult result = new SwaggerParser().readWithInfo(yaml); + assertEquals(Json.pretty(result.getSwagger()), "{ }"); + + } + + @org.junit.Test + public void testIssue998() throws Exception{ + + //DeserializationUtils.getOptions().setMaxYamlDepth(5000); + Swagger result = new SwaggerParser().read("issue_998.yaml"); + assertNull(result); + + } + + @org.junit.Test + public void testIssue998Billion() throws Exception{ + DeserializationUtils.getOptions().setMaxYamlReferences(100000L); + String yaml = "a: &a [\"lol\",\"lol\",\"lol\",\"lol\",\"lol\",\"lol\",\"lol\",\"lol\",\"lol\"]\n" + + "b: &b [*a,*a,*a,*a,*a,*a,*a,*a,*a]\n" + + "c: &c [*b,*b,*b,*b,*b,*b,*b,*b,*b]\n" + + "d: &d [*c,*c,*c,*c,*c,*c,*c,*c,*c]\n" + + "e: &e [*d,*d,*d,*d,*d,*d,*d,*d,*d]\n" + + "f: &f [*e,*e,*e,*e,*e,*e,*e,*e,*e]\n" + + "g: &g [*f,*f,*f,*f,*f,*f,*f,*f,*f]\n" + + "h: &h [*g,*g,*g,*g,*g,*g,*g,*g,*g]\n" + + "i: &i [*h,*h,*h,*h,*h,*h,*h,*h,*h]"; + + String yaml2 = "a: &a [\"lol\",\"lol\",\"lol\",\"lol\",\"lol\",\"lol\",\"lol\",\"lol\",\"lol\"]\n" + + "b: &b [*a,*a,*a,*a,*a,*a,*a,*a,*a]\n" + + "c: &c [*b,*b,*b,*b,*b,*b,*b,*b,*b]\n" + + "d: &d [*c,*c,*c,*c,*c,*c,*c,*c,*c]\n" + + "e: &e [*d,*d,*d,*d,*d,*d,*d,*d,*d]\n" + + "f: &f [*e,*e,*e,*e,*e,*e,*e,*e,*e]\n" + + "g: &g [*f,*f,*f,*f,*f,*f,*f,*f,*f]\n" + + "h: &h [*g,*g,*g,*g,*g,*g,*g,*g,*g]"; + + String yaml3 = "a: &a [\"lol\"]\n" + + "b: &b [*a,*a]\n" + + "c: &c [*b,*b]"; + + Swagger result = new SwaggerParser().readWithInfo(yaml).getSwagger(); + assertEquals(Json.pretty(result), "{ }"); + result = new SwaggerParser().readWithInfo(yaml2).getSwagger(); + assertEquals(Json.pretty(result), "{ }"); + DeserializationUtils.getOptions().setMaxYamlReferences(10000000L); + + } } diff --git a/modules/swagger-parser/src/test/resources/issue_998.yaml b/modules/swagger-parser/src/test/resources/issue_998.yaml new file mode 100755 index 0000000000..93503426f2 --- /dev/null +++ b/modules/swagger-parser/src/test/resources/issue_998.yaml @@ -0,0 +1,602 @@ +&id001 +*id001: poop +r: &id200 + a: + a: &id198 + a: &id196 + a: &id194 + a: &id192 + a: &id190 + a: &id188 + a: &id186 + a: &id184 + a: &id182 + a: &id180 + a: &id178 + a: &id176 + a: &id174 + a: &id172 + a: &id170 + a: &id168 + a: &id166 + a: &id164 + a: &id162 + a: &id160 + a: &id158 + a: &id156 + a: &id154 + a: &id152 + a: &id150 + a: &id148 + a: &id146 + a: &id144 + a: &id142 + a: &id140 + a: &id138 + a: &id136 + a: &id134 + a: &id132 + a: &id130 + a: &id128 + a: &id126 + a: &id124 + a: &id122 + a: &id120 + a: &id118 + a: &id116 + a: &id114 + a: &id112 + a: &id110 + a: &id108 + a: &id106 + a: &id104 + a: &id102 + a: &id100 + a: &id098 + a: &id096 + a: &id094 + a: &id092 + a: &id090 + a: &id088 + a: &id086 + a: &id084 + a: &id082 + a: &id080 + a: &id078 + a: &id076 + a: &id074 + a: &id072 + a: &id070 + a: &id068 + a: &id066 + a: &id064 + a: &id062 + a: &id060 + a: &id058 + a: &id056 + a: &id054 + a: &id052 + a: &id050 + a: &id048 + a: &id046 + a: &id044 + a: &id042 + a: &id040 + a: &id038 + a: &id036 + a: &id034 + a: &id032 + a: &id030 + a: &id028 + a: &id026 + a: &id024 + a: &id022 + a: &id020 + a: &id018 + a: &id016 + a: &id014 + a: &id012 + a: &id010 + a: &id008 + a: &id006 + a: &id004 + a: &id002 { + foo: '1'} + b: &id003 { + bar: '2'} + foo: '1' + b: &id005 + a: *id002 + bar: '2' + b: *id003 + foo: '1' + b: &id007 + a: *id004 + bar: '2' + b: *id005 + foo: '1' + b: &id009 + a: *id006 + bar: '2' + b: *id007 + foo: '1' + b: &id011 + a: *id008 + bar: '2' + b: *id009 + foo: '1' + b: &id013 + a: *id010 + bar: '2' + b: *id011 + foo: '1' + b: &id015 + a: *id012 + bar: '2' + b: *id013 + foo: '1' + b: &id017 + a: *id014 + bar: '2' + b: *id015 + foo: '1' + b: &id019 + a: *id016 + bar: '2' + b: *id017 + foo: '1' + b: &id021 + a: *id018 + bar: '2' + b: *id019 + foo: '1' + b: &id023 + a: *id020 + bar: '2' + b: *id021 + foo: '1' + b: &id025 + a: *id022 + bar: '2' + b: *id023 + foo: '1' + b: &id027 + a: *id024 + bar: '2' + b: *id025 + foo: '1' + b: &id029 + a: *id026 + bar: '2' + b: *id027 + foo: '1' + b: &id031 + a: *id028 + bar: '2' + b: *id029 + foo: '1' + b: &id033 + a: *id030 + bar: '2' + b: *id031 + foo: '1' + b: &id035 + a: *id032 + bar: '2' + b: *id033 + foo: '1' + b: &id037 + a: *id034 + bar: '2' + b: *id035 + foo: '1' + b: &id039 + a: *id036 + bar: '2' + b: *id037 + foo: '1' + b: &id041 + a: *id038 + bar: '2' + b: *id039 + foo: '1' + b: &id043 + a: *id040 + bar: '2' + b: *id041 + foo: '1' + b: &id045 + a: *id042 + bar: '2' + b: *id043 + foo: '1' + b: &id047 + a: *id044 + bar: '2' + b: *id045 + foo: '1' + b: &id049 + a: *id046 + bar: '2' + b: *id047 + foo: '1' + b: &id051 + a: *id048 + bar: '2' + b: *id049 + foo: '1' + b: &id053 + a: *id050 + bar: '2' + b: *id051 + foo: '1' + b: &id055 + a: *id052 + bar: '2' + b: *id053 + foo: '1' + b: &id057 + a: *id054 + bar: '2' + b: *id055 + foo: '1' + b: &id059 + a: *id056 + bar: '2' + b: *id057 + foo: '1' + b: &id061 + a: *id058 + bar: '2' + b: *id059 + foo: '1' + b: &id063 + a: *id060 + bar: '2' + b: *id061 + foo: '1' + b: &id065 + a: *id062 + bar: '2' + b: *id063 + foo: '1' + b: &id067 + a: *id064 + bar: '2' + b: *id065 + foo: '1' + b: &id069 + a: *id066 + bar: '2' + b: *id067 + foo: '1' + b: &id071 + a: *id068 + bar: '2' + b: *id069 + foo: '1' + b: &id073 + a: *id070 + bar: '2' + b: *id071 + foo: '1' + b: &id075 + a: *id072 + bar: '2' + b: *id073 + foo: '1' + b: &id077 + a: *id074 + bar: '2' + b: *id075 + foo: '1' + b: &id079 + a: *id076 + bar: '2' + b: *id077 + foo: '1' + b: &id081 + a: *id078 + bar: '2' + b: *id079 + foo: '1' + b: &id083 + a: *id080 + bar: '2' + b: *id081 + foo: '1' + b: &id085 + a: *id082 + bar: '2' + b: *id083 + foo: '1' + b: &id087 + a: *id084 + bar: '2' + b: *id085 + foo: '1' + b: &id089 + a: *id086 + bar: '2' + b: *id087 + foo: '1' + b: &id091 + a: *id088 + bar: '2' + b: *id089 + foo: '1' + b: &id093 + a: *id090 + bar: '2' + b: *id091 + foo: '1' + b: &id095 + a: *id092 + bar: '2' + b: *id093 + foo: '1' + b: &id097 + a: *id094 + bar: '2' + b: *id095 + foo: '1' + b: &id099 + a: *id096 + bar: '2' + b: *id097 + foo: '1' + b: &id101 + a: *id098 + bar: '2' + b: *id099 + foo: '1' + b: &id103 + a: *id100 + bar: '2' + b: *id101 + foo: '1' + b: &id105 + a: *id102 + bar: '2' + b: *id103 + foo: '1' + b: &id107 + a: *id104 + bar: '2' + b: *id105 + foo: '1' + b: &id109 + a: *id106 + bar: '2' + b: *id107 + foo: '1' + b: &id111 + a: *id108 + bar: '2' + b: *id109 + foo: '1' + b: &id113 + a: *id110 + bar: '2' + b: *id111 + foo: '1' + b: &id115 + a: *id112 + bar: '2' + b: *id113 + foo: '1' + b: &id117 + a: *id114 + bar: '2' + b: *id115 + foo: '1' + b: &id119 + a: *id116 + bar: '2' + b: *id117 + foo: '1' + b: &id121 + a: *id118 + bar: '2' + b: *id119 + foo: '1' + b: &id123 + a: *id120 + bar: '2' + b: *id121 + foo: '1' + b: &id125 + a: *id122 + bar: '2' + b: *id123 + foo: '1' + b: &id127 + a: *id124 + bar: '2' + b: *id125 + foo: '1' + b: &id129 + a: *id126 + bar: '2' + b: *id127 + foo: '1' + b: &id131 + a: *id128 + bar: '2' + b: *id129 + foo: '1' + b: &id133 + a: *id130 + bar: '2' + b: *id131 + foo: '1' + b: &id135 + a: *id132 + bar: '2' + b: *id133 + foo: '1' + b: &id137 + a: *id134 + bar: '2' + b: *id135 + foo: '1' + b: &id139 + a: *id136 + bar: '2' + b: *id137 + foo: '1' + b: &id141 + a: *id138 + bar: '2' + b: *id139 + foo: '1' + b: &id143 + a: *id140 + bar: '2' + b: *id141 + foo: '1' + b: &id145 + a: *id142 + bar: '2' + b: *id143 + foo: '1' + b: &id147 + a: *id144 + bar: '2' + b: *id145 + foo: '1' + b: &id149 + a: *id146 + bar: '2' + b: *id147 + foo: '1' + b: &id151 + a: *id148 + bar: '2' + b: *id149 + foo: '1' + b: &id153 + a: *id150 + bar: '2' + b: *id151 + foo: '1' + b: &id155 + a: *id152 + bar: '2' + b: *id153 + foo: '1' + b: &id157 + a: *id154 + bar: '2' + b: *id155 + foo: '1' + b: &id159 + a: *id156 + bar: '2' + b: *id157 + foo: '1' + b: &id161 + a: *id158 + bar: '2' + b: *id159 + foo: '1' + b: &id163 + a: *id160 + bar: '2' + b: *id161 + foo: '1' + b: &id165 + a: *id162 + bar: '2' + b: *id163 + foo: '1' + b: &id167 + a: *id164 + bar: '2' + b: *id165 + foo: '1' + b: &id169 + a: *id166 + bar: '2' + b: *id167 + foo: '1' + b: &id171 + a: *id168 + bar: '2' + b: *id169 + foo: '1' + b: &id173 + a: *id170 + bar: '2' + b: *id171 + foo: '1' + b: &id175 + a: *id172 + bar: '2' + b: *id173 + foo: '1' + b: &id177 + a: *id174 + bar: '2' + b: *id175 + foo: '1' + b: &id179 + a: *id176 + bar: '2' + b: *id177 + foo: '1' + b: &id181 + a: *id178 + bar: '2' + b: *id179 + foo: '1' + b: &id183 + a: *id180 + bar: '2' + b: *id181 + foo: '1' + b: &id185 + a: *id182 + bar: '2' + b: *id183 + foo: '1' + b: &id187 + a: *id184 + bar: '2' + b: *id185 + foo: '1' + b: &id189 + a: *id186 + bar: '2' + b: *id187 + foo: '1' + b: &id191 + a: *id188 + bar: '2' + b: *id189 + foo: '1' + b: &id193 + a: *id190 + bar: '2' + b: *id191 + foo: '1' + b: &id195 + a: *id192 + bar: '2' + b: *id193 + foo: '1' + b: &id197 + a: *id194 + bar: '2' + b: *id195 + foo: '1' + b: &id199 + a: *id196 + bar: '2' + b: *id197 + foo: '1' + b: + a: *id198 + bar: '2' + b: *id199 +j: *id200 \ No newline at end of file diff --git a/pom.xml b/pom.xml index bf6a402112..74a9c7a793 100644 --- a/pom.xml +++ b/pom.xml @@ -202,6 +202,11 @@ swagger-models ${swagger-core-version} + + org.yaml + snakeyaml + ${snakeyaml-version} + org.testng testng @@ -240,8 +245,9 @@ 2.4 + 1.23 1.6.3 - 1.5.21 + 1.5.22-SNAPSHOT 4.8.1 6.9.6 1.19