From b3f368ac370076aff3710fedbc744f553f2e87ec Mon Sep 17 00:00:00 2001
From: Marc Habegger <Marc.Habegger@swisscom.com>
Date: Thu, 25 Aug 2016 13:33:27 +0200
Subject: [PATCH] recursive examples patch without reformatting

---
 .../internal/utils/ExamplesUtil.java          |  55 +++++---
 .../swagger2markup/AsciidocConverterTest.java |  19 +++
 .../definitions.adoc                          |  19 +++
 .../overview.adoc                             |  28 ++++
 .../generated_recursion_examples/paths.adoc   | 126 ++++++++++++++++++
 .../security.adoc                             |   2 +
 .../resources/json/swagger_recursion.json     |  81 +++++++++++
 7 files changed, 310 insertions(+), 20 deletions(-)
 create mode 100644 src/test/resources/expected/asciidoc/generated_recursion_examples/definitions.adoc
 create mode 100644 src/test/resources/expected/asciidoc/generated_recursion_examples/overview.adoc
 create mode 100644 src/test/resources/expected/asciidoc/generated_recursion_examples/paths.adoc
 create mode 100644 src/test/resources/expected/asciidoc/generated_recursion_examples/security.adoc
 create mode 100644 src/test/resources/json/swagger_recursion.json

