From 3cf1f1a56a8b6b4ba9b19b403fa54b2574ef38c0 Mon Sep 17 00:00:00 2001 From: Tony Tam Date: Sun, 18 Oct 2015 20:51:55 -0700 Subject: [PATCH] added support for array and model inline types --- .../swagger/codegen/InlineModelResolver.java | 180 +++++++++++++++--- .../codegen/InlineModelResolverTest.java | 117 +++++++++++- 2 files changed, 266 insertions(+), 31 deletions(-) diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/InlineModelResolver.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/InlineModelResolver.java index c285faf73bf..3e64334f8e3 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/InlineModelResolver.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/InlineModelResolver.java @@ -3,9 +3,9 @@ package io.swagger.codegen; import io.swagger.models.*; import io.swagger.models.parameters.BodyParameter; import io.swagger.models.parameters.Parameter; -import io.swagger.models.properties.ObjectProperty; -import io.swagger.models.properties.Property; -import io.swagger.models.properties.RefProperty; +import io.swagger.models.parameters.RefParameter; +import io.swagger.models.properties.*; +import io.swagger.util.Json; import java.util.ArrayList; import java.util.HashMap; @@ -14,12 +14,18 @@ import java.util.Map; public class InlineModelResolver { private Swagger swagger = null; + private boolean skipMatches = false; Map addedModels = new HashMap(); + Map generatedSignature = new HashMap(); public void flatten(Swagger swagger) { this.swagger = swagger; + if(swagger.getDefinitions() == null) { + swagger.setDefinitions(new HashMap()); + } + // operations Map paths = swagger.getPaths(); Map models = swagger.getDefinitions(); @@ -35,24 +41,20 @@ public class InlineModelResolver { for(Parameter parameter : parameters) { if(parameter instanceof BodyParameter) { BodyParameter bp = (BodyParameter) parameter; - if(bp.getSchema() != null) { Model model = bp.getSchema(); if(model instanceof ModelImpl) { - String name = bp.getName(); - - if(models == null) { - models = new HashMap(); - swagger.setDefinitions(models); + String existing = matchGenerated(model); + if(existing != null) { + bp.setSchema(new RefModel(existing)); } else { - if (swagger.getDefinitions().containsKey(bp.getName())) { - name += "_" + "inline"; - } + String name = uniqueName(bp.getName()); + bp.setSchema(new RefModel(name)); + addGenerated(name, model); + swagger.addDefinition(name, model); } - swagger.addDefinition(name, model); - bp.setSchema(new RefModel(name)); } } } @@ -68,8 +70,44 @@ public class InlineModelResolver { String modelName = uniqueName("inline_response_" + key); ObjectProperty op = (ObjectProperty) property; Model model = modelFromProperty(op, modelName); - response.setSchema(new RefProperty(modelName)); - swagger.addDefinition(modelName, model); + String existing = matchGenerated(model); + if(existing != null) { + response.setSchema(new RefProperty(existing)); + } + else { + response.setSchema(new RefProperty(modelName)); + addGenerated(modelName, model); + swagger.addDefinition(modelName, model); + } + } + else if(property instanceof ArrayProperty) { + String modelName = uniqueName("inline_response_" + key); + ArrayProperty ap = (ArrayProperty) property; + Model model = modelFromProperty(ap, modelName); + if(model != null) { + String existing = matchGenerated(model); + if (existing != null) { + response.setSchema(new RefProperty(existing)); + } else { + response.setSchema(new RefProperty(modelName)); + addGenerated(modelName, model); + swagger.addDefinition(modelName, model); + } + } + } + else if(property instanceof MapProperty) { + MapProperty op = (MapProperty) property; + String modelName = uniqueName("inline_response_" + key); + Model model = modelFromProperty(op, modelName); + String existing = matchGenerated(model); + if(existing != null) { + response.setSchema(new RefProperty(existing)); + } + else { + response.setSchema(new RefProperty(modelName)); + addGenerated(modelName, model); + swagger.addDefinition(modelName, model); + } } } } @@ -88,15 +126,24 @@ public class InlineModelResolver { Map properties = m.getProperties(); flattenProperties(properties, modelName); + } else if (model instanceof ArrayModel) { ArrayModel m = (ArrayModel) model; Property inner = m.getItems(); if(inner instanceof ObjectProperty) { - String innerModelName = uniqueName(modelName + "_" + inner); - Model innerModel = modelFromProperty((ObjectProperty)inner, modelName); - swagger.addDefinition(innerModelName, innerModel); - m.setItems(new RefProperty(innerModelName)); + String innerModelName = uniqueName(modelName + "_inner"); + Model innerModel = modelFromProperty((ObjectProperty) inner, modelName); + + String existing = matchGenerated(innerModel); + if(existing == null) { + swagger.addDefinition(innerModelName, innerModel); + addGenerated(innerModelName, innerModel); + m.setItems(new RefProperty(innerModelName)); + } + else { + m.setItems(new RefProperty(existing)); + } } } else if (model instanceof ComposedModel) { @@ -106,6 +153,21 @@ public class InlineModelResolver { } } + public String matchGenerated(Model model) { + if(this.skipMatches) { + return null; + } + String json = Json.pretty(model); + if(generatedSignature.containsKey(json)) { + return generatedSignature.get(json); + } + return null; + } + + public void addGenerated(String name, Model model) { + generatedSignature.put(Json.pretty(model), name); + } + public String uniqueName(String key) { int count = 0; boolean done = false; @@ -135,11 +197,22 @@ public class InlineModelResolver { Property property = properties.get(key); if(property instanceof ObjectProperty) { String modelName = uniqueName(path + "_" + key); + + ObjectProperty op = (ObjectProperty) property; Model model = modelFromProperty(op, modelName); - modelsToAdd.put(modelName, model); - propsToUpdate.put(key, new RefProperty(modelName)); + String existing = matchGenerated(model); + + if(existing != null) { + propsToUpdate.put(key, new RefProperty(existing)); + } + else { + propsToUpdate.put(key, new RefProperty(modelName)); + modelsToAdd.put(modelName, model); + addGenerated(modelName, model); + swagger.addDefinition(modelName, model); + } } } if(propsToUpdate.size() > 0) { @@ -153,6 +226,41 @@ public class InlineModelResolver { } } + public Model modelFromProperty(ArrayProperty object, String path) { + String access = object.getAccess(); + String description = object.getDescription(); + String example = object.getExample(); + String name = object.getName(); + Integer position = object.getPosition(); + Boolean readOnly = object.getReadOnly(); + Boolean required = object.getRequired(); + String title = object.getTitle(); + Map extensions = object.getVendorExtensions(); + Xml xml = object.getXml(); + +// object.getItems() +// Map properties = object.getProperties(); + + Property inner = object.getItems(); + if(inner instanceof ObjectProperty) { + ArrayModel model = new ArrayModel(); + model.setDescription(description); + model.setExample(example); +// model.setName(name); +// model.setXml(xml); + + model.setItems(object.getItems()); + return model; + } + +// if(properties != null) { +// flattenProperties(properties, path); +// model.setProperties(properties); +// } + + return null; + } + public Model modelFromProperty(ObjectProperty object, String path) { String access = object.getAccess(); String description = object.getDescription(); @@ -180,4 +288,32 @@ public class InlineModelResolver { return model; } + + public Model modelFromProperty(MapProperty object, String path) { + String access = object.getAccess(); + String description = object.getDescription(); + String example = object.getExample(); + String name = object.getName(); + Integer position = object.getPosition(); + Boolean readOnly = object.getReadOnly(); + Boolean required = object.getRequired(); + String title = object.getTitle(); + Map extensions = object.getVendorExtensions(); + Xml xml = object.getXml(); + + ArrayModel model = new ArrayModel(); + model.setDescription(description); + model.setExample(example); + model.setItems(object.getAdditionalProperties()); + + return model; + } + + public boolean isSkipMatches() { + return skipMatches; + } + + public void setSkipMatches(boolean skipMatches) { + this.skipMatches = skipMatches; + } } diff --git a/modules/swagger-codegen/src/test/java/io/swagger/codegen/InlineModelResolverTest.java b/modules/swagger-codegen/src/test/java/io/swagger/codegen/InlineModelResolverTest.java index e922e0d6e2f..7affd97749a 100644 --- a/modules/swagger-codegen/src/test/java/io/swagger/codegen/InlineModelResolverTest.java +++ b/modules/swagger-codegen/src/test/java/io/swagger/codegen/InlineModelResolverTest.java @@ -4,11 +4,17 @@ package io.swagger.codegen; import io.swagger.models.*; import io.swagger.models.parameters.BodyParameter; import io.swagger.models.parameters.Parameter; -import io.swagger.models.properties.ObjectProperty; -import io.swagger.models.properties.StringProperty; +import io.swagger.models.properties.*; import io.swagger.util.Json; import org.junit.Test; +import java.lang.reflect.Array; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + public class InlineModelResolverTest { @Test public void resolveInlineModelTest() throws Exception { @@ -31,7 +37,15 @@ public class InlineModelResolverTest { new InlineModelResolver().flatten(swagger); - Json.prettyPrint(swagger); + ModelImpl user = (ModelImpl)swagger.getDefinitions().get("User"); + + assertNotNull(user); + assertTrue(user.getProperties().get("address") instanceof RefProperty); + + ModelImpl address = (ModelImpl)swagger.getDefinitions().get("User_address"); + assertNotNull(address); + assertNotNull(address.getProperties().get("city")); + assertNotNull(address.getProperties().get("street")); } @Test @@ -50,12 +64,18 @@ public class InlineModelResolverTest { .vendorExtension("x-foo", "bar") .description("it works!") .schema(new ObjectProperty() - .vendorExtension("x-baz", "boo") - .property("name", new StringProperty() - .vendorExtension("x-bars", "bleh")))))); + .property("name", new StringProperty()))))); new InlineModelResolver().flatten(swagger); - Json.prettyPrint(swagger); + Map responses = swagger.getPaths().get("/foo/bar").getGet().getResponses(); + + Response response = responses.get("200"); + assertNotNull(response); + assertTrue(response.getSchema() instanceof RefProperty); + + ModelImpl model = (ModelImpl)swagger.getDefinitions().get("inline_response_200"); + assertTrue(model.getProperties().size() == 1); + assertNotNull(model.getProperties().get("name")); } @Test @@ -76,7 +96,12 @@ public class InlineModelResolverTest { new InlineModelResolver().flatten(swagger); - Json.prettyPrint(swagger); + Model model = swagger.getDefinitions().get("User"); + assertTrue(model instanceof ArrayModel); + + Model user = swagger.getDefinitions().get("User_inner"); + assertNotNull(user); + assertEquals("description", user.getDescription()); } @Test @@ -92,6 +117,80 @@ public class InlineModelResolverTest { new InlineModelResolver().flatten(swagger); - Json.prettyPrint(swagger); + Operation operation = swagger.getPaths().get("/hello").getGet(); + BodyParameter bp = (BodyParameter)operation.getParameters().get(0); + assertTrue(bp.getSchema() instanceof RefModel); + + Model body = swagger.getDefinitions().get("body"); + assertTrue(body instanceof ModelImpl); + + ModelImpl impl = (ModelImpl) body; + assertNotNull(impl.getProperties().get("name")); + } + + @Test + public void resolveInlineArrayResponse() throws Exception { + Swagger swagger = new Swagger(); + + swagger.path("/foo/baz", new Path() + .get(new Operation() + .response(200, new Response() + .vendorExtension("x-foo", "bar") + .description("it works!") + .schema(new ArrayProperty() + .items( + new ObjectProperty() + .property("name", new StringProperty())))))); + + new InlineModelResolver().flatten(swagger); + + Response response = swagger.getPaths().get("/foo/baz").getGet().getResponses().get("200"); + assertNotNull(response); + + assertNotNull(response.getSchema()); + Property responseProperty = response.getSchema(); + assertTrue(responseProperty instanceof RefProperty); + + Model inline = swagger.getDefinitions().get("inline_response_200"); + assertNotNull(inline); + assertTrue(inline instanceof ArrayModel); + + ArrayModel am = (ArrayModel) inline; + assertTrue(am.getItems() instanceof RefProperty); + + Model inlineInner = swagger.getDefinitions().get("inline_response_200_inner"); + assertNotNull(inlineInner); + assertTrue(inlineInner instanceof ModelImpl); + + ModelImpl innerModel = (ModelImpl) inlineInner; + assertTrue(innerModel.getProperties().size() == 1); + assertNotNull(innerModel.getProperties().get("name")); + } + + @Test + public void testInlineMapResponse() throws Exception { + Swagger swagger = new Swagger(); + + MapProperty schema = new MapProperty(); + schema.setAdditionalProperties(new StringProperty()); + + swagger.path("/foo/baz", new Path() + .get(new Operation() + .response(200, new Response() + .vendorExtension("x-foo", "bar") + .description("it works!") + .schema(schema)))); + new InlineModelResolver().flatten(swagger); + + Response response = swagger.getPaths().get("/foo/baz").getGet().getResponses().get("200"); + + Property property = response.getSchema(); + assertTrue(property instanceof RefProperty); + + Model inline = swagger.getDefinitions().get("inline_response_200"); + assertTrue(inline instanceof ArrayModel); + ArrayModel am = (ArrayModel) inline; + Property innerProperty = am.getItems(); + assertTrue(innerProperty instanceof StringProperty); } }