This commit is contained in:
wing328 2018-01-07 19:11:40 +08:00
commit b7f4f3e058
11 changed files with 156 additions and 88 deletions

View File

@ -405,28 +405,28 @@ public class CodeGenMojo extends AbstractMojo {
// Set generation options // Set generation options
if (null != generateApis && generateApis) { if (null != generateApis && generateApis) {
System.setProperty("apis", ""); System.setProperty(CodegenConstants.APIS, "");
} else { } else {
System.clearProperty("apis"); System.clearProperty(CodegenConstants.APIS);
} }
if (null != generateModels && generateModels) { if (null != generateModels && generateModels) {
System.setProperty("models", modelsToGenerate); System.setProperty(CodegenConstants.MODELS, modelsToGenerate);
} else { } else {
System.clearProperty("models"); System.clearProperty(CodegenConstants.MODELS);
} }
if (null != generateSupportingFiles && generateSupportingFiles) { if (null != generateSupportingFiles && generateSupportingFiles) {
System.setProperty("supportingFiles", supportingFilesToGenerate); System.setProperty(CodegenConstants.SUPPORTING_FILES, supportingFilesToGenerate);
} else { } else {
System.clearProperty("supportingFiles"); System.clearProperty(CodegenConstants.SUPPORTING_FILES);
} }
System.setProperty("modelTests", generateModelTests.toString()); System.setProperty(CodegenConstants.MODEL_TESTS, generateModelTests.toString());
System.setProperty("modelDocs", generateModelDocumentation.toString()); System.setProperty(CodegenConstants.MODEL_DOCS, generateModelDocumentation.toString());
System.setProperty("apiTests", generateApiTests.toString()); System.setProperty(CodegenConstants.API_TESTS, generateApiTests.toString());
System.setProperty("apiDocs", generateApiDocumentation.toString()); System.setProperty(CodegenConstants.API_DOCS, generateApiDocumentation.toString());
System.setProperty("withXml", withXml.toString()); System.setProperty(CodegenConstants.WITH_XML, withXml.toString());
if (configOptions != null) { if (configOptions != null) {
// Retained for backwards-compataibility with configOptions -> instantiation-types // Retained for backwards-compataibility with configOptions -> instantiation-types

View File

@ -4,6 +4,8 @@ package io.swagger.codegen;
* A class for storing constants that are used throughout the project. * A class for storing constants that are used throughout the project.
*/ */
public class CodegenConstants { 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 APIS = "apis";
public static final String MODELS = "models"; public static final String MODELS = "models";
public static final String SUPPORTING_FILES = "supportingFiles"; 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 MODEL_DOCS = "modelDocs";
public static final String API_TESTS = "apiTests"; public static final String API_TESTS = "apiTests";
public static final String API_DOCS = "apiDocs"; 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 = "apiPackage";
public static final String API_PACKAGE_DESC = "package for generated api classes"; public static final String API_PACKAGE_DESC = "package for generated api classes";

View File

@ -1930,6 +1930,8 @@ public class DefaultCodegen {
if (property.defaultValue != null) { if (property.defaultValue != null) {
property.defaultValue = property.defaultValue.replace(baseItem.baseType, toEnumName(baseItem)); property.defaultValue = property.defaultValue.replace(baseItem.baseType, toEnumName(baseItem));
} }
updateCodegenPropertyEnum(property);
} }
} }

View File

@ -551,7 +551,7 @@ public class DefaultGenerator extends AbstractGenerator implements Generator {
return; return;
} }
Set<String> supportingFilesToGenerate = null; Set<String> supportingFilesToGenerate = null;
String supportingFiles = System.getProperty("supportingFiles"); String supportingFiles = System.getProperty(CodegenConstants.SUPPORTING_FILES);
if (supportingFiles != null && !supportingFiles.isEmpty()) { if (supportingFiles != null && !supportingFiles.isEmpty()) {
supportingFilesToGenerate = new HashSet<String>(Arrays.asList(supportingFiles.split(","))); supportingFilesToGenerate = new HashSet<String>(Arrays.asList(supportingFiles.split(",")));
} }

View File

