Skip to content

[csharp] Clean up ref/inner enum structure #6887

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jan 7, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -405,28 +405,28 @@ public void execute() throws MojoExecutionException {

// 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@
* 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";
public static final String MODEL_TESTS = "modelTests";
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";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1930,6 +1930,8 @@ protected void updateDataTypeWithEnumForArray(CodegenProperty property) {
if (property.defaultValue != null) {
property.defaultValue = property.defaultValue.replace(baseItem.baseType, toEnumName(baseItem));
}

updateCodegenPropertyEnum(property);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,7 @@ private void generateSupportingFiles(List<File> files, Map<String, Object> bundl
return;
}
Set<String> supportingFilesToGenerate = null;
String supportingFiles = System.getProperty("supportingFiles");
String supportingFiles = System.getProperty(CodegenConstants.SUPPORTING_FILES);
if (supportingFiles != null && !supportingFiles.isEmpty()) {
supportingFilesToGenerate = new HashSet<String>(Arrays.asList(supportingFiles.split(",")));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,7 @@ public Map<String, Object> postProcessAllModels(Map<String, Object> objs) {
* 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<String, Object> models) {
Map<String, CodegenModel> enumRefs = new HashMap<String, CodegenModel>();
for (Map.Entry<String, Object> entry : models.entrySet()) {
Expand All @@ -363,11 +364,57 @@ private void postProcessEnumRefs(final Map<String, Object> models) {
// 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<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 {
Expand All @@ -376,6 +423,42 @@ private void postProcessEnumRefs(final Map<String, Object> models) {
}
}

/**
* 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<String, Object> postProcessOperations(Map<String, Object> objs) {
super.postProcessOperations(objs);
Expand Down Expand Up @@ -746,6 +829,19 @@ public void setInterfacePrefix(final String 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
public String toEnumVarName(String name, String datatype) {
if (name.length() == 0) {
Expand Down Expand Up @@ -776,32 +872,6 @@ public String toEnumName(CodegenProperty property) {
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";
}
Expand All @@ -816,5 +886,4 @@ public String escapeQuotationMark(String input) {
public String escapeUnsafeCharacters(String input) {
return input.replace("*/", "*_/").replace("/*", "/_*").replace("--", "- -");
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -619,19 +619,6 @@ private CodegenModel reconcileInlineEnums(CodegenModel codegenModel, CodegenMode
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) {
Expand All @@ -644,8 +631,8 @@ public String toEnumVarName(String value, String datatype) {
}

// 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_");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@
{{#description}}
/// <value>{{description}}</value>
{{/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}}
/// <summary>
/// Enum {{name}} for {{{value}}}
/// Enum {{name}} for value: {{{value}}}
/// </summary>
[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}}
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
{{^isContainer}}
/// <summary>
/// {{^description}}Gets or Sets {{{name}}}{{/description}}{{#description}}{{description}}{{/description}}
/// {{^description}}Defines {{{name}}}{{/description}}{{#description}}{{description}}{{/description}}
/// </summary>
{{#description}}
/// <value>{{description}}</value>
{{/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}}
/// <summary>
/// Enum {{name}} for {{{value}}}
/// Enum {{name}} for value: {{{value}}}
/// </summary>
[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}}
Original file line number Diff line number Diff line change
Expand Up @@ -31,50 +31,50 @@ namespace IO.Swagger.Model
public partial class MyClassWithOptionalInlineEnum : IEquatable<MyClassWithOptionalInlineEnum>, IValidatableObject
{
/// <summary>
/// Gets or Sets Days
/// Defines Days
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public enum DaysEnum
{

/// <summary>
/// Enum Sun for "sun"
/// Enum Sun for value: sun
/// </summary>
[EnumMember(Value = "sun")]
Sun = 1,

/// <summary>
/// Enum Mon for "mon"
/// Enum Mon for value: mon
/// </summary>
[EnumMember(Value = "mon")]
Mon = 2,

/// <summary>
/// Enum Tue for "tue"
/// Enum Tue for value: tue
/// </summary>
[EnumMember(Value = "tue")]
Tue = 3,

/// <summary>
/// Enum Wed for "wed"
/// Enum Wed for value: wed
/// </summary>
[EnumMember(Value = "wed")]
Wed = 4,

/// <summary>
/// Enum Thu for "thu"
/// Enum Thu for value: thu
/// </summary>
[EnumMember(Value = "thu")]
Thu = 5,

/// <summary>
/// Enum Fri for "fri"
/// Enum Fri for value: fri
/// </summary>
[EnumMember(Value = "fri")]
Fri = 6,

/// <summary>
/// Enum Sat for "sat"
/// Enum Sat for value: sat
/// </summary>
[EnumMember(Value = "sat")]
Sat = 7
Expand Down
Loading