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 new file mode 100644 index 0000000000..c285faf73b --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/InlineModelResolver.java @@ -0,0 +1,183 @@ +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 java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class InlineModelResolver { + private Swagger swagger = null; + + Map addedModels = new HashMap(); + + public void flatten(Swagger swagger) { + this.swagger = swagger; + + // operations + Map paths = swagger.getPaths(); + Map models = swagger.getDefinitions(); + + if(paths != null) { + for(String pathname : paths.keySet()) { + Path path = paths.get(pathname); + + for(Operation operation: path.getOperations()) { + List parameters = operation.getParameters(); + + if(parameters != null) { + 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); + } + else { + if (swagger.getDefinitions().containsKey(bp.getName())) { + name += "_" + "inline"; + } + } + swagger.addDefinition(name, model); + bp.setSchema(new RefModel(name)); + } + } + } + } + } + Map responses = operation.getResponses(); + if(responses != null) { + for(String key : responses.keySet()) { + Response response = responses.get(key); + if(response.getSchema() != null) { + Property property = response.getSchema(); + if(property instanceof ObjectProperty) { + String modelName = uniqueName("inline_response_" + key); + ObjectProperty op = (ObjectProperty) property; + Model model = modelFromProperty(op, modelName); + response.setSchema(new RefProperty(modelName)); + swagger.addDefinition(modelName, model); + } + } + } + } + } + } + } + + // definitions + if(models != null) { + List modelNames = new ArrayList(models.keySet()); + for(String modelName : modelNames) { + Model model = models.get(modelName); + if(model instanceof ModelImpl) { + ModelImpl m = (ModelImpl) model; + + 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)); + } + } + else if (model instanceof ComposedModel) { + ComposedModel m = (ComposedModel) model; + } + } + } + } + + public String uniqueName(String key) { + int count = 0; + boolean done = false; + while(!done) { + String name = key; + if(count > 0) { + name = key + "_" + count; + } + if(swagger.getDefinitions() == null) { + return name; + } + else if (!swagger.getDefinitions().containsKey(name)) { + return name; + } + count += 1; + } + return key; + } + + public void flattenProperties(Map properties, String path) { + if(properties == null) { + return; + } + Map propsToUpdate = new HashMap(); + Map modelsToAdd = new HashMap(); + for(String key : properties.keySet()) { + 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)); + } + } + if(propsToUpdate.size() > 0) { + for(String key : propsToUpdate.keySet()) { + properties.put(key, propsToUpdate.get(key)); + } + } + for(String key : modelsToAdd.keySet()) { + swagger.addDefinition(key, modelsToAdd.get(key)); + this.addedModels.put(key, modelsToAdd.get(key)); + } + } + + public Model modelFromProperty(ObjectProperty 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(); + + Map properties = object.getProperties(); + + ModelImpl model = new ModelImpl(); + model.setDescription(description); + model.setExample(example); + model.setName(name); + model.setXml(xml); + + if(properties != null) { + flattenProperties(properties, path); + model.setProperties(properties); + } + + return model; + } +} 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 new file mode 100644 index 0000000000..e922e0d6e2 --- /dev/null +++ b/modules/swagger-codegen/src/test/java/io/swagger/codegen/InlineModelResolverTest.java @@ -0,0 +1,97 @@ +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.util.Json; +import org.junit.Test; + +public class InlineModelResolverTest { + @Test + public void resolveInlineModelTest() throws Exception { + Swagger swagger = new Swagger(); + + swagger.addDefinition("User", new ModelImpl() + .name("user") + .description("a common user") + .property("name", new StringProperty()) + .property("address", new ObjectProperty() + .title("title") + ._default("default") + .access("access") + .readOnly(false) + .required(true) + .description("description") + .name("name") + .property("street", new StringProperty()) + .property("city", new StringProperty()))); + + new InlineModelResolver().flatten(swagger); + + Json.prettyPrint(swagger); + } + + @Test + public void testInlineResponseModel() throws Exception { + Swagger swagger = new Swagger(); + + swagger.path("/foo/bar", new Path() + .get(new Operation() + .response(200, new Response() + .description("it works!") + .schema(new ObjectProperty() + .property("name", new StringProperty()))))) + .path("/foo/baz", new Path() + .get(new Operation() + .response(200, new Response() + .vendorExtension("x-foo", "bar") + .description("it works!") + .schema(new ObjectProperty() + .vendorExtension("x-baz", "boo") + .property("name", new StringProperty() + .vendorExtension("x-bars", "bleh")))))); + new InlineModelResolver().flatten(swagger); + + Json.prettyPrint(swagger); + } + + @Test + public void resolveInlineArrayModel() throws Exception { + Swagger swagger = new Swagger(); + + swagger.addDefinition("User", new ArrayModel() + .items(new ObjectProperty() + .title("title") + ._default("default") + .access("access") + .readOnly(false) + .required(true) + .description("description") + .name("name") + .property("street", new StringProperty()) + .property("city", new StringProperty()))); + + new InlineModelResolver().flatten(swagger); + + Json.prettyPrint(swagger); + } + + @Test + public void resolveInlineBodyParameter() throws Exception { + Swagger swagger = new Swagger(); + + swagger.path("/hello", new Path() + .get(new Operation() + .parameter(new BodyParameter() + .name("body") + .schema(new ModelImpl() + .property("name", new StringProperty()))))); + + new InlineModelResolver().flatten(swagger); + + Json.prettyPrint(swagger); + } +}