diff --git a/src/main/java/io/github/swagger2markup/internal/utils/ExamplesUtil.java b/src/main/java/io/github/swagger2markup/internal/utils/ExamplesUtil.java
index b44a3000..4254e60f 100644
--- a/src/main/java/io/github/swagger2markup/internal/utils/ExamplesUtil.java
+++ b/src/main/java/io/github/swagger2markup/internal/utils/ExamplesUtil.java
@@ -27,6 +27,7 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
@@ -34,6 +35,8 @@
 public class ExamplesUtil {
 
     private static Logger logger = LoggerFactory.getLogger(ExamplesUtil.class);
+	
+	private static final Integer MAX_RECURSION_TO_DISPLAY = 2;
 
     /**
      * Generates a Map of response examples
@@ -58,7 +61,7 @@ public static Map<String, Object> generateResponseExampleMap(boolean generateMis
 
                         if (example == null && schema instanceof RefProperty) {
                             String simpleRef = ((RefProperty) schema).getSimpleRef();
-                            example = generateExampleForRefModel(generateMissingExamples, simpleRef, definitions, markupDocBuilder);
+                            example = generateExampleForRefModel(generateMissingExamples, simpleRef, definitions, markupDocBuilder, new HashMap< String, Integer >());
                         }
                         if (example == null && generateMissingExamples) {
                             example = PropertyUtils.generateExample(schema, markupDocBuilder);
@@ -99,17 +102,17 @@ public static Map<String, Object> generateRequestExampleMap(boolean generateMiss
                     Model schema = ((BodyParameter) parameter).getSchema();
                     if (schema instanceof RefModel) {
                         String simpleRef = ((RefModel) schema).getSimpleRef();
-                        example = generateExampleForRefModel(generateMissingExamples, simpleRef, definitions, markupDocBuilder);
+                        example = generateExampleForRefModel(generateMissingExamples, simpleRef, definitions, markupDocBuilder, new HashMap< String, Integer >());
                     } else if (generateMissingExamples) {
                         if (schema instanceof ComposedModel) {
                             example = exampleMapForProperties(getPropertiesForComposedModel(
-                                    (ComposedModel) schema, definitions), definitions, markupDocBuilder);
+                                    (ComposedModel) schema, definitions), definitions, markupDocBuilder, new HashMap< String, Integer >());
                         } else if (schema instanceof ArrayModel) {
-                            example = generateExampleForArrayModel((ArrayModel) schema, definitions, markupDocBuilder);
+                            example = generateExampleForArrayModel((ArrayModel) schema, definitions, markupDocBuilder, new HashMap< String, Integer >());
                         } else {
                             example = schema.getExample();
                             if (example == null) {
-                                example = exampleMapForProperties(schema.getProperties(), definitions, markupDocBuilder);
+                                example = exampleMapForProperties(schema.getProperties(), definitions, markupDocBuilder, new HashMap< String, Integer >());
                             }
                         }
                     }
@@ -150,7 +153,7 @@ public static Map<String, Object> generateRequestExampleMap(boolean generateMiss
                 }
             } else if (parameter instanceof RefParameter) {
                 String simpleRef = ((RefParameter) parameter).getSimpleRef();
-                example = generateExampleForRefModel(generateMissingExamples, simpleRef, definitions, markupDocBuilder);
+                example = generateExampleForRefModel(generateMissingExamples, simpleRef, definitions, markupDocBuilder, new HashMap< String, Integer >());
             }
 
             if (example != null)
@@ -167,19 +170,30 @@ public static Map<String, Object> generateRequestExampleMap(boolean generateMiss
      * @param simpleRef the simple reference string
      * @param definitions the map of definitions
      * @param markupDocBuilder the markup builder
+	 * @param refStack map to detect cyclic references
      * @return returns an Object or Map of examples
      */
-    public static Object generateExampleForRefModel(boolean generateMissingExamples, String simpleRef, Map<String, Model> definitions, MarkupDocBuilder markupDocBuilder) {
+    public static Object generateExampleForRefModel(boolean generateMissingExamples, String simpleRef, Map<String, Model> definitions, MarkupDocBuilder markupDocBuilder, Map< String, Integer > refStack) {
         Model model = definitions.get(simpleRef);
         Object example = null;
         if (model != null) {
             example = model.getExample();
             if (example == null && generateMissingExamples) {
-                if (model instanceof ComposedModel) {
-                    example = exampleMapForProperties(getPropertiesForComposedModel((ComposedModel) model, definitions), definitions, markupDocBuilder);
+				if (!refStack.containsKey(simpleRef)) {
+                    refStack.put(simpleRef, 1);
                 } else {
-                    example = exampleMapForProperties(model.getProperties(), definitions, markupDocBuilder);
+                    refStack.put(simpleRef, refStack.get(simpleRef) + 1);
                 }
+				if (refStack.get(simpleRef) <= MAX_RECURSION_TO_DISPLAY) {
+					if (model instanceof ComposedModel) {
+						example = exampleMapForProperties(getPropertiesForComposedModel((ComposedModel) model, definitions), definitions, markupDocBuilder, refStack);
+					} else {
+						example = exampleMapForProperties(model.getProperties(), definitions, markupDocBuilder, refStack);
+					}
+				}else{
+					return "...";
+				}
+				refStack.put(simpleRef, refStack.get(simpleRef) - 1);
             }
         }
         return example;
@@ -217,19 +231,20 @@ private static Map<String, Property> getPropertiesForComposedModel(ComposedModel
      * @param properties the map of properties
      * @param definitions the map of definitions
      * @param markupDocBuilder the markup builder
+	 * @param refStack map to detect cyclic references
      *
      * @return a Map of examples
      */
-    public static Map<String, Object> exampleMapForProperties(Map<String, Property> properties, Map<String, Model> definitions, MarkupDocBuilder markupDocBuilder) {
+    public static Map<String, Object> exampleMapForProperties(Map<String, Property> properties, Map<String, Model> definitions, MarkupDocBuilder markupDocBuilder, Map< String, Integer > refStack) {
         Map<String, Object> exampleMap = new LinkedHashMap<>();
         if (properties != null) {
             for (Map.Entry<String, Property> property : properties.entrySet()) {
                 Object exampleObject = property.getValue().getExample();
                 if (exampleObject == null) {
                     if (property.getValue() instanceof RefProperty) {
-                        exampleObject = generateExampleForRefModel(true, ((RefProperty) property.getValue()).getSimpleRef(), definitions, markupDocBuilder);
+                        exampleObject = generateExampleForRefModel(true, ((RefProperty) property.getValue()).getSimpleRef(), definitions, markupDocBuilder, refStack);
                     } else if (property.getValue() instanceof ArrayProperty) {
-                        exampleObject = generateExampleForArrayProperty((ArrayProperty) property.getValue(), definitions, markupDocBuilder);
+                        exampleObject = generateExampleForArrayProperty((ArrayProperty) property.getValue(), definitions, markupDocBuilder, refStack);
                     } else if (property.getValue() instanceof MapProperty) {
                         exampleObject = generateExampleForMapProperty((MapProperty) property.getValue(), markupDocBuilder);
                     }
@@ -257,19 +272,19 @@ public static Object generateExampleForMapProperty(MapProperty property, MarkupD
         return exampleMap;
     }
 
-    public static Object generateExampleForArrayModel(ArrayModel model, Map<String, Model> definitions, MarkupDocBuilder markupDocBuilder) {
+    public static Object generateExampleForArrayModel(ArrayModel model, Map<String, Model> definitions, MarkupDocBuilder markupDocBuilder, Map< String, Integer > refStack) {
         if (model.getExample() != null) {
             return model.getExample();
         } else if (model.getProperties() != null) {
-            return new Object[]{exampleMapForProperties(model.getProperties(), definitions, markupDocBuilder)};
+            return new Object[]{exampleMapForProperties(model.getProperties(), definitions, markupDocBuilder, refStack)};
         } else {
             Property itemProperty = model.getItems();
             if (itemProperty.getExample() != null) {
                 return new Object[]{itemProperty.getExample()};
             } else if (itemProperty instanceof ArrayProperty) {
-                return new Object[]{generateExampleForArrayProperty((ArrayProperty) itemProperty, definitions, markupDocBuilder)};
+                return new Object[]{generateExampleForArrayProperty((ArrayProperty) itemProperty, definitions, markupDocBuilder, refStack)};
             } else if (itemProperty instanceof RefProperty) {
-                return new Object[]{generateExampleForRefModel(true, ((RefProperty) itemProperty).getSimpleRef(), definitions, markupDocBuilder)};
+                return new Object[]{generateExampleForRefModel(true, ((RefProperty) itemProperty).getSimpleRef(), definitions, markupDocBuilder, refStack)};
             } else {
                 return new Object[]{PropertyUtils.generateExample(itemProperty, markupDocBuilder)};
             }
@@ -284,14 +299,14 @@ public static Object generateExampleForArrayModel(ArrayModel model, Map<String,
      * @param markupDocBuilder the markup builder
      * @return array of Object
      */
-    public static Object[] generateExampleForArrayProperty(ArrayProperty value, Map<String, Model> definitions, MarkupDocBuilder markupDocBuilder) {
+    public static Object[] generateExampleForArrayProperty(ArrayProperty value, Map<String, Model> definitions, MarkupDocBuilder markupDocBuilder, Map< String, Integer > refStack) {
         Property property = value.getItems();
         if (property.getExample() != null) {
             return new Object[]{property.getExample()};
         } else if (property instanceof ArrayProperty) {
-            return new Object[]{generateExampleForArrayProperty((ArrayProperty) property, definitions, markupDocBuilder)};
+            return new Object[]{generateExampleForArrayProperty((ArrayProperty) property, definitions, markupDocBuilder, refStack)};
         } else if (property instanceof RefProperty) {
-            return new Object[]{generateExampleForRefModel(true, ((RefProperty) property).getSimpleRef(), definitions, markupDocBuilder)};
+            return new Object[]{generateExampleForRefModel(true, ((RefProperty) property).getSimpleRef(), definitions, markupDocBuilder, refStack)};
         } else {
             return new Object[]{PropertyUtils.generateExample(property, markupDocBuilder)};
         }
diff --git a/src/test/java/io/github/swagger2markup/AsciidocConverterTest.java b/src/test/java/io/github/swagger2markup/AsciidocConverterTest.java
index b54c62ca..e71a2118 100644
--- a/src/test/java/io/github/swagger2markup/AsciidocConverterTest.java
+++ b/src/test/java/io/github/swagger2markup/AsciidocConverterTest.java
@@ -189,6 +189,25 @@ public void testSwagger2AsciiDocConversionWithGeneratedExamples() throws IOExcep
         Path expectedFilesDirectory = Paths.get(AsciidocConverterTest.class.getResource("/expected/asciidoc/generated_examples").toURI());
         DiffUtils.assertThatAllFilesAreEqual(expectedFilesDirectory, outputDirectory, "testSwagger2AsciiDocConversionWithGeneratedExamples.html");
     }
+	
+	@Test
+    public void testSwagger2AsciiDocConversionWithGeneratedRecursiveExamples() throws IOException, URISyntaxException {
+        // Given
+        String swaggerJsonString = IOUtils.toString(getClass().getResourceAsStream("/json/swagger_recursion.json"));
+        Path outputDirectory = Paths.get("build/test/asciidoc/generated_recursion_examples");
+        FileUtils.deleteQuietly(outputDirectory.toFile());
+
+        // When
+        Swagger2MarkupConfig config = new Swagger2MarkupConfigBuilder().withoutInlineSchema().withGeneratedExamples().build();
+
+        Swagger2MarkupConverter.from(swaggerJsonString).withConfig(config).build().toFolder(outputDirectory);
+
+        // Then
+        String[] files = outputDirectory.toFile().list();
+        assertThat(files).hasSize(4).containsAll(expectedFiles);
+        Path expectedFilesDirectory = Paths.get(AsciidocConverterTest.class.getResource("/expected/asciidoc/generated_recursion_examples").toURI());
+        DiffUtils.assertThatAllFilesAreEqual(expectedFilesDirectory, outputDirectory, "testSwagger2AsciiDocConversionWithGeneratedRecursiveExamples.html");
+    }
 
     @Test
     public void testSwagger2AsciiDocWithInlineSchema() throws IOException, URISyntaxException {
diff --git a/src/test/resources/expected/asciidoc/generated_recursion_examples/definitions.adoc b/src/test/resources/expected/asciidoc/generated_recursion_examples/definitions.adoc
new file mode 100644
index 00000000..3b81c0a0
--- /dev/null
+++ b/src/test/resources/expected/asciidoc/generated_recursion_examples/definitions.adoc
@@ -0,0 +1,19 @@
+
+[[_definitions]]
+== Definitions
+
+[[_navigationentry]]
+=== NavigationEntry
+
+[options="header", cols=".^3,.^11,.^4"]
+|===
+|Name|Description|Schema
+|*childs* +
+_optional_|*Example* : `[ "<<_navigationentry>>" ]`|< <<_navigationentry,NavigationEntry>> > array
+|*id* +
+_optional_|Primary key of this entry +
+*Example* : `0.0`|number(int64)
+|===
+
+
+
diff --git a/src/test/resources/expected/asciidoc/generated_recursion_examples/overview.adoc b/src/test/resources/expected/asciidoc/generated_recursion_examples/overview.adoc
new file mode 100644
index 00000000..7d47c2e5
--- /dev/null
+++ b/src/test/resources/expected/asciidoc/generated_recursion_examples/overview.adoc
@@ -0,0 +1,28 @@
+= API
+
+
+[[_overview]]
+== Overview
+
+=== Version information
+[%hardbreaks]
+_Version_ : 2.0.0
+
+
+=== URI scheme
+[%hardbreaks]
+_BasePath_ : /navigation
+_Schemes_ : HTTPS
+
+
+=== Consumes
+
+* `application/json`
+
+
+=== Produces
+
+* `application/json`
+
+
+
diff --git a/src/test/resources/expected/asciidoc/generated_recursion_examples/paths.adoc b/src/test/resources/expected/asciidoc/generated_recursion_examples/paths.adoc
new file mode 100644
index 00000000..01a83732
--- /dev/null
+++ b/src/test/resources/expected/asciidoc/generated_recursion_examples/paths.adoc
@@ -0,0 +1,126 @@
+
+[[_paths]]
+== Paths
+
+[[_usernavigation]]
+=== Get navigation
+....
+GET /
+....
+
+
+==== Description
+Returns the navigation as a tree
+
+
+==== Responses
+
+[options="header", cols=".^2,.^14,.^4"]
+|===
+|HTTP Code|Description|Schema
+|*200*|Successful response|<<_navigationentry,NavigationEntry>>
+|===
+
+
+==== Tags
+
+* Navigation
+
+
+==== Example HTTP request
+
+===== Request path
+[source,json]
+----
+"/"
+----
+
+
+==== Example HTTP response
+
+===== Response 200
+[source,json]
+----
+{
+  "id" : 0.0,
+  "childs" : [ {
+    "id" : 0.0,
+    "childs" : [ "..." ]
+  } ]
+}
+----
+
+
+[[_updatenavigation]]
+=== update entry
+....
+PUT /
+....
+
+
+==== Description
+Updates the navigation tree
+
+
+==== Parameters
+
+[options="header", cols=".^2,.^3,.^9,.^4,.^2"]
+|===
+|Type|Name|Description|Schema|Default
+|*Body*|*entry* +
+_optional_||<<_navigationentry,NavigationEntry>>|
+|===
+
+
+==== Responses
+
+[options="header", cols=".^2,.^14,.^4"]
+|===
+|HTTP Code|Description|Schema
+|*200*|Successful response|<<_navigationentry,NavigationEntry>>
+|===
+
+
+==== Tags
+
+* Navigation
+
+
+==== Example HTTP request
+
+===== Request path
+[source,json]
+----
+"/"
+----
+
+
+===== Request body
+[source,json]
+----
+{
+  "id" : 0.0,
+  "childs" : [ {
+    "id" : 0.0,
+    "childs" : [ "..." ]
+  } ]
+}
+----
+
+
+==== Example HTTP response
+
+===== Response 200
+[source,json]
+----
+{
+  "id" : 0.0,
+  "childs" : [ {
+    "id" : 0.0,
+    "childs" : [ "..." ]
+  } ]
+}
+----
+
+
+
diff --git a/src/test/resources/expected/asciidoc/generated_recursion_examples/security.adoc b/src/test/resources/expected/asciidoc/generated_recursion_examples/security.adoc
new file mode 100644
index 00000000..139597f9
--- /dev/null
+++ b/src/test/resources/expected/asciidoc/generated_recursion_examples/security.adoc
@@ -0,0 +1,2 @@
+
+
diff --git a/src/test/resources/json/swagger_recursion.json b/src/test/resources/json/swagger_recursion.json
new file mode 100644
index 00000000..12e34f53
--- /dev/null
+++ b/src/test/resources/json/swagger_recursion.json
@@ -0,0 +1,81 @@
+{
+    "swagger": "2.0",
+    "info": {
+        "version": "2.0.0",
+        "title": "API"
+    },
+    "schemes": [
+        "https"
+    ],
+    "basePath": "/navigation",
+    "produces": [
+        "application/json"
+    ],
+    "consumes": [
+        "application/json"
+    ],
+    "paths": {
+        "/": {
+            "get": {
+                "operationId": "userNavigation",
+                "summary": "Get navigation",
+                "description": "Returns the navigation as a tree",
+                "parameters": [],
+                "tags": [
+                    "Navigation"
+                ],
+                "responses": {
+                    "200": {
+                        "description": "Successful response",
+                        "schema": {
+                            "$ref": "#/definitions/NavigationEntry"
+                        }
+                    }
+                }
+            },
+            "put": {
+                "operationId": "updateNavigation",
+                "summary": "update entry",
+                "description": "Updates the navigation tree",
+                "parameters": [
+                    {
+                      "name": "entry",
+                      "in": "body",
+                      "schema": {
+                        "$ref": "#/definitions/NavigationEntry"
+                      }
+                    }
+                ],
+                "tags": [
+                    "Navigation"
+                ],
+                "responses": {
+                    "200": {
+                        "description": "Successful response",
+                        "schema": {
+                            "$ref": "#/definitions/NavigationEntry"
+                        }
+                    }
+                }
+            }
+        }
+    },
+    "definitions": {
+        "NavigationEntry": {
+            "type": "object",
+            "properties": {
+                "id": {
+                    "description": "Primary key of this entry",
+                    "type": "number",
+                    "format": "int64"
+                },
+                "childs": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/NavigationEntry"
+                    }
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