@ -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. * those vars referencing RefModel'd enums to work the same as inlined enums rather than as objects.
* @param models * @param models
*/ */
@SuppressWarnings({ "unchecked" })
private void postProcessEnumRefs(final Map<String, Object> models) { private void postProcessEnumRefs(final Map<String, Object> models) {
Map<String, CodegenModel> enumRefs = new HashMap<String, CodegenModel>(); Map<String, CodegenModel> enumRefs = new HashMap<String, CodegenModel>();
for (Map.Entry<String, Object> entry : models.entrySet()) { for (Map.Entry<String, Object> entry : models.entrySet()) {
@ -372,11 +373,57 @@ public abstract class AbstractCSharpCodegen extends DefaultCodegen implements Co
// while enums in many other languages are true objects. // while enums in many other languages are true objects.
CodegenModel refModel = enumRefs.get(var.datatype); CodegenModel refModel = enumRefs.get(var.datatype);
var.allowableValues = refModel.allowableValues; var.allowableValues = refModel.allowableValues;
var.isEnum = true;
updateCodegenPropertyEnum(var); updateCodegenPropertyEnum(var);
// We do these after updateCodegenPropertyEnum to avoid generalities that don't mesh with C#. // We do these after updateCodegenPropertyEnum to avoid generalities that don't mesh with C#.
var.isPrimitiveType = true; 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<Map<String, String>> enumVars = (ArrayList<Map<String, String>>)model.allowableValues.get("enumVars");
List<Map<String, Object>> newEnumVars = new ArrayList<Map<String, Object>>();
for (Map<String, String> enumVar : enumVars) {
Map<String, Object> mixedVars = new HashMap<String, Object>();
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 { } 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 @Override
public Map<String, Object> postProcessOperations(Map<String, Object> objs) { public Map<String, Object> postProcessOperations(Map<String, Object> objs) {
super.postProcessOperations(objs); super.postProcessOperations(objs);
@ -769,6 +852,19 @@ public abstract class AbstractCSharpCodegen extends DefaultCodegen implements Co
this.interfacePrefix = interfacePrefix; 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 @Override
public String toEnumVarName(String name, String datatype) { public String toEnumVarName(String name, String datatype) {
if (name.length() == 0) { if (name.length() == 0) {
@ -799,32 +895,6 @@ public abstract class AbstractCSharpCodegen extends DefaultCodegen implements Co
return sanitizeName(camelize(property.name)) + "Enum"; 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() { public String testPackageName() {
return this.packageName + ".Test"; return this.packageName + ".Test";
} }
@ -839,5 +909,4 @@ public abstract class AbstractCSharpCodegen extends DefaultCodegen implements Co
public String escapeUnsafeCharacters(String input) { public String escapeUnsafeCharacters(String input) {
return input.replace("*/", "*_/").replace("/*", "/_*").replace("--", "- -"); return input.replace("*/", "*_/").replace("/*", "/_*").replace("--", "- -");
} }
} }

View File

@ -671,19 +671,6 @@ public class CSharpClientCodegen extends AbstractCSharpCodegen {
return codegenModel; 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 @Override
public String toEnumVarName(String value, String datatype) { public String toEnumVarName(String value, String datatype) {
if (value.length() == 0) { if (value.length() == 0) {
@ -696,8 +683,8 @@ public class CSharpClientCodegen extends AbstractCSharpCodegen {
} }
// number // number
if ("int?".equals(datatype) || "long?".equals(datatype) || if(datatype.startsWith("int") || datatype.startsWith("long") ||
"double?".equals(datatype) || "float?".equals(datatype)) { datatype.startsWith("double") || datatype.startsWith("float")) {
String varName = "NUMBER_" + value; String varName = "NUMBER_" + value;
varName = varName.replaceAll("-", "MINUS_"); varName = varName.replaceAll("-", "MINUS_");
varName = varName.replaceAll("\\+", "PLUS_"); varName = varName.replaceAll("\\+", "PLUS_");

View File

@ -4,14 +4,16 @@
{{#description}} {{#description}}
/// <value>{{description}}</value> /// <value>{{description}}</value>
{{/description}} {{/description}}
{{#allowableValues}}{{#enumVars}}{{#-first}}{{#isString}}
[JsonConverter(typeof(StringEnumConverter))] [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}} {{#allowableValues}}{{#enumVars}}
/// <summary> /// <summary>
/// Enum {{name}} for {{{value}}} /// Enum {{name}} for value: {{{value}}}
/// </summary> /// </summary>
[EnumMember(Value = {{#isInteger}}"{{/isInteger}}{{#isDouble}}"{{/isDouble}}{{{value}}}{{#isInteger}}"{{/isInteger}}{{#isDouble}}"{{/isDouble}})] {{#isString}}[EnumMember(Value = "{{{value}}}")]{{/isString}}
{{name}}{{#isInteger}} = {{{value}}}{{/isInteger}}{{^isInteger}} = {{-index}}{{/isInteger}}{{^-last}}, {{name}}{{^isString}} = {{{value}}}{{/isString}}{{#isString}} = {{-index}}{{/isString}}{{^-last}},
{{/-last}}{{/enumVars}}{{/allowableValues}} {{/-last}}{{/enumVars}}{{/allowableValues}}
} }{{! NOTE: This model's enumVars is modified to look like CodegenProperty}}

View File

@ -1,19 +1,21 @@
{{^isContainer}} {{^isContainer}}
/// <summary> /// <summary>
/// {{^description}}Gets or Sets {{{name}}}{{/description}}{{#description}}{{description}}{{/description}} /// {{^description}}Defines {{{name}}}{{/description}}{{#description}}{{description}}{{/description}}
/// </summary> /// </summary>
{{#description}} {{#description}}
/// <value>{{description}}</value> /// <value>{{description}}</value>
{{/description}} {{/description}}
{{#isString}}
[JsonConverter(typeof(StringEnumConverter))] [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}} {{#allowableValues}}{{#enumVars}}
/// <summary> /// <summary>
/// Enum {{name}} for {{{value}}} /// Enum {{name}} for value: {{{value}}}
/// </summary> /// </summary>
[EnumMember(Value = {{#isLong}}"{{/isLong}}{{#isInteger}}"{{/isInteger}}{{#isFloat}}"{{/isFloat}}{{#isDouble}}"{{/isDouble}}{{{value}}}{{#isLong}}"{{/isLong}}{{#isInteger}}"{{/isInteger}}{{#isDouble}}"{{/isDouble}}{{#isFloat}}"{{/isFloat}})] {{#isString}}[EnumMember(Value = "{{{value}}}")]{{/isString}}
{{name}}{{#isLong}} = {{{value}}}{{/isLong}}{{#isInteger}} = {{{value}}}{{/isInteger}}{{^isInteger}} = {{-index}}{{/isInteger}}{{^-last}}, {{name}}{{^isString}} = {{{value}}}{{/isString}}{{#isString}} = {{-index}}{{/isString}}{{^-last}},
{{/-last}}{{/enumVars}}{{/allowableValues}} {{/-last}}{{/enumVars}}{{/allowableValues}}
} }
{{/isContainer}} {{/isContainer}}

View File

@ -31,50 +31,50 @@ namespace IO.Swagger.Model
public partial class MyClassWithOptionalInlineEnum : IEquatable<MyClassWithOptionalInlineEnum>, IValidatableObject public partial class MyClassWithOptionalInlineEnum : IEquatable<MyClassWithOptionalInlineEnum>, IValidatableObject
{ {
/// <summary> /// <summary>
/// Gets or Sets Days /// Defines Days
/// </summary> /// </summary>
[JsonConverter(typeof(StringEnumConverter))] [JsonConverter(typeof(StringEnumConverter))]
public enum DaysEnum public enum DaysEnum
{ {
/// <summary> /// <summary>
/// Enum Sun for "sun" /// Enum Sun for value: sun
/// </summary> /// </summary>
[EnumMember(Value = "sun")] [EnumMember(Value = "sun")]
Sun = 1, Sun = 1,
/// <summary> /// <summary>
/// Enum Mon for "mon" /// Enum Mon for value: mon
/// </summary> /// </summary>
[EnumMember(Value = "mon")] [EnumMember(Value = "mon")]
Mon = 2, Mon = 2,
/// <summary> /// <summary>
/// Enum Tue for "tue" /// Enum Tue for value: tue
/// </summary> /// </summary>
[EnumMember(Value = "tue")] [EnumMember(Value = "tue")]
Tue = 3, Tue = 3,
/// <summary> /// <summary>
/// Enum Wed for "wed" /// Enum Wed for value: wed
/// </summary> /// </summary>
[EnumMember(Value = "wed")] [EnumMember(Value = "wed")]
Wed = 4, Wed = 4,
/// <summary> /// <summary>
/// Enum Thu for "thu" /// Enum Thu for value: thu
/// </summary> /// </summary>
[EnumMember(Value = "thu")] [EnumMember(Value = "thu")]
Thu = 5, Thu = 5,
/// <summary> /// <summary>
/// Enum Fri for "fri" /// Enum Fri for value: fri
/// </summary> /// </summary>
[EnumMember(Value = "fri")] [EnumMember(Value = "fri")]
Fri = 6, Fri = 6,
/// <summary> /// <summary>
/// Enum Sat for "sat" /// Enum Sat for value: sat
/// </summary> /// </summary>
[EnumMember(Value = "sat")] [EnumMember(Value = "sat")]
Sat = 7 Sat = 7

View File

@ -31,50 +31,50 @@ namespace IO.Swagger.Model
public partial class MyClassWithRequiredInlineEnum : IEquatable<MyClassWithRequiredInlineEnum>, IValidatableObject public partial class MyClassWithRequiredInlineEnum : IEquatable<MyClassWithRequiredInlineEnum>, IValidatableObject
{ {
/// <summary> /// <summary>
/// Gets or Sets Days /// Defines Days
/// </summary> /// </summary>
[JsonConverter(typeof(StringEnumConverter))] [JsonConverter(typeof(StringEnumConverter))]
public enum DaysEnum public enum DaysEnum
{ {
/// <summary> /// <summary>
/// Enum Sun for "sun" /// Enum Sun for value: sun
/// </summary> /// </summary>
[EnumMember(Value = "sun")] [EnumMember(Value = "sun")]
Sun = 1, Sun = 1,
/// <summary> /// <summary>
/// Enum Mon for "mon" /// Enum Mon for value: mon
/// </summary> /// </summary>
[EnumMember(Value = "mon")] [EnumMember(Value = "mon")]
Mon = 2, Mon = 2,
/// <summary> /// <summary>
/// Enum Tue for "tue" /// Enum Tue for value: tue
/// </summary> /// </summary>
[EnumMember(Value = "tue")] [EnumMember(Value = "tue")]
Tue = 3, Tue = 3,
/// <summary> /// <summary>
/// Enum Wed for "wed" /// Enum Wed for value: wed
/// </summary> /// </summary>
[EnumMember(Value = "wed")] [EnumMember(Value = "wed")]
Wed = 4, Wed = 4,
/// <summary> /// <summary>
/// Enum Thu for "thu" /// Enum Thu for value: thu
/// </summary> /// </summary>
[EnumMember(Value = "thu")] [EnumMember(Value = "thu")]
Thu = 5, Thu = 5,
/// <summary> /// <summary>
/// Enum Fri for "fri" /// Enum Fri for value: fri
/// </summary> /// </summary>
[EnumMember(Value = "fri")] [EnumMember(Value = "fri")]
Fri = 6, Fri = 6,
/// <summary> /// <summary>
/// Enum Sat for "sat" /// Enum Sat for value: sat
/// </summary> /// </summary>
[EnumMember(Value = "sat")] [EnumMember(Value = "sat")]
Sat = 7 Sat = 7

View File

@ -27,48 +27,50 @@ namespace IO.Swagger.Model
/// <summary> /// <summary>
/// Defines WeekDays /// Defines WeekDays
/// </summary> /// </summary>
[JsonConverter(typeof(StringEnumConverter))] [JsonConverter(typeof(StringEnumConverter))]
public enum WeekDays public enum WeekDays
{ {
/// <summary> /// <summary>
/// Enum Sun for "sun" /// Enum Sun for value: sun
/// </summary> /// </summary>
[EnumMember(Value = "sun")] [EnumMember(Value = "sun")]
Sun = 1, Sun = 1,
/// <summary> /// <summary>
/// Enum Mon for "mon" /// Enum Mon for value: mon
/// </summary> /// </summary>
[EnumMember(Value = "mon")] [EnumMember(Value = "mon")]
Mon = 2, Mon = 2,
/// <summary> /// <summary>
/// Enum Tue for "tue" /// Enum Tue for value: tue
/// </summary> /// </summary>
[EnumMember(Value = "tue")] [EnumMember(Value = "tue")]
Tue = 3, Tue = 3,
/// <summary> /// <summary>
/// Enum Wed for "wed" /// Enum Wed for value: wed
/// </summary> /// </summary>
[EnumMember(Value = "wed")] [EnumMember(Value = "wed")]
Wed = 4, Wed = 4,
/// <summary> /// <summary>
/// Enum Thu for "thu" /// Enum Thu for value: thu
/// </summary> /// </summary>
[EnumMember(Value = "thu")] [EnumMember(Value = "thu")]
Thu = 5, Thu = 5,
/// <summary> /// <summary>
/// Enum Fri for "fri" /// Enum Fri for value: fri
/// </summary> /// </summary>
[EnumMember(Value = "fri")] [EnumMember(Value = "fri")]
Fri = 6, Fri = 6,
/// <summary> /// <summary>
/// Enum Sat for "sat" /// Enum Sat for value: sat
/// </summary> /// </summary>
[EnumMember(Value = "sat")] [EnumMember(Value = "sat")]
Sat = 7 Sat = 7