1
1
package io .swagger .codegen .languages ;
2
2
3
+ import com .samskivert .mustache .Mustache ;
4
+ import com .samskivert .mustache .Template ;
3
5
import io .swagger .codegen .*;
4
6
import io .swagger .codegen .utils .ModelUtils ;
5
7
import io .swagger .models .properties .*;
8
10
import org .slf4j .LoggerFactory ;
9
11
10
12
import java .io .File ;
13
+ import java .io .IOException ;
14
+ import java .io .Writer ;
11
15
import java .util .*;
12
16
13
17
public abstract class AbstractCSharpCodegen extends DefaultCodegen implements CodegenConfig {
@@ -343,6 +347,7 @@ public Map<String, Object> postProcessAllModels(Map<String, Object> objs) {
343
347
* those vars referencing RefModel'd enums to work the same as inlined enums rather than as objects.
344
348
* @param models
345
349
*/
350
+ @ SuppressWarnings ({ "unchecked" })
346
351
private void postProcessEnumRefs (final Map <String , Object > models ) {
347
352
Map <String , CodegenModel > enumRefs = new HashMap <String , CodegenModel >();
348
353
for (Map .Entry <String , Object > entry : models .entrySet ()) {
@@ -354,6 +359,7 @@ private void postProcessEnumRefs(final Map<String, Object> models) {
354
359
355
360
for (Map .Entry <String , Object > entry : models .entrySet ()) {
356
361
String swaggerName = entry .getKey ();
362
+
357
363
CodegenModel model = ModelUtils .getModelByName (swaggerName , models );
358
364
if (model != null ) {
359
365
for (CodegenProperty var : model .allVars ) {
@@ -363,11 +369,57 @@ private void postProcessEnumRefs(final Map<String, Object> models) {
363
369
// while enums in many other languages are true objects.
364
370
CodegenModel refModel = enumRefs .get (var .datatype );
365
371
var .allowableValues = refModel .allowableValues ;
372
+ var .isEnum = true ;
373
+
366
374
updateCodegenPropertyEnum (var );
367
375
368
- // We do these after updateCodegenPropertyEnum to avoid generalities that don't mesh with C#.
376
+ // We do this after updateCodegenPropertyEnum to avoid generalities that don't mesh with C#.
369
377
var .isPrimitiveType = true ;
370
- var .isEnum = true ;
378
+ }
379
+ }
380
+
381
+ // We're looping all models here.
382
+ if (model .isEnum ) {
383
+ // We now need to make allowableValues.enumVars look like the context of CodegenProperty
384
+ Boolean isString = false ;
385
+ Boolean isInteger = false ;
386
+ Boolean isLong = false ;
387
+ Boolean isByte = false ;
388
+
389
+ if (model .dataType .startsWith ("byte" )) {
390
+ // C# Actually supports byte and short enums, swagger spec only supports byte.
391
+ isByte = true ;
392
+ model .vendorExtensions .put ("x-enum-byte" , true );
393
+ } else if (model .dataType .startsWith ("int32" )) {
394
+ isInteger = true ;
395
+ model .vendorExtensions .put ("x-enum-integer" , true );
396
+ } else if (model .dataType .startsWith ("int64" )) {
397
+ isLong = true ;
398
+ model .vendorExtensions .put ("x-enum-long" , true );
399
+ } else {
400
+ // 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)
401
+ isString = true ;
402
+ model .vendorExtensions .put ("x-enum-string" , true );
403
+ }
404
+
405
+ // Since we iterate enumVars for modelnnerEnum and enumClass templates, and CodegenModel is missing some of CodegenProperty's properties,
406
+ // 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.
407
+ List <Map <String , String >> enumVars = (ArrayList <Map <String , String >>)model .allowableValues .get ("enumVars" );
408
+ List <Map <String , Object >> newEnumVars = new ArrayList <Map <String , Object >>();
409
+ for (Map <String , String > enumVar : enumVars ) {
410
+ Map <String , Object > mixedVars = new HashMap <String , Object >();
411
+ mixedVars .putAll (enumVar );
412
+
413
+ mixedVars .put ("isString" , isString );
414
+ mixedVars .put ("isLong" , isLong );
415
+ mixedVars .put ("isInteger" , isInteger );
416
+ mixedVars .put ("isByte" , isByte );
417
+
418
+ newEnumVars .add (mixedVars );
419
+ }
420
+
421
+ if (!newEnumVars .isEmpty ()) {
422
+ model .allowableValues .put ("enumVars" , newEnumVars );
371
423
}
372
424
}
373
425
} else {
@@ -376,6 +428,42 @@ private void postProcessEnumRefs(final Map<String, Object> models) {
376
428
}
377
429
}
378
430
431
+ /**
432
+ * Update codegen property's enum by adding "enumVars" (with name and value)
433
+ *
434
+ * @param var list of CodegenProperty
435
+ */
436
+ @ Override
437
+ public void updateCodegenPropertyEnum (CodegenProperty var ) {
438
+ if (var .vendorExtensions == null ) {
439
+ var .vendorExtensions = new HashMap <>();
440
+ }
441
+
442
+ super .updateCodegenPropertyEnum (var );
443
+
444
+ // Because C# uses nullable primitives for datatype, and datatype is used in DefaultCodegen for determining enum-ness, guard against weirdness here.
445
+ if (var .isEnum ) {
446
+ if ("byte" .equals (var .dataFormat )) {// C# Actually supports byte and short enums.
447
+ var .vendorExtensions .put ("x-enum-byte" , true );
448
+ var .isString = false ;
449
+ var .isLong = false ;
450
+ var .isInteger = false ;
451
+ } else if ("int32" .equals (var .dataFormat )) {
452
+ var .isInteger = true ;
453
+ var .isString = false ;
454
+ var .isLong = false ;
455
+ } else if ("int64" .equals (var .dataFormat )) {
456
+ var .isLong = true ;
457
+ var .isString = false ;
458
+ var .isInteger = false ;
459
+ } 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)
460
+ var .isString = true ;
461
+ var .isInteger = false ;
462
+ var .isLong = false ;
463
+ }
464
+ }
465
+ }
466
+
379
467
@ Override
380
468
public Map <String , Object > postProcessOperations (Map <String , Object > objs ) {
381
469
super .postProcessOperations (objs );
@@ -746,6 +834,19 @@ public void setInterfacePrefix(final String interfacePrefix) {
746
834
this .interfacePrefix = interfacePrefix ;
747
835
}
748
836
837
+ @ Override
838
+ public String toEnumValue (String value , String datatype ) {
839
+ // C# only supports enums as literals for int, int?, long, long?, byte, and byte?. All else must be treated as strings.
840
+ // Per: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/enum
841
+ // The approved types for an enum are byte, sbyte, short, ushort, int, uint, long, or ulong.
842
+ // but we're not supporting unsigned integral types or shorts.
843
+ if (datatype .startsWith ("int" ) || datatype .startsWith ("long" ) || datatype .startsWith ("byte" )) {
844
+ return value ;
845
+ }
846
+
847
+ return escapeText (value );
848
+ }
849
+
749
850
@ Override
750
851
public String toEnumVarName (String name , String datatype ) {
751
852
if (name .length () == 0 ) {
@@ -776,32 +877,6 @@ public String toEnumName(CodegenProperty property) {
776
877
return sanitizeName (camelize (property .name )) + "Enum" ;
777
878
}
778
879
779
- /*
780
- @Override
781
- public String toEnumName(CodegenProperty property) {
782
- String enumName = sanitizeName(property.name);
783
- if (!StringUtils.isEmpty(modelNamePrefix)) {
784
- enumName = modelNamePrefix + "_" + enumName;
785
- }
786
-
787
- if (!StringUtils.isEmpty(modelNameSuffix)) {
788
- enumName = enumName + "_" + modelNameSuffix;
789
- }
790
-
791
- // model name cannot use reserved keyword, e.g. return
792
- if (isReservedWord(enumName)) {
793
- LOGGER.warn(enumName + " (reserved word) cannot be used as model name. Renamed to " + camelize("model_" + enumName));
794
- enumName = "model_" + enumName; // e.g. return => ModelReturn (after camelize)
795
- }
796
-
797
- if (enumName.matches("\\d.*")) { // starts with number
798
- return "_" + enumName;
799
- } else {
800
- return enumName;
801
- }
802
- }
803
- */
804
-
805
880
public String testPackageName () {
806
881
return this .packageName + ".Test" ;
807
882
}
@@ -816,5 +891,4 @@ public String escapeQuotationMark(String input) {
816
891
public String escapeUnsafeCharacters (String input ) {
817
892
return input .replace ("*/" , "*_/" ).replace ("/*" , "/_*" ).replace ("--" , "- -" );
818
893
}
819
-
820
894
}
0 commit comments