forked from loafle/openapi-generator-original
[csharp] Clean up ref/inner enum struture
Enums defines as ref models have a different object structure (CodegenModel) than those defined as inner enums (CodegenProperty). To make these look as similar as possible, we walk all ref model enums and reassign enumVars with the same properties inherited from the top level CodegenProperty so CodegenModel enums can use the same templates as inner enums.
This commit is contained in:
@@ -1955,6 +1955,8 @@ public class DefaultCodegen {
|
||||
if (property.defaultValue != null) {
|
||||
property.defaultValue = property.defaultValue.replace(baseItem.baseType, toEnumName(baseItem));
|
||||
}
|
||||
|
||||
updateCodegenPropertyEnum(property);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package io.swagger.codegen.languages;
|
||||
|
||||
import com.samskivert.mustache.Mustache;
|
||||
import com.samskivert.mustache.Template;
|
||||
import io.swagger.codegen.*;
|
||||
import io.swagger.codegen.utils.ModelUtils;
|
||||
import io.swagger.models.properties.*;
|
||||
@@ -8,6 +10,8 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.*;
|
||||
|
||||
public abstract class AbstractCSharpCodegen extends DefaultCodegen implements CodegenConfig {
|
||||
@@ -343,6 +347,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<String, Object> models) {
|
||||
Map<String, CodegenModel> enumRefs = new HashMap<String, CodegenModel>();
|
||||
for (Map.Entry<String, Object> entry : models.entrySet()) {
|
||||
@@ -354,6 +359,7 @@ public abstract class AbstractCSharpCodegen extends DefaultCodegen implements Co
|
||||
|
||||
for (Map.Entry<String, Object> entry : models.entrySet()) {
|
||||
String swaggerName = entry.getKey();
|
||||
|
||||
CodegenModel model = ModelUtils.getModelByName(swaggerName, models);
|
||||
if (model != null) {
|
||||
for (CodegenProperty var : model.allVars) {
|
||||
@@ -363,11 +369,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#.
|
||||
// We do this 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 {
|
||||
@@ -376,6 +428,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<String, Object> postProcessOperations(Map<String, Object> objs) {
|
||||
super.postProcessOperations(objs);
|
||||
@@ -746,6 +834,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) {
|
||||
@@ -776,32 +877,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";
|
||||
}
|
||||
@@ -816,5 +891,4 @@ public abstract class AbstractCSharpCodegen extends DefaultCodegen implements Co
|
||||
public String escapeUnsafeCharacters(String input) {
|
||||
return input.replace("*/", "*_/").replace("/*", "/_*").replace("--", "- -");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -611,19 +611,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) {
|
||||
@@ -636,8 +623,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_");
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
/// <summary>
|
||||
/// {{^description}}Gets or Sets {{{name}}}{{/description}}{{#description}}{{description}}{{/description}}
|
||||
/// </summary>
|
||||
{{#description}}
|
||||
/// <value>{{description}}</value>
|
||||
{{/description}}
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
{{>visibility}} enum {{#datatypeWithEnum}}{{.}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}}
|
||||
{
|
||||
{{#allowableValues}}{{#enumVars}}
|
||||
/// <summary>
|
||||
/// Enum {{name}} for {{{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}}{{^-last}},
|
||||
{{/-last}}{{/enumVars}}{{/allowableValues}}
|
||||
}
|
||||
@@ -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}}{{^-last}},
|
||||
{{#isString}}[EnumMember(Value = "{{{value}}}")]{{/isString}}
|
||||
{{name}}{{^isString}} = {{{value}}}{{/isString}}{{^-last}},
|
||||
{{/-last}}{{/enumVars}}{{/allowableValues}}
|
||||
}
|
||||
}{{! NOTE: This model's enumVars is modified to look like CodegenProperty}}
|
||||
|
||||
@@ -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}}{{^-last}},
|
||||
{{#isString}}[EnumMember(Value = "{{{value}}}")]{{/isString}}
|
||||
{{name}}{{^isString}} = {{{value}}}{{/isString}}{{^-last}},
|
||||
{{/-last}}{{/enumVars}}{{/allowableValues}}
|
||||
}
|
||||
{{/isContainer}}
|
||||
|
||||
@@ -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,
|
||||
|
||||
/// <summary>
|
||||
/// Enum Mon for "mon"
|
||||
/// Enum Mon for value: mon
|
||||
/// </summary>
|
||||
[EnumMember(Value = "mon")]
|
||||
Mon,
|
||||
|
||||
/// <summary>
|
||||
/// Enum Tue for "tue"
|
||||
/// Enum Tue for value: tue
|
||||
/// </summary>
|
||||
[EnumMember(Value = "tue")]
|
||||
Tue,
|
||||
|
||||
/// <summary>
|
||||
/// Enum Wed for "wed"
|
||||
/// Enum Wed for value: wed
|
||||
/// </summary>
|
||||
[EnumMember(Value = "wed")]
|
||||
Wed,
|
||||
|
||||
/// <summary>
|
||||
/// Enum Thu for "thu"
|
||||
/// Enum Thu for value: thu
|
||||
/// </summary>
|
||||
[EnumMember(Value = "thu")]
|
||||
Thu,
|
||||
|
||||
/// <summary>
|
||||
/// Enum Fri for "fri"
|
||||
/// Enum Fri for value: fri
|
||||
/// </summary>
|
||||
[EnumMember(Value = "fri")]
|
||||
Fri,
|
||||
|
||||
/// <summary>
|
||||
/// Enum Sat for "sat"
|
||||
/// Enum Sat for value: sat
|
||||
/// </summary>
|
||||
[EnumMember(Value = "sat")]
|
||||
Sat
|
||||
|
||||
@@ -31,50 +31,50 @@ namespace IO.Swagger.Model
|
||||
public partial class MyClassWithRequiredInlineEnum : IEquatable<MyClassWithRequiredInlineEnum>, 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,
|
||||
|
||||
/// <summary>
|
||||
/// Enum Mon for "mon"
|
||||
/// Enum Mon for value: mon
|
||||
/// </summary>
|
||||
[EnumMember(Value = "mon")]
|
||||
Mon,
|
||||
|
||||
/// <summary>
|
||||
/// Enum Tue for "tue"
|
||||
/// Enum Tue for value: tue
|
||||
/// </summary>
|
||||
[EnumMember(Value = "tue")]
|
||||
Tue,
|
||||
|
||||
/// <summary>
|
||||
/// Enum Wed for "wed"
|
||||
/// Enum Wed for value: wed
|
||||
/// </summary>
|
||||
[EnumMember(Value = "wed")]
|
||||
Wed,
|
||||
|
||||
/// <summary>
|
||||
/// Enum Thu for "thu"
|
||||
/// Enum Thu for value: thu
|
||||
/// </summary>
|
||||
[EnumMember(Value = "thu")]
|
||||
Thu,
|
||||
|
||||
/// <summary>
|
||||
/// Enum Fri for "fri"
|
||||
/// Enum Fri for value: fri
|
||||
/// </summary>
|
||||
[EnumMember(Value = "fri")]
|
||||
Fri,
|
||||
|
||||
/// <summary>
|
||||
/// Enum Sat for "sat"
|
||||
/// Enum Sat for value: sat
|
||||
/// </summary>
|
||||
[EnumMember(Value = "sat")]
|
||||
Sat
|
||||
|
||||
@@ -27,48 +27,50 @@ namespace IO.Swagger.Model
|
||||
/// <summary>
|
||||
/// Defines WeekDays
|
||||
/// </summary>
|
||||
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
|
||||
public enum WeekDays
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Enum Sun for "sun"
|
||||
/// Enum Sun for value: sun
|
||||
/// </summary>
|
||||
[EnumMember(Value = "sun")]
|
||||
Sun,
|
||||
|
||||
/// <summary>
|
||||
/// Enum Mon for "mon"
|
||||
/// Enum Mon for value: mon
|
||||
/// </summary>
|
||||
[EnumMember(Value = "mon")]
|
||||
Mon,
|
||||
|
||||
/// <summary>
|
||||
/// Enum Tue for "tue"
|
||||
/// Enum Tue for value: tue
|
||||
/// </summary>
|
||||
[EnumMember(Value = "tue")]
|
||||
Tue,
|
||||
|
||||
/// <summary>
|
||||
/// Enum Wed for "wed"
|
||||
/// Enum Wed for value: wed
|
||||
/// </summary>
|
||||
[EnumMember(Value = "wed")]
|
||||
Wed,
|
||||
|
||||
/// <summary>
|
||||
/// Enum Thu for "thu"
|
||||
/// Enum Thu for value: thu
|
||||
/// </summary>
|
||||
[EnumMember(Value = "thu")]
|
||||
Thu,
|
||||
|
||||
/// <summary>
|
||||
/// Enum Fri for "fri"
|
||||
/// Enum Fri for value: fri
|
||||
/// </summary>
|
||||
[EnumMember(Value = "fri")]
|
||||
Fri,
|
||||
|
||||
/// <summary>
|
||||
/// Enum Sat for "sat"
|
||||
/// Enum Sat for value: sat
|
||||
/// </summary>
|
||||
[EnumMember(Value = "sat")]
|
||||
Sat
|
||||
|
||||
Reference in New Issue
Block a user