diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenModel.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenModel.java index 438eb191294..76fcbc3d21c 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenModel.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenModel.java @@ -20,6 +20,7 @@ public class CodegenModel { public List requiredVars = new ArrayList(); // a list of required properties public List optionalVars = new ArrayList(); // a list of optional properties public List allVars; + public List parentVars = new ArrayList<>(); public Map allowableValues; // Sorted sets of required parameters. @@ -27,7 +28,7 @@ public class CodegenModel { public Set allMandatory; public Set imports = new TreeSet(); - public Boolean hasVars, emptyVars, hasMoreModels, hasEnums, isEnum, hasRequired; + public Boolean hasVars, emptyVars, hasMoreModels, hasEnums, isEnum, hasRequired,hasChildrens; public ExternalDocs externalDocs; public Map vendorExtensions; @@ -109,6 +110,10 @@ public class CodegenModel { return false; if (externalDocs != null ? !externalDocs.equals(that.externalDocs) : that.externalDocs != null) return false; + if (!Objects.equals(hasChildrens, that.hasChildrens)) + return false; + if (!Objects.equals(parentVars, that.parentVars)) + return false; return vendorExtensions != null ? vendorExtensions.equals(that.vendorExtensions) : that.vendorExtensions == null; } @@ -145,6 +150,8 @@ public class CodegenModel { result = 31 * result + (isEnum != null ? isEnum.hashCode() : 0); result = 31 * result + (externalDocs != null ? externalDocs.hashCode() : 0); result = 31 * result + (vendorExtensions != null ? vendorExtensions.hashCode() : 0); + result = 31 * result + Objects.hash(hasChildrens); + result = 31 * result + Objects.hash(parentVars); return result; } } 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 d58a1a81b1d..558a280ca03 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 @@ -2,8 +2,9 @@ package io.swagger.codegen; import java.util.List; import java.util.Map; +import java.util.Objects; -public class CodegenProperty { +public class CodegenProperty implements Cloneable { public String baseName, complexType, getter, setter, description, datatype, datatypeWithEnum, name, min, max, defaultValue, defaultValueWithParam, baseType, containerType; @@ -43,6 +44,8 @@ public class CodegenProperty { public CodegenProperty items; public Map vendorExtensions; public Boolean hasValidation; // true if pattern, maximum, etc are set (only used in the mustache template) + public String parent; + public String parentClass; @Override public String toString() { @@ -105,6 +108,8 @@ public class CodegenProperty { result = prime * result + ((isDateTime == null) ? 0 : isDateTime.hashCode()); result = prime * result + ((isMapContainer == null) ? 0 : isMapContainer.hashCode()); result = prime * result + ((isListContainer == null) ? 0 : isListContainer.hashCode()); + result = prime * result + Objects.hashCode(parent); + result = prime * result + Objects.hashCode(parentClass); return result; } @@ -256,6 +261,21 @@ public class CodegenProperty { if (this.isMapContainer != other.isMapContainer && (this.isMapContainer == null || !this.isMapContainer.equals(other.isMapContainer))) { return false; } + if (!Objects.equals(this.parent, other.parent)) { + return false; + } + if (!Objects.equals(this.parentClass, other.parentClass)) { + return false; + } return true; } + + @Override + public CodegenProperty clone() { + try { + return (CodegenProperty) super.clone(); + } catch (CloneNotSupportedException e) { + throw new IllegalStateException(e); + } + } } diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/NancyFXServerCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/NancyFXServerCodegen.java index a908143bdb2..9c7afce6d9e 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/NancyFXServerCodegen.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/NancyFXServerCodegen.java @@ -19,6 +19,7 @@ import static io.swagger.codegen.CodegenType.SERVER; import static java.util.Arrays.asList; import static java.util.UUID.randomUUID; import static org.apache.commons.lang3.StringUtils.capitalize; +import io.swagger.codegen.CodegenModel; import io.swagger.codegen.CodegenOperation; import io.swagger.codegen.CodegenProperty; import io.swagger.codegen.CodegenType; @@ -29,19 +30,24 @@ import io.swagger.models.properties.StringProperty; import java.io.File; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Predicate; +import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Multimap; public class NancyFXServerCodegen extends AbstractCSharpCodegen { private static final Logger log = LoggerFactory.getLogger(NancyFXServerCodegen.class); @@ -56,6 +62,8 @@ public class NancyFXServerCodegen extends AbstractCSharpCodegen { private final String packageGuid = "{" + randomUUID().toString().toUpperCase() + "}"; private final Map dependencies = new HashMap<>(); + private final Set parentModels = new HashSet<>(); + private final Multimap parentChildrens = ArrayListMultimap.create(); private final BiMap modelNameMapping = HashBiMap.create(); public NancyFXServerCodegen() { @@ -205,12 +213,89 @@ public class NancyFXServerCodegen extends AbstractCSharpCodegen { } } + @Override + public Map postProcessAllModels(final Map models) { + final Map processed = super.postProcessAllModels(models); + postProcessParentModels(models); + return processed; + } + + private void postProcessParentModels(final Map models) { + log.info("Processing parents: " + parentModels); + for (final String parent : parentModels) { + final CodegenModel parentModel = modelByName(parent, models); + parentModel.hasChildrens = true; + final Collection childrens = parentChildrens.get(parent); + for (final CodegenModel child : childrens) { + processParentPropertiesInChildModel(parentModel, child); + } + } + } + + private CodegenModel modelByName(final String name, final Map models) { + final Object data = models.get(name); + if (data instanceof Map) { + final Map dataMap = (Map) data; + final Object dataModels = dataMap.get("models"); + if (dataModels instanceof List) { + final List dataModelsList = (List) dataModels; + for (final Object entry : dataModelsList) { + if (entry instanceof Map) { + final Map entryMap = (Map) entry; + final Object model = entryMap.get("model"); + if (model instanceof CodegenModel) { + return (CodegenModel) model; + } + } + } + } + } + return null; + } + + private void processParentPropertiesInChildModel(final CodegenModel parent, final CodegenModel child) { + final Map childPropertiesByName = new HashMap<>(child.vars.size()); + for (final CodegenProperty property : child.vars) { + childPropertiesByName.put(property.name, property); + } + CodegenProperty previousParentVar = null; + for (final CodegenProperty property : parent.vars) { + final CodegenProperty duplicatedByParent = childPropertiesByName.get(property.name); + if (duplicatedByParent != null) { + log.info(String.format("Property: '%s' in '%s' model is inherited from '%s'" , + property.name, child.classname, parent.classname)); + duplicatedByParent.parent = parent.name; + duplicatedByParent.parentClass = parent.classname; + + final CodegenProperty parentVar = duplicatedByParent.clone(); + parentVar.hasMore = false; + child.parentVars.add(parentVar); + if (previousParentVar != null) { + previousParentVar.hasMore = true; + } + previousParentVar = parentVar; + } + } + } + + @Override + public void postProcessModelProperty(final CodegenModel model, final CodegenProperty property) { + super.postProcessModelProperty(model, property); + if (!isNullOrEmpty(model.parent)) { + parentModels.add(model.parent); + if (!parentChildrens.containsEntry(model.parent, model)) { + parentChildrens.put(model.parent, model); + } + } + } + @Override public String toEnumVarName(final String name, final String datatype) { final String enumName = camelize( sanitizeName(name) .replaceFirst("^_", "") - .replaceFirst("_$", "")); + .replaceFirst("_$", "") + .replaceAll("-", "_")); final String result; if (enumName.matches("\\d.*")) { result = "_" + enumName; @@ -269,7 +354,7 @@ public class NancyFXServerCodegen extends AbstractCSharpCodegen { @Override public String toEnumName(final CodegenProperty property) { - return sanitizeName(camelize(property.name)) ; + return sanitizeName(camelize(property.name)); } @Override diff --git a/modules/swagger-codegen/src/main/resources/nancyfx/innerModelEnum.mustache b/modules/swagger-codegen/src/main/resources/nancyfx/innerModelEnum.mustache index 19e4731f2cf..54d23b1d8d5 100644 --- a/modules/swagger-codegen/src/main/resources/nancyfx/innerModelEnum.mustache +++ b/modules/swagger-codegen/src/main/resources/nancyfx/innerModelEnum.mustache @@ -1 +1 @@ -public enum {{#datatypeWithEnum}}{{.}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}} { {{#allowableValues}}{{#enumVars}}{{{name}}}{{^-last}}, {{/-last}}{{/enumVars}}{{/allowableValues}} }; \ No newline at end of file +public enum {{#parentClass}}{{parentClass}}{{/parentClass}}{{^parentClass}}{{classname}}{{/parentClass}}{{#datatypeWithEnum}}{{.}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}} { {{#allowableValues}}{{#enumVars}}{{{name}}}{{^-last}}, {{/-last}}{{/enumVars}}{{/allowableValues}} }; \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/nancyfx/model.mustache b/modules/swagger-codegen/src/main/resources/nancyfx/model.mustache index e199575a130..409bd60641a 100644 --- a/modules/swagger-codegen/src/main/resources/nancyfx/model.mustache +++ b/modules/swagger-codegen/src/main/resources/nancyfx/model.mustache @@ -10,40 +10,42 @@ using NodaTime; {{#models}} {{#model}} namespace {{packageName}}.{{packageContext}}.Models -{ {{#vars}}{{#isEnum}} - {{>innerModelEnum}}{{/isEnum}}{{#items.isEnum}} +{ {{#vars}}{{#isEnum}}{{^parent}} + {{>innerModelEnum}}{{/parent}}{{/isEnum}}{{#items.isEnum}} {{#items}}{{>innerModelEnum}}{{/items}}{{/items.isEnum}}{{/vars}} /// /// {{#description}}{{.}}{{/description}}{{^description}}{{classname}}{{/description}} /// - public sealed class {{classname}}: {{#parent}}{{{parent}}}, {{/parent}} IEquatable<{{classname}}> - { {{#vars}} + public {{^hasChildrens}}sealed {{/hasChildrens}}class {{classname}}: {{#parent}}{{{parent}}}, {{/parent}} IEquatable<{{classname}}> + { {{#vars}}{{^parent}} /// /// {{^description}}{{{name}}}{{/description}}{{#description}}{{description}}{{/description}} /// public {{>nullableDataType}} {{name}} { get; private set; } -{{/vars}} +{{/parent}}{{/vars}} /// /// Empty constructor required by some serializers. /// Use {{classname}}.Builder() for instance creation instead. /// [Obsolete] - public {{classname}}() {} - - private {{classname}}({{#vars}}{{>nullableDataType}} {{name}}{{#hasMore}}, {{/hasMore}}{{/vars}}) + public {{classname}}(){{#parent}} : base({{/parent}}{{#parentVars}}null{{#hasMore}}, {{/hasMore}}{{/parentVars}}{{#parent}}){{/parent}} { - {{#vars}} + } + + {{#hasChildrens}}protected{{/hasChildrens}}{{^hasChildrens}}private{{/hasChildrens}} {{classname}}({{#vars}}{{>nullableDataType}} {{name}}{{#hasMore}}, {{/hasMore}}{{/vars}}){{#parent}} : base({{#parentVars}}{{name}}{{#hasMore}}, {{/hasMore}}{{/parentVars}}){{/parent}} + { + {{#vars}}{{^parent}} this.{{name}} = {{name}}; - {{/vars}} + {{/parent}}{{/vars}} } /// /// Returns builder of {{classname}}. /// /// {{classname}}Builder - public static {{classname}}Builder Builder() + public static {{#parent}}new {{/parent}}{{classname}}Builder Builder() { return new {{classname}}Builder(); } @@ -53,7 +55,7 @@ namespace {{packageName}}.{{packageContext}}.Models /// Use it to change properties. /// /// {{classname}}Builder - public {{classname}}Builder With() + public {{#parent}}new {{/parent}}{{classname}}Builder With() { return Builder() {{#vars}} diff --git a/modules/swagger-codegen/src/main/resources/nancyfx/modelMutable.mustache b/modules/swagger-codegen/src/main/resources/nancyfx/modelMutable.mustache index bcded25eec8..038d4224eb1 100644 --- a/modules/swagger-codegen/src/main/resources/nancyfx/modelMutable.mustache +++ b/modules/swagger-codegen/src/main/resources/nancyfx/modelMutable.mustache @@ -10,14 +10,14 @@ using NodaTime; {{#models}} {{#model}} namespace {{packageName}}.{{packageContext}}.Models -{ {{#vars}}{{#isEnum}} - {{>innerModelEnum}}{{/isEnum}}{{#items.isEnum}} +{ {{#vars}}{{#isEnum}}{{^parent}} + {{>innerModelEnum}}{{/parent}}{{/isEnum}}{{#items.isEnum}} {{#items}}{{>innerModelEnum}}{{/items}}{{/items.isEnum}}{{/vars}} - /// +/// /// {{#description}}{{.}}{{/description}}{{^description}}{{classname}}{{/description}} /// - public sealed class {{classname}}: {{#parent}}{{{parent}}}, {{/parent}} IEquatable<{{classname}}> + public {{^hasChildrens}}sealed {{/hasChildrens}}class {{classname}}: {{#parent}}{{{parent}}}, {{/parent}} IEquatable<{{classname}}> { {{#vars}} /// /// {{^description}}{{{name}}}{{/description}}{{#description}}{{description}}{{/description}} diff --git a/modules/swagger-codegen/src/main/resources/nancyfx/nullableDataType.mustache b/modules/swagger-codegen/src/main/resources/nancyfx/nullableDataType.mustache index c999b870119..534590a7f89 100644 --- a/modules/swagger-codegen/src/main/resources/nancyfx/nullableDataType.mustache +++ b/modules/swagger-codegen/src/main/resources/nancyfx/nullableDataType.mustache @@ -1 +1 @@ -{{&datatypeWithEnum}}{{#isEnum}}?{{/isEnum}} \ No newline at end of file +{{#isEnum}}{{#parentClass}}{{parentClass}}{{/parentClass}}{{^parentClass}}{{classname}}{{/parentClass}}{{/isEnum}}{{&datatypeWithEnum}}{{#isEnum}}?{{/isEnum}} \ No newline at end of file