Merge pull request #738 from tomtit/issue429

Fixes #429: Handling of composed models has been added.
This commit is contained in:
Tony Tam 2015-05-23 15:10:38 -07:00
commit 095771d345
4 changed files with 126 additions and 112 deletions

View File

@ -1,10 +1,30 @@
package com.wordnik.swagger.codegen; package com.wordnik.swagger.codegen;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.Nullable;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.wordnik.swagger.codegen.examples.ExampleGenerator; import com.wordnik.swagger.codegen.examples.ExampleGenerator;
import com.wordnik.swagger.models.ArrayModel; import com.wordnik.swagger.models.ArrayModel;
import com.wordnik.swagger.models.ComposedModel;
import com.wordnik.swagger.models.Model; import com.wordnik.swagger.models.Model;
import com.wordnik.swagger.models.ModelImpl; import com.wordnik.swagger.models.ModelImpl;
import com.wordnik.swagger.models.Operation; import com.wordnik.swagger.models.Operation;
@ -40,27 +60,9 @@ import com.wordnik.swagger.models.properties.RefProperty;
import com.wordnik.swagger.models.properties.StringProperty; import com.wordnik.swagger.models.properties.StringProperty;
import com.wordnik.swagger.util.Json; import com.wordnik.swagger.util.Json;
import javax.annotation.Nullable;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DefaultCodegen { public class DefaultCodegen {
Logger LOGGER = LoggerFactory.getLogger(DefaultCodegen.class); private static final Logger LOGGER = LoggerFactory.getLogger(DefaultCodegen.class);
protected String outputFolder = ""; protected String outputFolder = "";
protected Set<String> defaultIncludes = new HashSet<String>(); protected Set<String> defaultIncludes = new HashSet<String>();
@ -473,100 +475,28 @@ public class DefaultCodegen {
m.classVarName = toVarName(name); m.classVarName = toVarName(name);
m.modelJson = Json.pretty(model); m.modelJson = Json.pretty(model);
m.externalDocs = model.getExternalDocs(); m.externalDocs = model.getExternalDocs();
int count = 0;
if(model instanceof ArrayModel) { if(model instanceof ArrayModel) {
ArrayModel am = (ArrayModel) model; ArrayModel am = (ArrayModel) model;
ArrayProperty arrayProperty = new ArrayProperty(am.getItems()); ArrayProperty arrayProperty = new ArrayProperty(am.getItems());
CodegenProperty cp = fromProperty(name, arrayProperty); addParentContainer(m, name, arrayProperty);
if(cp.complexType != null && !defaultIncludes.contains(cp.complexType))
m.imports.add(cp.complexType);
m.parent = toInstantiationType(arrayProperty);
String containerType = cp.containerType;
if(instantiationTypes.containsKey(containerType))
m.imports.add(instantiationTypes.get(containerType));
if(typeMapping.containsKey(containerType)) {
containerType = typeMapping.get(containerType);
cp.containerType = containerType;
m.imports.add(containerType);
}
} }
else if (model instanceof RefModel) { else if (model instanceof RefModel) {
// TODO // TODO
} } else if (model instanceof ComposedModel) {
else { final ComposedModel composed = (ComposedModel) model;
final RefModel parent = (RefModel) composed.getParent();
final String parentModel = toModelName(parent.getSimpleRef());
m.parent = parentModel;
addImport(m, parentModel);
final ModelImpl child = (ModelImpl) composed.getChild();
addVars(m, child.getProperties(), child.getRequired());
} else {
ModelImpl impl = (ModelImpl) model; ModelImpl impl = (ModelImpl) model;
if(impl.getAdditionalProperties() != null) { if(impl.getAdditionalProperties() != null) {
MapProperty mapProperty = new MapProperty(impl.getAdditionalProperties()); MapProperty mapProperty = new MapProperty(impl.getAdditionalProperties());
CodegenProperty cp = fromProperty(name, mapProperty); addParentContainer(m, name, mapProperty);
if(cp.complexType != null && !defaultIncludes.contains(cp.complexType))
m.imports.add(cp.complexType);
m.parent = toInstantiationType(mapProperty);
String containerType = cp.containerType;
if(instantiationTypes.containsKey(containerType))
m.imports.add(instantiationTypes.get(containerType));
if(typeMapping.containsKey(containerType)) {
containerType = typeMapping.get(containerType);
cp.containerType = containerType;
m.imports.add(containerType);
}
}
if(impl.getProperties() != null && impl.getProperties().size() > 0) {
m.hasVars = true;
m.hasEnums = false;
for(String key: impl.getProperties().keySet()) {
Property prop = impl.getProperties().get(key);
if(prop == null) {
LOGGER.warn("null property for " + key);
}
else {
CodegenProperty cp;
try{
cp = fromProperty(key, prop);
}
catch(Exception e) {
System.out.println("failed to process model " + name);
throw new RuntimeException(e);
}
cp.required = null;
if(impl.getRequired() != null) {
for(String req : impl.getRequired()) {
if(key.equals(req))
cp.required = true;
}
}
if(cp.complexType != null && !defaultIncludes.contains(cp.complexType)) {
m.imports.add(cp.complexType);
}
m.vars.add(cp);
count += 1;
if (cp.isEnum)
m.hasEnums = true;
if(count != impl.getProperties().keySet().size())
cp.hasMore = new Boolean(true);
if(cp.isContainer != null) {
String arrayImport = typeMapping.get("array");
if(arrayImport != null &&
!languageSpecificPrimitives.contains(arrayImport) &&
!defaultIncludes.contains(arrayImport))
m.imports.add(arrayImport);
}
if(cp.complexType != null &&
!languageSpecificPrimitives.contains(cp.complexType) &&
!defaultIncludes.contains(cp.complexType))
m.imports.add(cp.complexType);
if(cp.baseType != null &&
!languageSpecificPrimitives.contains(cp.baseType) &&
!defaultIncludes.contains(cp.baseType))
m.imports.add(cp.baseType);
}
}
}
else {
m.emptyVars = true;
} }
addVars(m, impl.getProperties(), impl.getRequired());
} }
return m; return m;
} }
@ -1149,6 +1079,62 @@ public class DefaultCodegen {
co.baseName = tag; co.baseName = tag;
} }
private void addParentContainer(CodegenModel m, String name, Property property) {
final CodegenProperty tmp = fromProperty(name, property);
addImport(m, tmp.complexType);
m.parent = toInstantiationType(property);
final String containerType = tmp.containerType;
final String instantiationType = instantiationTypes.get(containerType);
if (instantiationType != null) {
addImport(m, instantiationType);
}
final String mappedType = typeMapping.get(containerType);
if (mappedType != null) {
addImport(m, mappedType);
}
}
private void addImport(CodegenModel m, String type) {
if (type != null && !languageSpecificPrimitives.contains(type) && !defaultIncludes.contains(type)) {
m.imports.add(type);
}
}
private void addVars(CodegenModel m, Map<String, Property> properties, Collection<String> required) {
if (properties != null && properties.size() > 0) {
m.hasVars = true;
m.hasEnums = false;
final int totalCount = properties.size();
final Set<String> mandatory = required == null ? Collections.<String> emptySet() : new HashSet<String>(required);
int count = 0;
for (Map.Entry<String, Property> entry : properties.entrySet()) {
final String key = entry.getKey();
final Property prop = entry.getValue();
if (prop == null) {
LOGGER.warn("null property for " + key);
} else {
final CodegenProperty cp = fromProperty(key, prop);
cp.required = mandatory.contains(key) ? true : null;
if (cp.isEnum) {
m.hasEnums = true;
}
count += 1;
if (count != totalCount)
cp.hasMore = true;
if (cp.isContainer != null) {
addImport(m, typeMapping.get("array"));
}
addImport(m, cp.baseType);
addImport(m, cp.complexType);
m.vars.add(cp);
}
}
} else {
m.emptyVars = true;
}
}
/* underscore and camelize are copied from Twitter elephant bird /* underscore and camelize are copied from Twitter elephant bird
* https://github.com/twitter/elephant-bird/blob/master/core/src/main/java/com/twitter/elephantbird/util/Strings.java * https://github.com/twitter/elephant-bird/blob/master/core/src/main/java/com/twitter/elephantbird/util/Strings.java
*/ */

