diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenProperty.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenProperty.java index 7872da2c707..2f186816d1e 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenProperty.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenProperty.java @@ -34,4 +34,108 @@ public class CodegenProperty { public boolean isEnum; public List _enum; public Map allowableValues; + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final CodegenProperty other = (CodegenProperty) obj; + if ((this.baseName == null) ? (other.baseName != null) : !this.baseName.equals(other.baseName)) { + return false; + } + if ((this.complexType == null) ? (other.complexType != null) : !this.complexType.equals(other.complexType)) { + return false; + } + if ((this.getter == null) ? (other.getter != null) : !this.getter.equals(other.getter)) { + return false; + } + if ((this.setter == null) ? (other.setter != null) : !this.setter.equals(other.setter)) { + return false; + } + if ((this.description == null) ? (other.description != null) : !this.description.equals(other.description)) { + return false; + } + if ((this.datatype == null) ? (other.datatype != null) : !this.datatype.equals(other.datatype)) { + return false; + } + if ((this.datatypeWithEnum == null) ? (other.datatypeWithEnum != null) : !this.datatypeWithEnum.equals(other.datatypeWithEnum)) { + return false; + } + if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) { + return false; + } + if ((this.min == null) ? (other.min != null) : !this.min.equals(other.min)) { + return false; + } + if ((this.max == null) ? (other.max != null) : !this.max.equals(other.max)) { + return false; + } + if ((this.defaultValue == null) ? (other.defaultValue != null) : !this.defaultValue.equals(other.defaultValue)) { + return false; + } + if ((this.baseType == null) ? (other.baseType != null) : !this.baseType.equals(other.baseType)) { + return false; + } + if ((this.containerType == null) ? (other.containerType != null) : !this.containerType.equals(other.containerType)) { + return false; + } + if (this.maxLength != other.maxLength && (this.maxLength == null || !this.maxLength.equals(other.maxLength))) { + return false; + } + if (this.minLength != other.minLength && (this.minLength == null || !this.minLength.equals(other.minLength))) { + return false; + } + if ((this.pattern == null) ? (other.pattern != null) : !this.pattern.equals(other.pattern)) { + return false; + } + if ((this.example == null) ? (other.example != null) : !this.example.equals(other.example)) { + return false; + } + if ((this.jsonSchema == null) ? (other.jsonSchema != null) : !this.jsonSchema.equals(other.jsonSchema)) { + return false; + } + if (this.minimum != other.minimum && (this.minimum == null || !this.minimum.equals(other.minimum))) { + return false; + } + if (this.maximum != other.maximum && (this.maximum == null || !this.maximum.equals(other.maximum))) { + return false; + } + if (this.exclusiveMinimum != other.exclusiveMinimum && (this.exclusiveMinimum == null || !this.exclusiveMinimum.equals(other.exclusiveMinimum))) { + return false; + } + if (this.exclusiveMaximum != other.exclusiveMaximum && (this.exclusiveMaximum == null || !this.exclusiveMaximum.equals(other.exclusiveMaximum))) { + return false; + } + if (this.required != other.required && (this.required == null || !this.required.equals(other.required))) { + return false; + } + if (this.secondaryParam != other.secondaryParam && (this.secondaryParam == null || !this.secondaryParam.equals(other.secondaryParam))) { + return false; + } + if (this.isPrimitiveType != other.isPrimitiveType && (this.isPrimitiveType == null || !this.isPrimitiveType.equals(other.isPrimitiveType))) { + return false; + } + if (this.isContainer != other.isContainer && (this.isContainer == null || !this.isContainer.equals(other.isContainer))) { + return false; + } + if (this.isNotContainer != other.isNotContainer && (this.isNotContainer == null || !this.isNotContainer.equals(other.isNotContainer))) { + return false; + } + if (this.isEnum != other.isEnum) { + return false; + } + if (this._enum != other._enum && (this._enum == null || !this._enum.equals(other._enum))) { + return false; + } + if (this.allowableValues != other.allowableValues && (this.allowableValues == null || !this.allowableValues.equals(other.allowableValues))) { + return false; + } + return true; + } + + } diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavaClientCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavaClientCodegen.java index 099a9cb9add..678cce9263a 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavaClientCodegen.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavaClientCodegen.java @@ -1,17 +1,30 @@ package io.swagger.codegen.languages; +import com.google.common.base.Strings; import io.swagger.codegen.CliOption; import io.swagger.codegen.CodegenConfig; +import io.swagger.codegen.CodegenModel; +import io.swagger.codegen.CodegenProperty; import io.swagger.codegen.CodegenType; import io.swagger.codegen.DefaultCodegen; import io.swagger.codegen.SupportingFile; +import io.swagger.models.ComposedModel; +import io.swagger.models.Model; +import io.swagger.models.ModelImpl; +import io.swagger.models.RefModel; import io.swagger.models.properties.ArrayProperty; import io.swagger.models.properties.MapProperty; import io.swagger.models.properties.Property; +import io.swagger.models.properties.StringProperty; 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 org.apache.commons.lang.StringUtils; @@ -255,6 +268,57 @@ public class JavaClientCodegen extends DefaultCodegen implements CodegenConfig { return camelize(operationId, true); } + @Override + public CodegenModel fromModel(String name, Model model, Map allDefinitions) { + CodegenModel codegenModel = super.fromModel(name, model, allDefinitions); + + if (allDefinitions != null && codegenModel != null && codegenModel.parent != null && codegenModel.hasEnums) { + final Model parentModel = allDefinitions.get(toModelName(codegenModel.parent)); + final CodegenModel parentCodegenModel = super.fromModel(codegenModel.parent, parentModel); + codegenModel = this.reconcileInlineEnums(codegenModel, parentCodegenModel); + } + + return codegenModel; + } + + private CodegenModel reconcileInlineEnums(CodegenModel codegenModel, CodegenModel parentCodegenModel) { + // This generator uses inline classes to define enums, which breaks when + // dealing with models that have subTypes. To clean this up, we will analyze + // the parent and child models, look for enums that match, and remove + // them from the child models and leave them in the parent. + // Because the child models extend the parents, the enums will be available via the parent. + + // Only bother with reconciliation if the parent model has enums. + if (parentCodegenModel.hasEnums) { + + // Get the properties for the parent and child models + final List parentModelCodegenProperties = parentCodegenModel.vars; + List codegenProperties = codegenModel.vars; + + // Iterate over all of the parent model properties + for (CodegenProperty parentModelCodegenPropery : parentModelCodegenProperties) { + // Look for enums + if (parentModelCodegenPropery.isEnum) { + // Now that we have found an enum in the parent class, + // and search the child class for the same enum. + Iterator iterator = codegenProperties.iterator(); + while (iterator.hasNext()) { + CodegenProperty codegenProperty = iterator.next(); + if (codegenProperty.isEnum && codegenProperty.equals(parentModelCodegenPropery)) { + // We found an enum in the child class that is + // a duplicate of the one in the parent, so remove it. + iterator.remove(); + } + } + } + } + + codegenModel.vars = codegenProperties; + } + + return codegenModel; + } + public void setInvokerPackage(String invokerPackage) { this.invokerPackage = invokerPackage; } diff --git a/modules/swagger-codegen/src/test/scala/Java/JavaModelEnumTest.scala b/modules/swagger-codegen/src/test/scala/Java/JavaModelEnumTest.scala index e5191e1ae23..30a70ca6dfb 100644 --- a/modules/swagger-codegen/src/test/scala/Java/JavaModelEnumTest.scala +++ b/modules/swagger-codegen/src/test/scala/Java/JavaModelEnumTest.scala @@ -31,4 +31,55 @@ class JavaModelEnumTest extends FlatSpec with Matchers { enumVar.baseType should be("String") enumVar.isEnum should equal(true) } + + it should "not override identical parent enums" in { + + val identicalEnumProperty = new StringProperty() + identicalEnumProperty.setEnum(List("VALUE1", "VALUE2", "VALUE3").asJava) + + val subEnumProperty = new StringProperty() + subEnumProperty.setEnum(List("SUB1", "SUB2", "SUB3").asJava) + + // Add one enum ptoperty to the parent + val parentProperties = new java.util.HashMap[String, Property]() + parentProperties.put("sharedThing", identicalEnumProperty) + + // Add TWO enums to the subType model; one of which is identical to the one in parent class + val subProperties = new java.util.HashMap[String, Property]() + subProperties.put("sharedThing", identicalEnumProperty) + subProperties.put("unsharedThing", identicalEnumProperty) + + val parentModel = new ModelImpl(); + parentModel.setProperties(parentProperties); + parentModel.name("parentModel"); + + val subModel = new ModelImpl(); + subModel.setProperties(subProperties); + subModel.name("subModel"); + + val model = new ComposedModel() + .parent(new RefModel(parentModel.getName())) + .child(subModel) + .interfaces(new java.util.ArrayList[RefModel]()) + + val codegen = new JavaClientCodegen() + val allModels = new java.util.HashMap[String, Model]() + allModels.put(codegen.toModelName(parentModel.getName()), parentModel) + allModels.put(codegen.toModelName(subModel.getName()), subModel) + + val cm = codegen.fromModel("sample", model, allModels) + + cm.name should be("sample") + cm.classname should be("Sample") + cm.parent should be("ParentModel") + cm.imports.asScala should be(Set("ParentModel")) + + // Assert that only the unshared/uninherited enum remains + cm.vars.size should be (1) + val enumVar = cm.vars.get(0) + enumVar.baseName should be("unsharedThing") + enumVar.datatype should be("String") + enumVar.datatypeWithEnum should be("UnsharedThingEnum") + enumVar.isEnum should equal(true) + } } \ No newline at end of file