Skip to content

Commit bc097cf

Browse files
gbrown-cewing328
andauthored
[C#] Fixed valuetype parameters and discriminator deserialization (#5680)
* Fixed valuetype parameters and discriminator deserialization - Made non-required valuetypes nullable, and flagged required valuetypes as "x-csharp-value-type" - Made sure to camelCase discriminator property names in Subtype converter * Ran pet store sample script * Ensure that readWriteVars and readOnlyVars are also marked as isEnum and isPrimitiveType where appropriate * Updated petstore sample with enum fix * Fields that are required should emit default values (otherwise the consuming API might throw a fit * Added missing sample updated * Re-ran petstore example script to grab all changes * Rebased and re-ran example update script * update csharp samples Co-authored-by: William Cheng <wing328hk@gmail.com>
1 parent a8885e8 commit bc097cf

File tree

65 files changed

+550
-545
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+550
-545
lines changed

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractCSharpCodegen.java

+26
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,32 @@ private void postProcessEnumRefs(final Map<String, Object> models) {
470470
var.isPrimitiveType = true;
471471
}
472472
}
473+
for (CodegenProperty var : model.readWriteVars) {
474+
if (enumRefs.containsKey(var.dataType)) {
475+
// Handle any enum properties referred to by $ref.
476+
// This is different in C# than most other generators, because enums in C# are compiled to integral types,
477+
// while enums in many other languages are true objects.
478+
CodegenModel refModel = enumRefs.get(var.dataType);
479+
var.allowableValues = refModel.allowableValues;
480+
var.isEnum = true;
481+
482+
// We do these after updateCodegenPropertyEnum to avoid generalities that don't mesh with C#.
483+
var.isPrimitiveType = true;
484+
}
485+
}
486+
for (CodegenProperty var : model.readOnlyVars) {
487+
if (enumRefs.containsKey(var.dataType)) {
488+
// Handle any enum properties referred to by $ref.
489+
// This is different in C# than most other generators, because enums in C# are compiled to integral types,
490+
// while enums in many other languages are true objects.
491+
CodegenModel refModel = enumRefs.get(var.dataType);
492+
var.allowableValues = refModel.allowableValues;
493+
var.isEnum = true;
494+
495+
// We do these after updateCodegenPropertyEnum to avoid generalities that don't mesh with C#.
496+
var.isPrimitiveType = true;
497+
}
498+
}
473499

474500
// We're looping all models here.
475501
if (model.isEnum) {

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CSharpClientCodegen.java

+12
Original file line numberDiff line numberDiff line change
@@ -661,13 +661,25 @@ public void postProcessParameter(CodegenParameter parameter) {
661661
postProcessPattern(parameter.pattern, parameter.vendorExtensions);
662662
postProcessEmitDefaultValue(parameter.vendorExtensions);
663663
super.postProcessParameter(parameter);
664+
665+
if (nullableType.contains(parameter.dataType)) {
666+
if (!parameter.required) { //optional
667+
parameter.dataType = parameter.dataType + "?";
668+
} else {
669+
parameter.vendorExtensions.put("x-csharp-value-type", true);
670+
}
671+
}
664672
}
665673

666674
@Override
667675
public void postProcessModelProperty(CodegenModel model, CodegenProperty property) {
668676
postProcessPattern(property.pattern, property.vendorExtensions);
669677
postProcessEmitDefaultValue(property.vendorExtensions);
670678
super.postProcessModelProperty(model, property);
679+
680+
if (!property.isContainer && (nullableType.contains(property.dataType) || property.isEnum)) {
681+
property.vendorExtensions.put("x-csharp-value-type", true);
682+
}
671683
}
672684

673685
/*

modules/openapi-generator/src/main/resources/csharp/modelGeneric.mustache

+3-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
/// </summary>
44
[DataContract]
55
{{#discriminator}}
6-
[JsonConverter(typeof(JsonSubtypes), "{{{discriminatorName}}}")]{{#children}}
6+
[JsonConverter(typeof(JsonSubtypes), "{{#lambda.camelcase_param}}{{{discriminatorName}}}{{/lambda.camelcase_param}}")]{{#children}}
77
[JsonSubtypes.KnownSubType(typeof({{classname}}), "{{^vendorExtensions.x-discriminator-value}}{{name}}{{/vendorExtensions.x-discriminator-value}}{{#vendorExtensions.x-discriminator-value}}{{{vendorExtensions.x-discriminator-value}}}{{/vendorExtensions.x-discriminator-value}}")]{{/children}}
88
{{/discriminator}}
99
{{#generatePropertyChanged}}
@@ -31,7 +31,7 @@
3131
{{#description}}
3232
/// <value>{{description}}</value>
3333
{{/description}}
34-
[DataMember(Name="{{baseName}}", EmitDefaultValue={{#vendorExtensions.x-emit-default-value}}true{{/vendorExtensions.x-emit-default-value}}{{^vendorExtensions.x-emit-default-value}}{{#isNullable}}true{{/isNullable}}{{^isNullable}}false{{/isNullable}}{{/vendorExtensions.x-emit-default-value}})]
34+
[DataMember(Name="{{baseName}}", EmitDefaultValue={{#vendorExtensions.x-emit-default-value}}true{{/vendorExtensions.x-emit-default-value}}{{^vendorExtensions.x-emit-default-value}}{{#isNullable}}true{{/isNullable}}{{^isNullable}}{{#required}}true{{/required}}{{^required}}false{{/required}}{{/isNullable}}{{/vendorExtensions.x-emit-default-value}})]
3535
public {{#complexType}}{{{complexType}}}{{/complexType}}{{^complexType}}{{{datatypeWithEnum}}}{{/complexType}}{{^isContainer}}{{^required}}?{{/required}}{{/isContainer}} {{name}} { get; set; }
3636
{{/isEnum}}
3737
{{/vars}}
@@ -108,7 +108,7 @@ this.{{name}} = {{#lambda.camelcase_param}}{{name}}{{/lambda.camelcase_param}};
108108
/// {{^description}}Gets or Sets {{{name}}}{{/description}}{{#description}}{{description}}{{/description}}
109109
/// </summary>{{#description}}
110110
/// <value>{{description}}</value>{{/description}}
111-
[DataMember(Name="{{baseName}}", EmitDefaultValue={{#vendorExtensions.x-emit-default-value}}true{{/vendorExtensions.x-emit-default-value}}{{^vendorExtensions.x-emit-default-value}}{{#isNullable}}true{{/isNullable}}{{^isNullable}}false{{/isNullable}}{{/vendorExtensions.x-emit-default-value}})]{{#isDate}}
111+
[DataMember(Name="{{baseName}}", EmitDefaultValue={{#vendorExtensions.x-emit-default-value}}true{{/vendorExtensions.x-emit-default-value}}{{^vendorExtensions.x-emit-default-value}}{{#isNullable}}true{{/isNullable}}{{^isNullable}}{{#required}}true{{/required}}{{^required}}false{{/required}}{{/isNullable}}{{/vendorExtensions.x-emit-default-value}})]{{#isDate}}
112112
[JsonConverter(typeof(OpenAPIDateConverter))]{{/isDate}}
113113
public {{{dataType}}} {{name}} { get; {{#isReadOnly}}private {{/isReadOnly}}set; }
114114
{{/isEnum}}

samples/client/petstore/csharp-netcore/OpenAPIClient/src/Org.OpenAPITools/Model/EnumTest.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ protected EnumTest() { }
159159
/// <param name="enumInteger">enumInteger.</param>
160160
/// <param name="enumNumber">enumNumber.</param>
161161
/// <param name="outerEnum">outerEnum.</param>
162-
public EnumTest(EnumStringEnum? enumString = default(EnumStringEnum?), EnumStringRequiredEnum enumStringRequired = default(EnumStringRequiredEnum), EnumIntegerEnum? enumInteger = default(EnumIntegerEnum?), EnumNumberEnum? enumNumber = default(EnumNumberEnum?), OuterEnum outerEnum = default(OuterEnum))
162+
public EnumTest(EnumStringEnum? enumString = default(EnumStringEnum?), EnumStringRequiredEnum enumStringRequired = default(EnumStringRequiredEnum), EnumIntegerEnum? enumInteger = default(EnumIntegerEnum?), EnumNumberEnum? enumNumber = default(EnumNumberEnum?), OuterEnum? outerEnum = default(OuterEnum?))
163163
{
164164
this.EnumStringRequired = enumStringRequired;
165165
this.EnumString = enumString;

samples/client/petstore/csharp-netcore/OpenAPIClientCore/src/Org.OpenAPITools/Model/EnumTest.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ protected EnumTest() { }
159159
/// <param name="enumInteger">enumInteger.</param>
160160
/// <param name="enumNumber">enumNumber.</param>
161161
/// <param name="outerEnum">outerEnum.</param>
162-
public EnumTest(EnumStringEnum? enumString = default(EnumStringEnum?), EnumStringRequiredEnum enumStringRequired = default(EnumStringRequiredEnum), EnumIntegerEnum? enumInteger = default(EnumIntegerEnum?), EnumNumberEnum? enumNumber = default(EnumNumberEnum?), OuterEnum outerEnum = default(OuterEnum))
162+
public EnumTest(EnumStringEnum? enumString = default(EnumStringEnum?), EnumStringRequiredEnum enumStringRequired = default(EnumStringRequiredEnum), EnumIntegerEnum? enumInteger = default(EnumIntegerEnum?), EnumNumberEnum? enumNumber = default(EnumNumberEnum?), OuterEnum? outerEnum = default(OuterEnum?))
163163
{
164164
this.EnumStringRequired = enumStringRequired;
165165
this.EnumString = enumString;

samples/client/petstore/csharp/OpenAPIClient/docs/FakeApi.md

+31-31
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ No authorization required
9797

9898
## FakeOuterBooleanSerialize
9999

100-
> bool FakeOuterBooleanSerialize (bool body = null)
100+
> bool FakeOuterBooleanSerialize (bool? body = null)
101101
102102

103103

@@ -120,7 +120,7 @@ namespace Example
120120
{
121121
Configuration.Default.BasePath = "http://petstore.swagger.io:80/v2";
122122
var apiInstance = new FakeApi(Configuration.Default);
123-
var body = true; // bool | Input boolean as post body (optional)
123+
var body = true; // bool? | Input boolean as post body (optional)
124124
125125
try
126126
{
@@ -143,7 +143,7 @@ namespace Example
143143

144144
Name | Type | Description | Notes
145145
------------- | ------------- | ------------- | -------------
146-
**body** | **bool**| Input boolean as post body | [optional]
146+
**body** | **bool?**| Input boolean as post body | [optional]
147147

148148
### Return type
149149

@@ -245,7 +245,7 @@ No authorization required
245245

246246
## FakeOuterNumberSerialize
247247

248-
> decimal FakeOuterNumberSerialize (decimal body = null)
248+
> decimal FakeOuterNumberSerialize (decimal? body = null)
249249
250250

251251

@@ -268,7 +268,7 @@ namespace Example
268268
{
269269
Configuration.Default.BasePath = "http://petstore.swagger.io:80/v2";
270270
var apiInstance = new FakeApi(Configuration.Default);
271-
var body = 8.14; // decimal | Input number as post body (optional)
271+
var body = 8.14; // decimal? | Input number as post body (optional)
272272
273273
try
274274
{
@@ -291,7 +291,7 @@ namespace Example
291291

292292
Name | Type | Description | Notes
293293
------------- | ------------- | ------------- | -------------
294-
**body** | **decimal**| Input number as post body | [optional]
294+
**body** | **decimal?**| Input number as post body | [optional]
295295

296296
### Return type
297297

@@ -614,7 +614,7 @@ No authorization required
614614

615615
## TestEndpointParameters
616616

617-
> void TestEndpointParameters (decimal number, double _double, string patternWithoutDelimiter, byte[] _byte, int integer = null, int int32 = null, long int64 = null, float _float = null, string _string = null, System.IO.Stream binary = null, DateTime date = null, DateTime dateTime = null, string password = null, string callback = null)
617+
> void TestEndpointParameters (decimal number, double _double, string patternWithoutDelimiter, byte[] _byte, int? integer = null, int? int32 = null, long? int64 = null, float? _float = null, string _string = null, System.IO.Stream binary = null, DateTime? date = null, DateTime? dateTime = null, string password = null, string callback = null)
618618
619619
Fake endpoint for testing various parameters 假端點 偽のエンドポイント 가짜 엔드 포인트
620620

@@ -645,14 +645,14 @@ namespace Example
645645
var _double = 1.2D; // double | None
646646
var patternWithoutDelimiter = patternWithoutDelimiter_example; // string | None
647647
var _byte = BYTE_ARRAY_DATA_HERE; // byte[] | None
648-
var integer = 56; // int | None (optional)
649-
var int32 = 56; // int | None (optional)
650-
var int64 = 789; // long | None (optional)
651-
var _float = 3.4F; // float | None (optional)
648+
var integer = 56; // int? | None (optional)
649+
var int32 = 56; // int? | None (optional)
650+
var int64 = 789; // long? | None (optional)
651+
var _float = 3.4F; // float? | None (optional)
652652
var _string = _string_example; // string | None (optional)
653653
var binary = BINARY_DATA_HERE; // System.IO.Stream | None (optional)
654-
var date = 2013-10-20; // DateTime | None (optional)
655-
var dateTime = 2013-10-20T19:20:30+01:00; // DateTime | None (optional)
654+
var date = 2013-10-20; // DateTime? | None (optional)
655+
var dateTime = 2013-10-20T19:20:30+01:00; // DateTime? | None (optional)
656656
var password = password_example; // string | None (optional)
657657
var callback = callback_example; // string | None (optional)
658658
@@ -681,14 +681,14 @@ Name | Type | Description | Notes
681681
**_double** | **double**| None |
682682
**patternWithoutDelimiter** | **string**| None |
683683
**_byte** | **byte[]**| None |
684-
**integer** | **int**| None | [optional]
685-
**int32** | **int**| None | [optional]
686-
**int64** | **long**| None | [optional]
687-
**_float** | **float**| None | [optional]
684+
**integer** | **int?**| None | [optional]
685+
**int32** | **int?**| None | [optional]
686+
**int64** | **long?**| None | [optional]
687+
**_float** | **float?**| None | [optional]
688688
**_string** | **string**| None | [optional]
689689
**binary** | **System.IO.Stream**| None | [optional]
690-
**date** | **DateTime**| None | [optional]
691-
**dateTime** | **DateTime**| None | [optional]
690+
**date** | **DateTime?**| None | [optional]
691+
**dateTime** | **DateTime?**| None | [optional]
692692
**password** | **string**| None | [optional]
693693
**callback** | **string**| None | [optional]
694694

@@ -719,7 +719,7 @@ void (empty response body)
719719

720720
## TestEnumParameters
721721

722-
> void TestEnumParameters (List<string> enumHeaderStringArray = null, string enumHeaderString = null, List<string> enumQueryStringArray = null, string enumQueryString = null, int enumQueryInteger = null, double enumQueryDouble = null, List<string> enumFormStringArray = null, string enumFormString = null)
722+
> void TestEnumParameters (List<string> enumHeaderStringArray = null, string enumHeaderString = null, List<string> enumQueryStringArray = null, string enumQueryString = null, int? enumQueryInteger = null, double? enumQueryDouble = null, List<string> enumFormStringArray = null, string enumFormString = null)
723723
724724
To test enum parameters
725725

@@ -746,8 +746,8 @@ namespace Example
746746
var enumHeaderString = enumHeaderString_example; // string | Header parameter enum test (string) (optional) (default to -efg)
747747
var enumQueryStringArray = enumQueryStringArray_example; // List<string> | Query parameter enum test (string array) (optional)
748748
var enumQueryString = enumQueryString_example; // string | Query parameter enum test (string) (optional) (default to -efg)
749-
var enumQueryInteger = 56; // int | Query parameter enum test (double) (optional)
750-
var enumQueryDouble = 1.2D; // double | Query parameter enum test (double) (optional)
749+
var enumQueryInteger = 56; // int? | Query parameter enum test (double) (optional)
750+
var enumQueryDouble = 1.2D; // double? | Query parameter enum test (double) (optional)
751751
var enumFormStringArray = new List<string>(); // List<string> | Form parameter enum test (string array) (optional) (default to $)
752752
var enumFormString = enumFormString_example; // string | Form parameter enum test (string) (optional) (default to -efg)
753753
@@ -776,8 +776,8 @@ Name | Type | Description | Notes
776776
**enumHeaderString** | **string**| Header parameter enum test (string) | [optional] [default to -efg]
777777
**enumQueryStringArray** | **List&lt;string&gt;**| Query parameter enum test (string array) | [optional]
778778
**enumQueryString** | **string**| Query parameter enum test (string) | [optional] [default to -efg]
779-
**enumQueryInteger** | **int**| Query parameter enum test (double) | [optional]
780-
**enumQueryDouble** | **double**| Query parameter enum test (double) | [optional]
779+
**enumQueryInteger** | **int?**| Query parameter enum test (double) | [optional]
780+
**enumQueryDouble** | **double?**| Query parameter enum test (double) | [optional]
781781
**enumFormStringArray** | [**List&lt;string&gt;**](string.md)| Form parameter enum test (string array) | [optional] [default to $]
782782
**enumFormString** | **string**| Form parameter enum test (string) | [optional] [default to -efg]
783783

@@ -808,7 +808,7 @@ No authorization required
808808

809809
## TestGroupParameters
810810

811-
> void TestGroupParameters (int requiredStringGroup, bool requiredBooleanGroup, long requiredInt64Group, int stringGroup = null, bool booleanGroup = null, long int64Group = null)
811+
> void TestGroupParameters (int requiredStringGroup, bool requiredBooleanGroup, long requiredInt64Group, int? stringGroup = null, bool? booleanGroup = null, long? int64Group = null)
812812
813813
Fake endpoint to test group parameters (optional)
814814

@@ -834,9 +834,9 @@ namespace Example
834834
var requiredStringGroup = 56; // int | Required String in group parameters
835835
var requiredBooleanGroup = true; // bool | Required Boolean in group parameters
836836
var requiredInt64Group = 789; // long | Required Integer in group parameters
837-
var stringGroup = 56; // int | String in group parameters (optional)
838-
var booleanGroup = true; // bool | Boolean in group parameters (optional)
839-
var int64Group = 789; // long | Integer in group parameters (optional)
837+
var stringGroup = 56; // int? | String in group parameters (optional)
838+
var booleanGroup = true; // bool? | Boolean in group parameters (optional)
839+
var int64Group = 789; // long? | Integer in group parameters (optional)
840840
841841
try
842842
{
@@ -862,9 +862,9 @@ Name | Type | Description | Notes
862862
**requiredStringGroup** | **int**| Required String in group parameters |
863863
**requiredBooleanGroup** | **bool**| Required Boolean in group parameters |
864864
**requiredInt64Group** | **long**| Required Integer in group parameters |
865-
**stringGroup** | **int**| String in group parameters | [optional]
866-
**booleanGroup** | **bool**| Boolean in group parameters | [optional]
867-
**int64Group** | **long**| Integer in group parameters | [optional]
865+
**stringGroup** | **int?**| String in group parameters | [optional]
866+
**booleanGroup** | **bool?**| Boolean in group parameters | [optional]
867+
**int64Group** | **long?**| Integer in group parameters | [optional]
868868

869869
### Return type
870870

0 commit comments

Comments
 (0)