View File

@ -0,0 +1,28 @@
package Java
import scala.collection.JavaConverters._
import org.junit.runner.RunWith
import org.scalatest.FlatSpec
import org.scalatest.Matchers
import org.scalatest.junit.JUnitRunner
import com.wordnik.swagger.codegen.languages.JavaClientCodegen
import com.wordnik.swagger.models.ComposedModel
import com.wordnik.swagger.models.ModelImpl
import com.wordnik.swagger.models.RefModel
import com.wordnik.swagger.models.properties.StringProperty
@RunWith(classOf[JUnitRunner])
class JavaInheritanceTest extends FlatSpec with Matchers {
it should "convert a composed model" in {
val model = new ComposedModel().parent(new RefModel("Base")).child(new ModelImpl().additionalProperties(new StringProperty()))
val codegen = new JavaClientCodegen()
val cm = codegen.fromModel("sample", model)
cm.name should be("sample")
cm.classname should be("Sample")
cm.parent should be("Base")
cm.imports.asScala should be (Set("Base"))
}
}

View File

@ -1,4 +1,4 @@
package objc package Objc
import com.wordnik.swagger.codegen.languages.ObjcClientCodegen import com.wordnik.swagger.codegen.languages.ObjcClientCodegen
import com.wordnik.swagger.util.Json import com.wordnik.swagger.util.Json
@ -217,8 +217,8 @@ class ObjcModelTest extends FlatSpec with Matchers {
cm.description should be ("an array model") cm.description should be ("an array model")
cm.vars.size should be (0) cm.vars.size should be (0)
cm.parent should be ("NSMutableArray") cm.parent should be ("NSMutableArray")
cm.imports.size should be (3) cm.imports.size should be (1)
(cm.imports.asScala.toSet & Set("SWGChildren", "NSArray", "NSMutableArray")).size should be (3) (cm.imports.asScala.toSet & Set("SWGChildren")).size should be (1)
} }
it should "convert an map model" in { it should "convert an map model" in {
@ -234,8 +234,8 @@ class ObjcModelTest extends FlatSpec with Matchers {
cm.description should be ("an map model") cm.description should be ("an map model")
cm.vars.size should be (0) cm.vars.size should be (0)
cm.parent should be ("NSMutableDictionary") cm.parent should be ("NSMutableDictionary")
cm.imports.size should be (3) cm.imports.size should be (1)
(cm.imports.asScala.toSet & Set("SWGChildren", "NSDictionary", "NSMutableDictionary")).size should be (3) (cm.imports.asScala.toSet & Set("SWGChildren")).size should be (1)
} }
it should "create proper imports per #316" in { it should "create proper imports per #316" in {

View File

@ -1,4 +1,4 @@
package Java package scala
import com.wordnik.swagger.codegen.languages.ScalaClientCodegen import com.wordnik.swagger.codegen.languages.ScalaClientCodegen
import com.wordnik.swagger.util.Json import com.wordnik.swagger.util.Json
@ -218,8 +218,8 @@ class ScalaModelTest extends FlatSpec with Matchers {
cm.description should be ("an array model") cm.description should be ("an array model")
cm.vars.size should be (0) cm.vars.size should be (0)
cm.parent should be ("ListBuffer[Children]") cm.parent should be ("ListBuffer[Children]")
cm.imports.size should be (3) cm.imports.size should be (2)
(cm.imports.asScala.toSet & Set("List", "ListBuffer", "Children")).size should be (3) (cm.imports.asScala.toSet & Set("ListBuffer", "Children")).size should be (2)
} }
it should "convert an map model" in { it should "convert an map model" in {