diff --git a/modules/swagger-codegen-maven-plugin/src/main/java/io/swagger/codegen/plugin/CodeGenMojo.java b/modules/swagger-codegen-maven-plugin/src/main/java/io/swagger/codegen/plugin/CodeGenMojo.java index a73ed6aa0c0..58fbeda5943 100644 --- a/modules/swagger-codegen-maven-plugin/src/main/java/io/swagger/codegen/plugin/CodeGenMojo.java +++ b/modules/swagger-codegen-maven-plugin/src/main/java/io/swagger/codegen/plugin/CodeGenMojo.java @@ -405,28 +405,28 @@ public class CodeGenMojo extends AbstractMojo { // Set generation options if (null != generateApis && generateApis) { - System.setProperty("apis", ""); + System.setProperty(CodegenConstants.APIS, ""); } else { - System.clearProperty("apis"); + System.clearProperty(CodegenConstants.APIS); } if (null != generateModels && generateModels) { - System.setProperty("models", modelsToGenerate); + System.setProperty(CodegenConstants.MODELS, modelsToGenerate); } else { - System.clearProperty("models"); + System.clearProperty(CodegenConstants.MODELS); } if (null != generateSupportingFiles && generateSupportingFiles) { - System.setProperty("supportingFiles", supportingFilesToGenerate); + System.setProperty(CodegenConstants.SUPPORTING_FILES, supportingFilesToGenerate); } else { - System.clearProperty("supportingFiles"); + System.clearProperty(CodegenConstants.SUPPORTING_FILES); } - System.setProperty("modelTests", generateModelTests.toString()); - System.setProperty("modelDocs", generateModelDocumentation.toString()); - System.setProperty("apiTests", generateApiTests.toString()); - System.setProperty("apiDocs", generateApiDocumentation.toString()); - System.setProperty("withXml", withXml.toString()); + System.setProperty(CodegenConstants.MODEL_TESTS, generateModelTests.toString()); + System.setProperty(CodegenConstants.MODEL_DOCS, generateModelDocumentation.toString()); + System.setProperty(CodegenConstants.API_TESTS, generateApiTests.toString()); + System.setProperty(CodegenConstants.API_DOCS, generateApiDocumentation.toString()); + System.setProperty(CodegenConstants.WITH_XML, withXml.toString()); if (configOptions != null) { // Retained for backwards-compataibility with configOptions -> instantiation-types diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenConstants.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenConstants.java index 379102f417a..c8e957f4aae 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenConstants.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenConstants.java @@ -4,6 +4,8 @@ package io.swagger.codegen; * A class for storing constants that are used throughout the project. */ public class CodegenConstants { + /* System Properties */ + // NOTE: We may want to move these to a separate class to avoid confusion or modification. public static final String APIS = "apis"; public static final String MODELS = "models"; public static final String SUPPORTING_FILES = "supportingFiles"; @@ -11,6 +13,8 @@ public class CodegenConstants { public static final String MODEL_DOCS = "modelDocs"; public static final String API_TESTS = "apiTests"; public static final String API_DOCS = "apiDocs"; + public static final String WITH_XML = "withXml"; + /* /end System Properties */ public static final String API_PACKAGE = "apiPackage"; public static final String API_PACKAGE_DESC = "package for generated api classes"; diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/DefaultCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/DefaultCodegen.java index 2593f85c3ba..605e33c2112 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/DefaultCodegen.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/DefaultCodegen.java @@ -1930,6 +1930,8 @@ public class DefaultCodegen { if (property.defaultValue != null) { property.defaultValue = property.defaultValue.replace(baseItem.baseType, toEnumName(baseItem)); } + + updateCodegenPropertyEnum(property); } } diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/DefaultGenerator.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/DefaultGenerator.java index bba4e9f0511..839af675fe1 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/DefaultGenerator.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/DefaultGenerator.java @@ -551,7 +551,7 @@ public class DefaultGenerator extends AbstractGenerator implements Generator { return; } Set supportingFilesToGenerate = null; - String supportingFiles = System.getProperty("supportingFiles"); + String supportingFiles = System.getProperty(CodegenConstants.SUPPORTING_FILES); if (supportingFiles != null && !supportingFiles.isEmpty()) { supportingFilesToGenerate = new HashSet(Arrays.asList(supportingFiles.split(","))); } diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/AbstractCSharpCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/AbstractCSharpCodegen.java index 50e278e714e..1a288e7c2ea 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/AbstractCSharpCodegen.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/AbstractCSharpCodegen.java @@ -352,6 +352,7 @@ public abstract class AbstractCSharpCodegen extends DefaultCodegen implements Co * those vars referencing RefModel'd enums to work the same as inlined enums rather than as objects. * @param models */ + @SuppressWarnings({ "unchecked" }) private void postProcessEnumRefs(final Map models) { Map enumRefs = new HashMap(); for (Map.Entry entry : models.entrySet()) { @@ -372,11 +373,57 @@ public abstract class AbstractCSharpCodegen extends DefaultCodegen implements Co // while enums in many other languages are true objects. CodegenModel refModel = enumRefs.get(var.datatype); var.allowableValues = refModel.allowableValues; + var.isEnum = true; + updateCodegenPropertyEnum(var); // We do these after updateCodegenPropertyEnum to avoid generalities that don't mesh with C#. var.isPrimitiveType = true; - var.isEnum = true; + } + } + + // We're looping all models here. + if (model.isEnum) { + // We now need to make allowableValues.enumVars look like the context of CodegenProperty + Boolean isString = false; + Boolean isInteger = false; + Boolean isLong = false; + Boolean isByte = false; + + if (model.dataType.startsWith("byte")) { + // C# Actually supports byte and short enums, swagger spec only supports byte. + isByte = true; + model.vendorExtensions.put("x-enum-byte", true); + } else if (model.dataType.startsWith("int32")) { + isInteger = true; + model.vendorExtensions.put("x-enum-integer", true); + } else if (model.dataType.startsWith("int64")) { + isLong = true; + model.vendorExtensions.put("x-enum-long", true); + } else { + // C# doesn't support non-integral enums, so we need to treat everything else as strings (e.g. to not lose precision or data integrity) + isString = true; + model.vendorExtensions.put("x-enum-string", true); + } + + // Since we iterate enumVars for modelnnerEnum and enumClass templates, and CodegenModel is missing some of CodegenProperty's properties, + // we can take advantage of Mustache's contextual lookup to add the same "properties" to the model's enumVars scope rather than CodegenProperty's scope. + List> enumVars = (ArrayList>)model.allowableValues.get("enumVars"); + List> newEnumVars = new ArrayList>(); + for (Map enumVar : enumVars) { + Map mixedVars = new HashMap(); + mixedVars.putAll(enumVar); + + mixedVars.put("isString", isString); + mixedVars.put("isLong", isLong); + mixedVars.put("isInteger", isInteger); + mixedVars.put("isByte", isByte); + + newEnumVars.add(mixedVars); + } + + if (!newEnumVars.isEmpty()) { + model.allowableValues.put("enumVars", newEnumVars); } } } else { @@ -385,6 +432,42 @@ public abstract class AbstractCSharpCodegen extends DefaultCodegen implements Co } } + /** + * Update codegen property's enum by adding "enumVars" (with name and value) + * + * @param var list of CodegenProperty + */ + @Override + public void updateCodegenPropertyEnum(CodegenProperty var) { + if (var.vendorExtensions == null) { + var.vendorExtensions = new HashMap<>(); + } + + super.updateCodegenPropertyEnum(var); + + // Because C# uses nullable primitives for datatype, and datatype is used in DefaultCodegen for determining enum-ness, guard against weirdness here. + if (var.isEnum) { + if ("byte".equals(var.dataFormat)) {// C# Actually supports byte and short enums. + var.vendorExtensions.put("x-enum-byte", true); + var.isString = false; + var.isLong = false; + var.isInteger = false; + } else if ("int32".equals(var.dataFormat)) { + var.isInteger = true; + var.isString = false; + var.isLong = false; + } else if ("int64".equals(var.dataFormat)) { + var.isLong = true; + var.isString = false; + var.isInteger = false; + } else {// C# doesn't support non-integral enums, so we need to treat everything else as strings (e.g. to not lose precision or data integrity) + var.isString = true; + var.isInteger = false; + var.isLong = false; + } + } + } + @Override public Map postProcessOperations(Map objs) { super.postProcessOperations(objs); @@ -769,6 +852,19 @@ public abstract class AbstractCSharpCodegen extends DefaultCodegen implements Co this.interfacePrefix = interfacePrefix; } + @Override + public String toEnumValue(String value, String datatype) { + // C# only supports enums as literals for int, int?, long, long?, byte, and byte?. All else must be treated as strings. + // Per: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/enum + // The approved types for an enum are byte, sbyte, short, ushort, int, uint, long, or ulong. + // but we're not supporting unsigned integral types or shorts. + if(datatype.startsWith("int") || datatype.startsWith("long") || datatype.startsWith("byte")) { + return value; + } + + return escapeText(value); + } + @Override public String toEnumVarName(String name, String datatype) { if (name.length() == 0) { @@ -799,32 +895,6 @@ public abstract class AbstractCSharpCodegen extends DefaultCodegen implements Co return sanitizeName(camelize(property.name)) + "Enum"; } - /* - @Override - public String toEnumName(CodegenProperty property) { - String enumName = sanitizeName(property.name); - if (!StringUtils.isEmpty(modelNamePrefix)) { - enumName = modelNamePrefix + "_" + enumName; - } - - if (!StringUtils.isEmpty(modelNameSuffix)) { - enumName = enumName + "_" + modelNameSuffix; - } - - // model name cannot use reserved keyword, e.g. return - if (isReservedWord(enumName)) { - LOGGER.warn(enumName + " (reserved word) cannot be used as model name. Renamed to " + camelize("model_" + enumName)); - enumName = "model_" + enumName; // e.g. return => ModelReturn (after camelize) - } - - if (enumName.matches("\\d.*")) { // starts with number - return "_" + enumName; - } else { - return enumName; - } - } - */ - public String testPackageName() { return this.packageName + ".Test"; } @@ -839,5 +909,4 @@ public abstract class AbstractCSharpCodegen extends DefaultCodegen implements Co public String escapeUnsafeCharacters(String input) { return input.replace("*/", "*_/").replace("/*", "/_*").replace("--", "- -"); } - } diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/CSharpClientCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/CSharpClientCodegen.java index ec212afeb5b..ab42bbaf80c 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/CSharpClientCodegen.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/CSharpClientCodegen.java @@ -671,19 +671,6 @@ public class CSharpClientCodegen extends AbstractCSharpCodegen { return codegenModel; } - @Override - public String toEnumValue(String value, String datatype) { - if ("int?".equalsIgnoreCase(datatype) || "long?".equalsIgnoreCase(datatype) || - "double?".equalsIgnoreCase(datatype) || "float?".equalsIgnoreCase(datatype)) { - return value; - } else if ("float?".equalsIgnoreCase(datatype)) { - // for float in C#, append "f". e.g. 3.14 => 3.14f - return value + "f"; - } else { - return "\"" + escapeText(value) + "\""; - } - } - @Override public String toEnumVarName(String value, String datatype) { if (value.length() == 0) { @@ -696,8 +683,8 @@ public class CSharpClientCodegen extends AbstractCSharpCodegen { } // number - if ("int?".equals(datatype) || "long?".equals(datatype) || - "double?".equals(datatype) || "float?".equals(datatype)) { + if(datatype.startsWith("int") || datatype.startsWith("long") || + datatype.startsWith("double") || datatype.startsWith("float")) { String varName = "NUMBER_" + value; varName = varName.replaceAll("-", "MINUS_"); varName = varName.replaceAll("\\+", "PLUS_"); diff --git a/modules/swagger-codegen/src/main/resources/csharp/modelEnum.mustache b/modules/swagger-codegen/src/main/resources/csharp/modelEnum.mustache index 23f575bb06f..a7cf4473385 100644 --- a/modules/swagger-codegen/src/main/resources/csharp/modelEnum.mustache +++ b/modules/swagger-codegen/src/main/resources/csharp/modelEnum.mustache @@ -4,14 +4,16 @@ {{#description}} /// {{description}} {{/description}} + {{#allowableValues}}{{#enumVars}}{{#-first}}{{#isString}} [JsonConverter(typeof(StringEnumConverter))] - {{>visibility}} enum {{#datatypeWithEnum}}{{.}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}} + {{/isString}}{{/-first}}{{/enumVars}}{{/allowableValues}} + {{>visibility}} enum {{#datatypeWithEnum}}{{.}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}}{{#vendorExtensions.x-enum-byte}}: byte{{/vendorExtensions.x-enum-byte}} { {{#allowableValues}}{{#enumVars}} /// - /// Enum {{name}} for {{{value}}} + /// Enum {{name}} for value: {{{value}}} /// - [EnumMember(Value = {{#isInteger}}"{{/isInteger}}{{#isDouble}}"{{/isDouble}}{{{value}}}{{#isInteger}}"{{/isInteger}}{{#isDouble}}"{{/isDouble}})] - {{name}}{{#isInteger}} = {{{value}}}{{/isInteger}}{{^isInteger}} = {{-index}}{{/isInteger}}{{^-last}}, + {{#isString}}[EnumMember(Value = "{{{value}}}")]{{/isString}} + {{name}}{{^isString}} = {{{value}}}{{/isString}}{{#isString}} = {{-index}}{{/isString}}{{^-last}}, {{/-last}}{{/enumVars}}{{/allowableValues}} - } + }{{! NOTE: This model's enumVars is modified to look like CodegenProperty}} diff --git a/modules/swagger-codegen/src/main/resources/csharp/modelInnerEnum.mustache b/modules/swagger-codegen/src/main/resources/csharp/modelInnerEnum.mustache index 674ab033d01..bede8a16b5e 100644 --- a/modules/swagger-codegen/src/main/resources/csharp/modelInnerEnum.mustache +++ b/modules/swagger-codegen/src/main/resources/csharp/modelInnerEnum.mustache @@ -1,19 +1,21 @@ {{^isContainer}} /// - /// {{^description}}Gets or Sets {{{name}}}{{/description}}{{#description}}{{description}}{{/description}} + /// {{^description}}Defines {{{name}}}{{/description}}{{#description}}{{description}}{{/description}} /// {{#description}} /// {{description}} {{/description}} + {{#isString}} [JsonConverter(typeof(StringEnumConverter))] - {{>visibility}} enum {{#datatypeWithEnum}}{{&.}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}} + {{/isString}} + {{>visibility}} enum {{#datatypeWithEnum}}{{.}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}}{{#vendorExtensions.x-enum-byte}}: byte{{/vendorExtensions.x-enum-byte}} { {{#allowableValues}}{{#enumVars}} /// - /// Enum {{name}} for {{{value}}} + /// Enum {{name}} for value: {{{value}}} /// - [EnumMember(Value = {{#isLong}}"{{/isLong}}{{#isInteger}}"{{/isInteger}}{{#isFloat}}"{{/isFloat}}{{#isDouble}}"{{/isDouble}}{{{value}}}{{#isLong}}"{{/isLong}}{{#isInteger}}"{{/isInteger}}{{#isDouble}}"{{/isDouble}}{{#isFloat}}"{{/isFloat}})] - {{name}}{{#isLong}} = {{{value}}}{{/isLong}}{{#isInteger}} = {{{value}}}{{/isInteger}}{{^isInteger}} = {{-index}}{{/isInteger}}{{^-last}}, + {{#isString}}[EnumMember(Value = "{{{value}}}")]{{/isString}} + {{name}}{{^isString}} = {{{value}}}{{/isString}}{{#isString}} = {{-index}}{{/isString}}{{^-last}}, {{/-last}}{{/enumVars}}{{/allowableValues}} } {{/isContainer}} diff --git a/modules/swagger-codegen/src/test/resources/integrationtests/csharp/general/enum-support-expected/src/IO.Swagger/Model/MyClassWithOptionalInlineEnum.cs b/modules/swagger-codegen/src/test/resources/integrationtests/csharp/general/enum-support-expected/src/IO.Swagger/Model/MyClassWithOptionalInlineEnum.cs index f0232199d26..1acd88ef379 100644 --- a/modules/swagger-codegen/src/test/resources/integrationtests/csharp/general/enum-support-expected/src/IO.Swagger/Model/MyClassWithOptionalInlineEnum.cs +++ b/modules/swagger-codegen/src/test/resources/integrationtests/csharp/general/enum-support-expected/src/IO.Swagger/Model/MyClassWithOptionalInlineEnum.cs @@ -31,50 +31,50 @@ namespace IO.Swagger.Model public partial class MyClassWithOptionalInlineEnum : IEquatable, IValidatableObject { /// - /// Gets or Sets Days + /// Defines Days /// [JsonConverter(typeof(StringEnumConverter))] public enum DaysEnum { /// - /// Enum Sun for "sun" + /// Enum Sun for value: sun /// [EnumMember(Value = "sun")] Sun = 1, /// - /// Enum Mon for "mon" + /// Enum Mon for value: mon /// [EnumMember(Value = "mon")] Mon = 2, /// - /// Enum Tue for "tue" + /// Enum Tue for value: tue /// [EnumMember(Value = "tue")] Tue = 3, /// - /// Enum Wed for "wed" + /// Enum Wed for value: wed /// [EnumMember(Value = "wed")] Wed = 4, /// - /// Enum Thu for "thu" + /// Enum Thu for value: thu /// [EnumMember(Value = "thu")] Thu = 5, /// - /// Enum Fri for "fri" + /// Enum Fri for value: fri /// [EnumMember(Value = "fri")] Fri = 6, /// - /// Enum Sat for "sat" + /// Enum Sat for value: sat /// [EnumMember(Value = "sat")] Sat = 7 diff --git a/modules/swagger-codegen/src/test/resources/integrationtests/csharp/general/enum-support-expected/src/IO.Swagger/Model/MyClassWithRequiredInlineEnum.cs b/modules/swagger-codegen/src/test/resources/integrationtests/csharp/general/enum-support-expected/src/IO.Swagger/Model/MyClassWithRequiredInlineEnum.cs index 1d461a4e558..ac6c2009b41 100644 --- a/modules/swagger-codegen/src/test/resources/integrationtests/csharp/general/enum-support-expected/src/IO.Swagger/Model/MyClassWithRequiredInlineEnum.cs +++ b/modules/swagger-codegen/src/test/resources/integrationtests/csharp/general/enum-support-expected/src/IO.Swagger/Model/MyClassWithRequiredInlineEnum.cs @@ -31,50 +31,50 @@ namespace IO.Swagger.Model public partial class MyClassWithRequiredInlineEnum : IEquatable, IValidatableObject { /// - /// Gets or Sets Days + /// Defines Days /// [JsonConverter(typeof(StringEnumConverter))] public enum DaysEnum { /// - /// Enum Sun for "sun" + /// Enum Sun for value: sun /// [EnumMember(Value = "sun")] Sun = 1, /// - /// Enum Mon for "mon" + /// Enum Mon for value: mon /// [EnumMember(Value = "mon")] Mon = 2, /// - /// Enum Tue for "tue" + /// Enum Tue for value: tue /// [EnumMember(Value = "tue")] Tue = 3, /// - /// Enum Wed for "wed" + /// Enum Wed for value: wed /// [EnumMember(Value = "wed")] Wed = 4, /// - /// Enum Thu for "thu" + /// Enum Thu for value: thu /// [EnumMember(Value = "thu")] Thu = 5, /// - /// Enum Fri for "fri" + /// Enum Fri for value: fri /// [EnumMember(Value = "fri")] Fri = 6, /// - /// Enum Sat for "sat" + /// Enum Sat for value: sat /// [EnumMember(Value = "sat")] Sat = 7 diff --git a/modules/swagger-codegen/src/test/resources/integrationtests/csharp/general/enum-support-expected/src/IO.Swagger/Model/WeekDays.cs b/modules/swagger-codegen/src/test/resources/integrationtests/csharp/general/enum-support-expected/src/IO.Swagger/Model/WeekDays.cs index e51a01de8fa..5c449b6cc0e 100644 --- a/modules/swagger-codegen/src/test/resources/integrationtests/csharp/general/enum-support-expected/src/IO.Swagger/Model/WeekDays.cs +++ b/modules/swagger-codegen/src/test/resources/integrationtests/csharp/general/enum-support-expected/src/IO.Swagger/Model/WeekDays.cs @@ -27,48 +27,50 @@ namespace IO.Swagger.Model /// /// Defines WeekDays /// + [JsonConverter(typeof(StringEnumConverter))] + public enum WeekDays { /// - /// Enum Sun for "sun" + /// Enum Sun for value: sun /// [EnumMember(Value = "sun")] Sun = 1, /// - /// Enum Mon for "mon" + /// Enum Mon for value: mon /// [EnumMember(Value = "mon")] Mon = 2, /// - /// Enum Tue for "tue" + /// Enum Tue for value: tue /// [EnumMember(Value = "tue")] Tue = 3, /// - /// Enum Wed for "wed" + /// Enum Wed for value: wed /// [EnumMember(Value = "wed")] Wed = 4, /// - /// Enum Thu for "thu" + /// Enum Thu for value: thu /// [EnumMember(Value = "thu")] Thu = 5, /// - /// Enum Fri for "fri" + /// Enum Fri for value: fri /// [EnumMember(Value = "fri")] Fri = 6, /// - /// Enum Sat for "sat" + /// Enum Sat for value: sat /// [EnumMember(Value = "sat")] Sat = 7