From e4276853d760b452d59514d94db011c934a9348b Mon Sep 17 00:00:00 2001 From: Javier Velilla Date: Fri, 4 Aug 2017 13:38:50 -0300 Subject: [PATCH] Fixed typo in the Abstract Eiffel class. (#6239) Fixed typo in shell script Added support for Outer Enums, inner enums not supported. Added missing UUID library in ecf template. Improved Model inheritance. --- bin/eiffel-petstore.sh | 4 +- ...ogegen.java => AbstractEiffelCodegen.java} | 171 ++++++++++++++---- .../languages/EiffelClientCodegen.java | 55 +++++- .../src/main/resources/Eiffel/api.mustache | 1 + .../main/resources/Eiffel/api_client.mustache | 9 +- .../src/main/resources/Eiffel/ecf.mustache | 1 + .../src/main/resources/Eiffel/model.mustache | 13 +- .../main/resources/Eiffel/model_enum.mustache | 36 ++++ .../resources/Eiffel/model_generic.mustache | 7 + .../resources/Eiffel/test/ecf_test.mustache | 2 + samples/client/petstore/eiffel/api_client.ecf | 3 +- .../client/petstore/eiffel/test/api_test.ecf | 4 +- 12 files changed, 254 insertions(+), 52 deletions(-) rename modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/{AbstractEiffelCogegen.java => AbstractEiffelCodegen.java} (73%) create mode 100644 modules/swagger-codegen/src/main/resources/Eiffel/model_enum.mustache create mode 100644 modules/swagger-codegen/src/main/resources/Eiffel/model_generic.mustache diff --git a/bin/eiffel-petstore.sh b/bin/eiffel-petstore.sh index 126c8ca00197..f306cccfe708 100755 --- a/bin/eiffel-petstore.sh +++ b/bin/eiffel-petstore.sh @@ -26,6 +26,6 @@ fi # if you've executed sbt assembly previously it will use that instead. export JAVA_OPTS="${JAVA_OPTS} -XX:MaxPermSize=256M -Xmx1024M -DloggerPath=conf/log4j.properties" -ags="$@ generate -i modules/swagger-codegen/src/test/resources/2_0/petstore-with-fake-endpoints-models-for-testing.yaml -l eiffel -o samples/client/petstore/eiffel/" +args="$@ generate -i modules/swagger-codegen/src/test/resources/2_0/petstore-with-fake-endpoints-models-for-testing.yaml -l eiffel -o samples/client/petstore/eiffel/" -java $JAVA_OPTS -jar $executable $ags +java $JAVA_OPTS -jar $executable $args diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/AbstractEiffelCogegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/AbstractEiffelCodegen.java similarity index 73% rename from modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/AbstractEiffelCogegen.java rename to modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/AbstractEiffelCodegen.java index c6beb7f3a0c4..723e2fb1f7eb 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/AbstractEiffelCogegen.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/AbstractEiffelCodegen.java @@ -2,7 +2,6 @@ package io.swagger.codegen.languages; import static com.google.common.base.Strings.isNullOrEmpty; -import java.io.File; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; @@ -27,16 +26,18 @@ import io.swagger.codegen.CodegenParameter; import io.swagger.codegen.CodegenProperty; import io.swagger.codegen.DefaultCodegen; import io.swagger.codegen.utils.ModelUtils; +import io.swagger.models.Model; import io.swagger.models.properties.ArrayProperty; import io.swagger.models.properties.MapProperty; import io.swagger.models.properties.Property; +import io.swagger.util.Json; -public abstract class AbstractEiffelCogegen extends DefaultCodegen implements CodegenConfig { +public abstract class AbstractEiffelCodegen extends DefaultCodegen implements CodegenConfig { private final Set parentModels = new HashSet<>(); private final Multimap childrenByParent = ArrayListMultimap.create(); - - public AbstractEiffelCogegen(){ + + public AbstractEiffelCodegen(){ super(); setReservedWordsLowerCase(Arrays.asList( // language reserved words @@ -384,32 +385,34 @@ public abstract class AbstractEiffelCogegen extends DefaultCodegen implements Co @Override public Map postProcessModels(Map objs) { // remove model imports to avoid error - List> imports = (List>) objs.get("imports"); - final String prefix = modelPackage(); - Iterator> iterator = imports.iterator(); - while (iterator.hasNext()) { - String _import = iterator.next().get("import"); - if (_import.startsWith(prefix)) - iterator.remove(); - } - - // recursively add import for mapping one type to multiple imports - List> recursiveImports = (List>) objs.get("imports"); - if (recursiveImports == null) - return objs; - - ListIterator> listIterator = imports.listIterator(); - while (listIterator.hasNext()) { - String _import = listIterator.next().get("import"); - // if the import package happens to be found in the importMapping - // (key) - // add the corresponding import package to the list - if (importMapping.containsKey(_import)) { - listIterator.add(createMapping("import", importMapping.get(_import))); - } - } - - return objs; +// List> imports = (List>) objs.get("imports"); +// final String prefix = modelPackage(); +// Iterator> iterator = imports.iterator(); +// while (iterator.hasNext()) { +// String _import = iterator.next().get("import"); +// if (_import.startsWith(prefix)) +// iterator.remove(); +// } +// +// // recursively add import for mapping one type to multiple imports +// List> recursiveImports = (List>) objs.get("imports"); +// if (recursiveImports == null) +// return objs; +// +// ListIterator> listIterator = imports.listIterator(); +// while (listIterator.hasNext()) { +// String _import = listIterator.next().get("import"); +// // if the import package happens to be found in the importMapping +// // (key) +// // add the corresponding import package to the list +// if (importMapping.containsKey(_import)) { +// listIterator.add(createMapping("import", importMapping.get(_import))); +// } +// } +// +// return objs; + // process enum in models + return postProcessModelsEnum(objs); } @Override @@ -439,14 +442,76 @@ public abstract class AbstractEiffelCogegen extends DefaultCodegen implements Co for (final CodegenProperty childProperty : child.vars) { childPropertiesByName.put(childProperty.name, childProperty); } - for (final CodegenProperty parentProperty : parent.vars) { - final CodegenProperty duplicatedByParent = childPropertiesByName.get(parentProperty.name); - if (duplicatedByParent != null) { - duplicatedByParent.isInherited = true; + if (parent != null) { + for (final CodegenProperty parentProperty : parent.vars) { + final CodegenProperty duplicatedByParent = childPropertiesByName.get(parentProperty.name); + if (duplicatedByParent != null) { + duplicatedByParent.isInherited = true; + } } } } + + @Override + public CodegenModel fromModel(String name, Model model, Map allDefinitions) { + CodegenModel codegenModel = super.fromModel(name, model, allDefinitions); + if (allDefinitions != null && codegenModel.parentSchema != null && codegenModel.hasEnums) { + final Model parentModel = allDefinitions.get(codegenModel.parentSchema); + final CodegenModel parentCodegenModel = super.fromModel(codegenModel.parent, parentModel); + codegenModel = AbstractEiffelCodegen.reconcileInlineEnums(codegenModel, parentCodegenModel); + } + return codegenModel; + } + + private static 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) { + return codegenModel; + } + + // 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 + boolean removedChildEnum = false; + 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(); + removedChildEnum = true; + } + } + } + } + + if(removedChildEnum) { + // If we removed an entry from this model's vars, we need to ensure hasMore is updated + int count = 0, numVars = codegenProperties.size(); + for(CodegenProperty codegenProperty : codegenProperties) { + count += 1; + codegenProperty.hasMore = (count < numVars) ? true : false; + } + codegenModel.vars = codegenProperties; + } + return codegenModel; + } + + @Override protected boolean needToImport(String type) { return !defaultIncludes.contains(type) && !languageSpecificPrimitives.contains(type); @@ -501,7 +566,41 @@ public abstract class AbstractEiffelCogegen extends DefaultCodegen implements Co } else { return operationId; } - } - + + /** + * Update property for array(list) container + * @param property Codegen property + * @param innerProperty Codegen inner property of map or list + */ + @Override + protected void updatePropertyForArray(CodegenProperty property, CodegenProperty innerProperty) { + if (innerProperty == null) { + LOGGER.warn("skipping invalid array property " + Json.pretty(property)); + return; + } + property.dataFormat = innerProperty.dataFormat; + if (!languageSpecificPrimitives.contains(innerProperty.baseType)) { + property.complexType = innerProperty.baseType; + } else { + property.isPrimitiveType = true; + } + property.items = innerProperty; + // inner item is Enum + if (isPropertyInnerMostEnum(property)) { + // We use the data type instead of the Enum class. + // at the moment is not supported. + + // isEnum is set to true when the type is an enum + // or the inner type of an array/map is an enum + //property.isEnum = true; + // update datatypeWithEnum and default value for array + // e.g. List => List + //updateDataTypeWithEnumForArray(property); + // set allowable values to enum values (including array/map of enum) + //property.allowableValues = getInnerEnumAllowableValues(property); + } + + } + } diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/EiffelClientCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/EiffelClientCodegen.java index 55c15e27fe20..28d7879a0be2 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/EiffelClientCodegen.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/EiffelClientCodegen.java @@ -1,16 +1,19 @@ package io.swagger.codegen.languages; import java.io.File; +import java.util.HashMap; +import java.util.Map; import java.util.UUID; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import io.swagger.codegen.CodegenConstants; +import io.swagger.codegen.CodegenProperty; import io.swagger.codegen.CodegenType; import io.swagger.codegen.SupportingFile; -public class EiffelClientCodegen extends AbstractEiffelCogegen { +public class EiffelClientCodegen extends AbstractEiffelCodegen { static Logger LOGGER = LoggerFactory.getLogger(EiffelClientCodegen.class); protected String libraryTarget = "swagger_eiffel_client"; @@ -42,10 +45,9 @@ public class EiffelClientCodegen extends AbstractEiffelCogegen { super(); uuid = UUID.randomUUID(); uuidTest = UUID.randomUUID(); - ; outputFolder = "generated-code/Eiffel"; modelDocTemplateFiles.put("model_doc.mustache", ".md"); - modelTemplateFiles.put("model.mustache", ".e"); + modelTemplateFiles.put("model_generic.mustache", ".e"); apiTemplateFiles.put("api.mustache", ".e"); apiTestTemplateFiles.put("test/api_test.mustache", ".e"); apiDocTemplateFiles.put("api_doc.mustache", ".md"); @@ -155,6 +157,53 @@ public class EiffelClientCodegen extends AbstractEiffelCogegen { public void setPackageVersion(String packageVersion) { this.packageVersion = packageVersion; } + + @Override + public String toEnumName(CodegenProperty property) { + return sanitizeName(property.name).toUpperCase() + "_ENUM"; + } + + @Override + public String toEnumVarName(String value, String datatype) { + if (value.length() == 0) { + return "EMPTY"; + } + + // for symbol, e.g. $, # + if (getSymbolName(value) != null) { + return getSymbolName(value).toUpperCase(); + } + + // number + if ("INTEGER_32".equals(datatype) || "INTEGER_64".equals(datatype) || + "REAL_32".equals(datatype) || "REAL_64".equals(datatype)) { + String varName = "NUMBER_" + value; + varName = varName.replaceAll("-", "MINUS_"); + varName = varName.replaceAll("\\+", "PLUS_"); + varName = varName.replaceAll("\\.", "_DOT_"); + return varName; + } + + // string + String var = value.replaceAll("\\W+", "_").toLowerCase(); + if (var.matches("\\d.*")) { + return "val_" + var; + } else if (var.startsWith("_")){ + return "val" + var; + } else { + return "val_" + var; + } + } + + @Override + public String toEnumValue(String value, String datatype) { + if ("INTEGER_32".equals(datatype) || "INTEGER_64".equals(datatype) || + "REAL_32".equals(datatype) || "REAL_64".equals(datatype)) { + return value; + } else { + return "\"" + escapeText(value) + "\""; + } + } } diff --git a/modules/swagger-codegen/src/main/resources/Eiffel/api.mustache b/modules/swagger-codegen/src/main/resources/Eiffel/api.mustache index 3cae5b2c6e50..9c08b336862d 100644 --- a/modules/swagger-codegen/src/main/resources/Eiffel/api.mustache +++ b/modules/swagger-codegen/src/main/resources/Eiffel/api.mustache @@ -36,6 +36,7 @@ feature -- API Access {{#queryParams}} l_request.fill_query_params(api_client.parameter_to_tuple("{{#collectionFormat}}{{{collectionFormat}}}{{/collectionFormat}}", "{{baseName}}", {{paramName}})); {{/queryParams}} + {{#headerParams}} if attached {{paramName}} as l_{{paramName}} then l_request.add_header(l_{{paramName}}.out,"{{baseName}}"); diff --git a/modules/swagger-codegen/src/main/resources/Eiffel/api_client.mustache b/modules/swagger-codegen/src/main/resources/Eiffel/api_client.mustache index 330a0c61a2d9..9de50417eb91 100644 --- a/modules/swagger-codegen/src/main/resources/Eiffel/api_client.mustache +++ b/modules/swagger-codegen/src/main/resources/Eiffel/api_client.mustache @@ -123,7 +123,7 @@ feature -- Helper: OAuth Authentication feature -- Query Parameter Helpers - parameter_to_tuple (a_collection_format, a_name: STRING; a_value: ANY): LIST [TUPLE [name: STRING; value: STRING]] + parameter_to_tuple (a_collection_format, a_name: STRING; a_value: detachable ANY): LIST [TUPLE [name: STRING; value: STRING]] -- A list of tuples with name and valule. -- collectionFormat collection format (e.g. csv, tsv) -- name Name @@ -175,7 +175,12 @@ feature -- Query Parameter Helpers end else create {ARRAYED_LIST [TUPLE [name: STRING; value: STRING]]} Result.make (1) - Result.force ([a_name,a_value.out]) + if attached a_value then + Result.force ([a_name,a_value.out]) + else + Result.force ([a_name,""]) + end + end end diff --git a/modules/swagger-codegen/src/main/resources/Eiffel/ecf.mustache b/modules/swagger-codegen/src/main/resources/Eiffel/ecf.mustache index 53926e66537e..73341130a9c8 100644 --- a/modules/swagger-codegen/src/main/resources/Eiffel/ecf.mustache +++ b/modules/swagger-codegen/src/main/resources/Eiffel/ecf.mustache @@ -19,6 +19,7 @@ + diff --git a/modules/swagger-codegen/src/main/resources/Eiffel/model.mustache b/modules/swagger-codegen/src/main/resources/Eiffel/model.mustache index 388fc7c9cc28..64f0c64e4674 100644 --- a/modules/swagger-codegen/src/main/resources/Eiffel/model.mustache +++ b/modules/swagger-codegen/src/main/resources/Eiffel/model.mustache @@ -1,7 +1,3 @@ -{{>noteinfo}} -{{#models}} -{{#model}} - class {{classname}} inherit @@ -18,7 +14,12 @@ inherit {{#parent}} {{{parent}}} rename - out as out_{{{parentSchema}}} + out as out_{{{parentSchema}}}, + is_equal as is_equal_{{{parentSchema}}}, + copy as copy_{{{parentSchema}}} + select + is_equal_{{{parentSchema}}}, + copy_{{{parentSchema}}} end {{/parent}} @@ -103,5 +104,3 @@ feature -- Change Element {{/vars}} end end -{{/model}} -{{/models}} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/Eiffel/model_enum.mustache b/modules/swagger-codegen/src/main/resources/Eiffel/model_enum.mustache new file mode 100644 index 000000000000..7ec1a444db7d --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/Eiffel/model_enum.mustache @@ -0,0 +1,36 @@ +class {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}} + +feature -- Access + + value: detachable {{dataType}} + -- enumerated value. + note + option: stable + attribute + end + +feature -- Enum + + {{#allowableValues}} + {{#enumVars}} + {{{name}}}: {{classname}} + once + create Result + Result.set_value ({{{value}}}){{^-last}}{{/-last}}{{#-last}}{{/-last}} + end + + {{/enumVars}} + {{/allowableValues}} + +feature -- Element Change + + set_value (a_val: like value) + -- Set `value' with `a_value'. + do + value := a_val + ensure + value_set: value = a_val + end + + +end diff --git a/modules/swagger-codegen/src/main/resources/Eiffel/model_generic.mustache b/modules/swagger-codegen/src/main/resources/Eiffel/model_generic.mustache new file mode 100644 index 000000000000..1a83370f8d2e --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/Eiffel/model_generic.mustache @@ -0,0 +1,7 @@ +{{>noteinfo}} +{{#models}} +{{#model}} +{{#isEnum}}{{>model_enum}}{{/isEnum}}{{^isEnum}}{{>model}}{{/isEnum}} +{{/model}} +{{/models}} + diff --git a/modules/swagger-codegen/src/main/resources/Eiffel/test/ecf_test.mustache b/modules/swagger-codegen/src/main/resources/Eiffel/test/ecf_test.mustache index b5f9b4a82403..347dc9f63110 100644 --- a/modules/swagger-codegen/src/main/resources/Eiffel/test/ecf_test.mustache +++ b/modules/swagger-codegen/src/main/resources/Eiffel/test/ecf_test.mustache @@ -16,6 +16,8 @@ + + diff --git a/samples/client/petstore/eiffel/api_client.ecf b/samples/client/petstore/eiffel/api_client.ecf index 6864a472003b..dde6c4935043 100644 --- a/samples/client/petstore/eiffel/api_client.ecf +++ b/samples/client/petstore/eiffel/api_client.ecf @@ -1,5 +1,5 @@ - + @@ -19,6 +19,7 @@ + diff --git a/samples/client/petstore/eiffel/test/api_test.ecf b/samples/client/petstore/eiffel/test/api_test.ecf index 1b1f1b589ad7..81f8eb4f32fa 100644 --- a/samples/client/petstore/eiffel/test/api_test.ecf +++ b/samples/client/petstore/eiffel/test/api_test.ecf @@ -1,5 +1,5 @@ - + @@ -16,6 +16,8 @@ + +