Skip to content

Commit b7f4f3e

Browse files
committed
Merge branch 'csharp-enum-cleanup' of https://github.com/jimschubert/swagger-codegen
2 parents f9105c8 + 64fafb5 commit b7f4f3e

File tree

11 files changed

+156
-88
lines changed

11 files changed

+156
-88
lines changed

modules/swagger-codegen-maven-plugin/src/main/java/io/swagger/codegen/plugin/CodeGenMojo.java

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -405,28 +405,28 @@ public void execute() throws MojoExecutionException {
405405

406406
// Set generation options
407407
if (null != generateApis && generateApis) {
408-
System.setProperty("apis", "");
408+
System.setProperty(CodegenConstants.APIS, "");
409409
} else {
410-
System.clearProperty("apis");
410+
System.clearProperty(CodegenConstants.APIS);
411411
}
412412

413413
if (null != generateModels && generateModels) {
414-
System.setProperty("models", modelsToGenerate);
414+
System.setProperty(CodegenConstants.MODELS, modelsToGenerate);
415415
} else {
416-
System.clearProperty("models");
416+
System.clearProperty(CodegenConstants.MODELS);
417417
}
418418

419419
if (null != generateSupportingFiles && generateSupportingFiles) {
420-
System.setProperty("supportingFiles", supportingFilesToGenerate);
420+
System.setProperty(CodegenConstants.SUPPORTING_FILES, supportingFilesToGenerate);
421421
} else {
422-
System.clearProperty("supportingFiles");
422+
System.clearProperty(CodegenConstants.SUPPORTING_FILES);
423423
}
424424

425-
System.setProperty("modelTests", generateModelTests.toString());
426-
System.setProperty("modelDocs", generateModelDocumentation.toString());
427-
System.setProperty("apiTests", generateApiTests.toString());
428-
System.setProperty("apiDocs", generateApiDocumentation.toString());
429-
System.setProperty("withXml", withXml.toString());
425+
System.setProperty(CodegenConstants.MODEL_TESTS, generateModelTests.toString());
426+
System.setProperty(CodegenConstants.MODEL_DOCS, generateModelDocumentation.toString());
427+
System.setProperty(CodegenConstants.API_TESTS, generateApiTests.toString());
428+
System.setProperty(CodegenConstants.API_DOCS, generateApiDocumentation.toString());
429+
System.setProperty(CodegenConstants.WITH_XML, withXml.toString());
430430

431431
if (configOptions != null) {
432432
// Retained for backwards-compataibility with configOptions -> instantiation-types

modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenConstants.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,17 @@
44
* A class for storing constants that are used throughout the project.
55
*/
66
public class CodegenConstants {
7+
/* System Properties */
8+
// NOTE: We may want to move these to a separate class to avoid confusion or modification.
79
public static final String APIS = "apis";
810
public static final String MODELS = "models";
911
public static final String SUPPORTING_FILES = "supportingFiles";
1012
public static final String MODEL_TESTS = "modelTests";
1113
public static final String MODEL_DOCS = "modelDocs";
1214
public static final String API_TESTS = "apiTests";
1315
public static final String API_DOCS = "apiDocs";
16+
public static final String WITH_XML = "withXml";
17+
/* /end System Properties */
1418

1519
public static final String API_PACKAGE = "apiPackage";
1620
public static final String API_PACKAGE_DESC = "package for generated api classes";

modules/swagger-codegen/src/main/java/io/swagger/codegen/DefaultCodegen.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1930,6 +1930,8 @@ protected void updateDataTypeWithEnumForArray(CodegenProperty property) {
19301930
if (property.defaultValue != null) {
19311931
property.defaultValue = property.defaultValue.replace(baseItem.baseType, toEnumName(baseItem));
19321932
}
1933+
1934+
updateCodegenPropertyEnum(property);
19331935
}
19341936
}
19351937

modules/swagger-codegen/src/main/java/io/swagger/codegen/DefaultGenerator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -551,7 +551,7 @@ private void generateSupportingFiles(List<File> files, Map<String, Object> bundl
551551
return;
552552
}
553553
Set<String> supportingFilesToGenerate = null;
554-
String supportingFiles = System.getProperty("supportingFiles");
554+
String supportingFiles = System.getProperty(CodegenConstants.SUPPORTING_FILES);
555555
if (supportingFiles != null && !supportingFiles.isEmpty()) {
556556
supportingFilesToGenerate = new HashSet<String>(Arrays.asList(supportingFiles.split(",")));
557557
}

modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/AbstractCSharpCodegen.java

Lines changed: 97 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,7 @@ public Map<String, Object> postProcessAllModels(Map<String, Object> objs) {
352352
* those vars referencing RefModel'd enums to work the same as inlined enums rather than as objects.
353353
* @param models
354354
*/
355+
@SuppressWarnings({ "unchecked" })
355356
private void postProcessEnumRefs(final Map<String, Object> models) {
356357
Map<String, CodegenModel> enumRefs = new HashMap<String, CodegenModel>();
357358
for (Map.Entry<String, Object> entry : models.entrySet()) {
@@ -372,11 +373,57 @@ private void postProcessEnumRefs(final Map<String, Object> models) {
372373
// while enums in many other languages are true objects.
373374
CodegenModel refModel = enumRefs.get(var.datatype);
374375
var.allowableValues = refModel.allowableValues;
376+
var.isEnum = true;
377+
375378
updateCodegenPropertyEnum(var);
376379

377380
// We do these after updateCodegenPropertyEnum to avoid generalities that don't mesh with C#.
378381
var.isPrimitiveType = true;
379-
var.isEnum = true;
382+
}
383+
}
384+
385+
// We're looping all models here.
386+
if (model.isEnum) {
387+
// We now need to make allowableValues.enumVars look like the context of CodegenProperty
388+
Boolean isString = false;
389+
Boolean isInteger = false;
390+
Boolean isLong = false;
391+
Boolean isByte = false;
392+
393+
if (model.dataType.startsWith("byte")) {
394+
// C# Actually supports byte and short enums, swagger spec only supports byte.
395+
isByte = true;
396+
model.vendorExtensions.put("x-enum-byte", true);
397+
} else if (model.dataType.startsWith("int32")) {
398+
isInteger = true;
399+
model.vendorExtensions.put("x-enum-integer", true);
400+
} else if (model.dataType.startsWith("int64")) {
401+
isLong = true;
402+
model.vendorExtensions.put("x-enum-long", true);
403+
} else {
404+
// 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)
405+
isString = true;
406+
model.vendorExtensions.put("x-enum-string", true);
407+
}
408+
409+
// Since we iterate enumVars for modelnnerEnum and enumClass templates, and CodegenModel is missing some of CodegenProperty's properties,
410+
// 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.
411+
List<Map<String, String>> enumVars = (ArrayList<Map<String, String>>)model.allowableValues.get("enumVars");
412+
List<Map<String, Object>> newEnumVars = new ArrayList<Map<String, Object>>();
413+
for (Map<String, String> enumVar : enumVars) {
414+
Map<String, Object> mixedVars = new HashMap<String, Object>();
415+
mixedVars.putAll(enumVar);
416+
417+
mixedVars.put("isString", isString);
418+
mixedVars.put("isLong", isLong);
419+
mixedVars.put("isInteger", isInteger);
420+
mixedVars.put("isByte", isByte);
421+
422+
newEnumVars.add(mixedVars);
423+
}
424+
425+
if (!newEnumVars.isEmpty()) {
426+
model.allowableValues.put("enumVars", newEnumVars);
380427
}
381428
}
382429
} else {
@@ -385,6 +432,42 @@ private void postProcessEnumRefs(final Map<String, Object> models) {
385432
}
386433
}
387434

435+
/**
436+
* Update codegen property's enum by adding "enumVars" (with name and value)
437+
*
438+
* @param var list of CodegenProperty
439+
*/
440+
@Override
441+
public void updateCodegenPropertyEnum(CodegenProperty var) {
442+
if (var.vendorExtensions == null) {
443+
var.vendorExtensions = new HashMap<>();
444+
}
445+
446+
super.updateCodegenPropertyEnum(var);
447+
448+
// Because C# uses nullable primitives for datatype, and datatype is used in DefaultCodegen for determining enum-ness, guard against weirdness here.
449+
if (var.isEnum) {
450+
if ("byte".equals(var.dataFormat)) {// C# Actually supports byte and short enums.
451+
var.vendorExtensions.put("x-enum-byte", true);
452+
var.isString = false;
453+
var.isLong = false;
454+
var.isInteger = false;
455+
} else if ("int32".equals(var.dataFormat)) {
456+
var.isInteger = true;
457+
var.isString = false;
458+
var.isLong = false;
459+
} else if ("int64".equals(var.dataFormat)) {
460+
var.isLong = true;
461+
var.isString = false;
462+
var.isInteger = false;
463+
} 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)
464+
var.isString = true;
465+
var.isInteger = false;
466+
var.isLong = false;
467+
}
468+
}
469+
}
470+
388471
@Override
389472
public Map<String, Object> postProcessOperations(Map<String, Object> objs) {
390473
super.postProcessOperations(objs);
@@ -769,6 +852,19 @@ public void setInterfacePrefix(final String interfacePrefix) {
769852
this.interfacePrefix = interfacePrefix;
770853
}
771854

855+
@Override
856+
public String toEnumValue(String value, String datatype) {
857+
// C# only supports enums as literals for int, int?, long, long?, byte, and byte?. All else must be treated as strings.
858+
// Per: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/enum
859+
// The approved types for an enum are byte, sbyte, short, ushort, int, uint, long, or ulong.
860+
// but we're not supporting unsigned integral types or shorts.
861+
if(datatype.startsWith("int") || datatype.startsWith("long") || datatype.startsWith("byte")) {
862+
return value;
863+
}
864+
865+
return escapeText(value);
866+
}
867+
772868
@Override
773869
public String toEnumVarName(String name, String datatype) {
774870
if (name.length() == 0) {
@@ -799,32 +895,6 @@ public String toEnumName(CodegenProperty property) {
799895
return sanitizeName(camelize(property.name)) + "Enum";
800896
}
801897

802-
/*
803-
@Override
804-
public String toEnumName(CodegenProperty property) {
805-
String enumName = sanitizeName(property.name);
806-
if (!StringUtils.isEmpty(modelNamePrefix)) {
807-
enumName = modelNamePrefix + "_" + enumName;
808-
}
809-
810-
if (!StringUtils.isEmpty(modelNameSuffix)) {
811-
enumName = enumName + "_" + modelNameSuffix;
812-
}
813-
814-
// model name cannot use reserved keyword, e.g. return
815-
if (isReservedWord(enumName)) {
816-
LOGGER.warn(enumName + " (reserved word) cannot be used as model name. Renamed to " + camelize("model_" + enumName));
817-
enumName = "model_" + enumName; // e.g. return => ModelReturn (after camelize)
818-
}
819-
820-
if (enumName.matches("\\d.*")) { // starts with number
821-
return "_" + enumName;
822-
} else {
823-
return enumName;
824-
}
825-
}
826-
*/
827-
828898
public String testPackageName() {
829899
return this.packageName + ".Test";
830900
}
@@ -839,5 +909,4 @@ public String escapeQuotationMark(String input) {
839909
public String escapeUnsafeCharacters(String input) {
840910
return input.replace("*/", "*_/").replace("/*", "/_*").replace("--", "- -");
841911
}
842-
843912
}

modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/CSharpClientCodegen.java

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -671,19 +671,6 @@ private CodegenModel reconcileInlineEnums(CodegenModel codegenModel, CodegenMode
671671
return codegenModel;
672672
}
673673

674-
@Override
675-
public String toEnumValue(String value, String datatype) {
676-
if ("int?".equalsIgnoreCase(datatype) || "long?".equalsIgnoreCase(datatype) ||
677-
"double?".equalsIgnoreCase(datatype) || "float?".equalsIgnoreCase(datatype)) {
678-
return value;
679-
} else if ("float?".equalsIgnoreCase(datatype)) {
680-
// for float in C#, append "f". e.g. 3.14 => 3.14f
681-
return value + "f";
682-
} else {
683-
return "\"" + escapeText(value) + "\"";
684-
}
685-
}
686-
687674
@Override
688675
public String toEnumVarName(String value, String datatype) {
689676
if (value.length() == 0) {
@@ -696,8 +683,8 @@ public String toEnumVarName(String value, String datatype) {
696683
}
697684

698685
// number
699-
if ("int?".equals(datatype) || "long?".equals(datatype) ||
700-
"double?".equals(datatype) || "float?".equals(datatype)) {
686+
if(datatype.startsWith("int") || datatype.startsWith("long") ||
687+
datatype.startsWith("double") || datatype.startsWith("float")) {
701688
String varName = "NUMBER_" + value;
702689
varName = varName.replaceAll("-", "MINUS_");
703690
varName = varName.replaceAll("\\+", "PLUS_");

modules/swagger-codegen/src/main/resources/csharp/modelEnum.mustache

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,16 @@
44
{{#description}}
55
/// <value>{{description}}</value>
66
{{/description}}
7+
{{#allowableValues}}{{#enumVars}}{{#-first}}{{#isString}}
78
[JsonConverter(typeof(StringEnumConverter))]
8-
{{>visibility}} enum {{#datatypeWithEnum}}{{.}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}}
9+
{{/isString}}{{/-first}}{{/enumVars}}{{/allowableValues}}
10+
{{>visibility}} enum {{#datatypeWithEnum}}{{.}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}}{{#vendorExtensions.x-enum-byte}}: byte{{/vendorExtensions.x-enum-byte}}
911
{
1012
{{#allowableValues}}{{#enumVars}}
1113
/// <summary>
12-
/// Enum {{name}} for {{{value}}}
14+
/// Enum {{name}} for value: {{{value}}}
1315
/// </summary>
14-
[EnumMember(Value = {{#isInteger}}"{{/isInteger}}{{#isDouble}}"{{/isDouble}}{{{value}}}{{#isInteger}}"{{/isInteger}}{{#isDouble}}"{{/isDouble}})]
15-
{{name}}{{#isInteger}} = {{{value}}}{{/isInteger}}{{^isInteger}} = {{-index}}{{/isInteger}}{{^-last}},
16+
{{#isString}}[EnumMember(Value = "{{{value}}}")]{{/isString}}
17+
{{name}}{{^isString}} = {{{value}}}{{/isString}}{{#isString}} = {{-index}}{{/isString}}{{^-last}},
1618
{{/-last}}{{/enumVars}}{{/allowableValues}}
17-
}
19+
}{{! NOTE: This model's enumVars is modified to look like CodegenProperty}}
Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
11
{{^isContainer}}
22
/// <summary>
3-
/// {{^description}}Gets or Sets {{{name}}}{{/description}}{{#description}}{{description}}{{/description}}
3+
/// {{^description}}Defines {{{name}}}{{/description}}{{#description}}{{description}}{{/description}}
44
/// </summary>
55
{{#description}}
66
/// <value>{{description}}</value>
77
{{/description}}
8+
{{#isString}}
89
[JsonConverter(typeof(StringEnumConverter))]
9-
{{>visibility}} enum {{#datatypeWithEnum}}{{&.}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}}
10+
{{/isString}}
11+
{{>visibility}} enum {{#datatypeWithEnum}}{{.}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}}{{#vendorExtensions.x-enum-byte}}: byte{{/vendorExtensions.x-enum-byte}}
1012
{
1113
{{#allowableValues}}{{#enumVars}}
1214
/// <summary>
13-
/// Enum {{name}} for {{{value}}}
15+
/// Enum {{name}} for value: {{{value}}}
1416
/// </summary>
15-
[EnumMember(Value = {{#isLong}}"{{/isLong}}{{#isInteger}}"{{/isInteger}}{{#isFloat}}"{{/isFloat}}{{#isDouble}}"{{/isDouble}}{{{value}}}{{#isLong}}"{{/isLong}}{{#isInteger}}"{{/isInteger}}{{#isDouble}}"{{/isDouble}}{{#isFloat}}"{{/isFloat}})]
16-
{{name}}{{#isLong}} = {{{value}}}{{/isLong}}{{#isInteger}} = {{{value}}}{{/isInteger}}{{^isInteger}} = {{-index}}{{/isInteger}}{{^-last}},
17+
{{#isString}}[EnumMember(Value = "{{{value}}}")]{{/isString}}
18+
{{name}}{{^isString}} = {{{value}}}{{/isString}}{{#isString}} = {{-index}}{{/isString}}{{^-last}},
1719
{{/-last}}{{/enumVars}}{{/allowableValues}}
1820
}
1921
{{/isContainer}}

modules/swagger-codegen/src/test/resources/integrationtests/csharp/general/enum-support-expected/src/IO.Swagger/Model/MyClassWithOptionalInlineEnum.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,50 +31,50 @@ namespace IO.Swagger.Model
3131
public partial class MyClassWithOptionalInlineEnum : IEquatable<MyClassWithOptionalInlineEnum>, IValidatableObject
3232
{
3333
/// <summary>
34-
/// Gets or Sets Days
34+
/// Defines Days
3535
/// </summary>
3636
[JsonConverter(typeof(StringEnumConverter))]
3737
public enum DaysEnum
3838
{
3939

4040
/// <summary>
41-
/// Enum Sun for "sun"
41+
/// Enum Sun for value: sun
4242
/// </summary>
4343
[EnumMember(Value = "sun")]
4444
Sun = 1,
4545

4646
/// <summary>
47-
/// Enum Mon for "mon"
47+
/// Enum Mon for value: mon
4848
/// </summary>
4949
[EnumMember(Value = "mon")]
5050
Mon = 2,
5151

5252
/// <summary>
53-
/// Enum Tue for "tue"
53+
/// Enum Tue for value: tue
5454
/// </summary>
5555
[EnumMember(Value = "tue")]
5656
Tue = 3,
5757

5858
/// <summary>
59-
/// Enum Wed for "wed"
59+
/// Enum Wed for value: wed
6060
/// </summary>
6161
[EnumMember(Value = "wed")]
6262
Wed = 4,
6363

6464
/// <summary>
65-
/// Enum Thu for "thu"
65+
/// Enum Thu for value: thu
6666
/// </summary>
6767
[EnumMember(Value = "thu")]
6868
Thu = 5,
6969

7070
/// <summary>
71-
/// Enum Fri for "fri"
71+
/// Enum Fri for value: fri
7272
/// </summary>
7373
[EnumMember(Value = "fri")]
7474
Fri = 6,
7575

7676
/// <summary>
77-
/// Enum Sat for "sat"
77+
/// Enum Sat for value: sat
7878
/// </summary>
7979
[EnumMember(Value = "sat")]
8080
Sat = 7

0 commit comments

Comments
 (0)