forked from loafle/openapi-generator-original
Csharp nullable support (#2528)
* Added nullable-type support to CSharpClientCodegen Overrode getNullableType method Added non-nullable type varients to 'typeMapping' collection Removed nullable type shorthand from api template * Added testcase for nullable support Set Integer property to not be nullable. Expect no '?' in baseType Set String property to be nullable. Expect no '?' in baseType * Implemented changes to 'csharp' generator from PR #1819.
This commit is contained in:
+26
@@ -86,6 +86,18 @@ public class CSharpClientCodegen extends AbstractCSharpCodegen {
|
||||
|
||||
cliOptions.clear();
|
||||
|
||||
typeMapping.put("boolean", "bool");
|
||||
typeMapping.put("integer", "int");
|
||||
typeMapping.put("float", "float");
|
||||
typeMapping.put("long", "long");
|
||||
typeMapping.put("double", "double");
|
||||
typeMapping.put("number", "decimal");
|
||||
typeMapping.put("DateTime", "DateTime");
|
||||
typeMapping.put("date", "DateTime");
|
||||
typeMapping.put("UUID", "Guid");
|
||||
|
||||
setSupportNullable(Boolean.TRUE);
|
||||
|
||||
// CLI options
|
||||
addOption(CodegenConstants.PACKAGE_NAME,
|
||||
"C# package name (convention: Title.Case).",
|
||||
@@ -862,4 +874,18 @@ public class CSharpClientCodegen extends AbstractCSharpCodegen {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNullableType(Schema p, String type) {
|
||||
boolean isNullableExpected = p.getNullable() == null || (p.getNullable() != null && p.getNullable());
|
||||
|
||||
if (isNullableExpected && languageSpecificPrimitives.contains(type + "?")) {
|
||||
return type + "?";
|
||||
} else if (languageSpecificPrimitives.contains(type)) {
|
||||
return type;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace {{packageName}}.{{apiPackage}}
|
||||
/// <exception cref="{{packageName}}.Client.ApiException">Thrown when fails to make API call</exception>
|
||||
{{#allParams}}/// <param name="{{paramName}}">{{description}}{{^required}} (optional{{#defaultValue}}, default to {{.}}{{/defaultValue}}){{/required}}</param>
|
||||
{{/allParams}}/// <returns>{{#returnType}}{{returnType}}{{/returnType}}</returns>
|
||||
{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}void{{/returnType}} {{operationId}} ({{#allParams}}{{{dataType}}}{{^required}}{{^isNullable}}?{{/isNullable}}{{/required}} {{paramName}}{{^required}}{{#optionalMethodArgument}} = null{{/optionalMethodArgument}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}});
|
||||
{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}void{{/returnType}} {{operationId}} ({{#allParams}}{{{dataType}}} {{paramName}}{{^required}}{{#optionalMethodArgument}} = null{{/optionalMethodArgument}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}});
|
||||
|
||||
/// <summary>
|
||||
/// {{summary}}
|
||||
@@ -43,7 +43,7 @@ namespace {{packageName}}.{{apiPackage}}
|
||||
/// <exception cref="{{packageName}}.Client.ApiException">Thrown when fails to make API call</exception>
|
||||
{{#allParams}}/// <param name="{{paramName}}">{{description}}{{^required}} (optional{{#defaultValue}}, default to {{.}}{{/defaultValue}}){{/required}}</param>
|
||||
{{/allParams}}/// <returns>ApiResponse of {{#returnType}}{{returnType}}{{/returnType}}{{^returnType}}Object(void){{/returnType}}</returns>
|
||||
ApiResponse<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Object{{/returnType}}> {{operationId}}WithHttpInfo ({{#allParams}}{{{dataType}}}{{^required}}{{^isNullable}}?{{/isNullable}}{{/required}} {{paramName}}{{^required}}{{#optionalMethodArgument}} = null{{/optionalMethodArgument}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}});
|
||||
ApiResponse<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Object{{/returnType}}> {{operationId}}WithHttpInfo ({{#allParams}}{{{dataType}}} {{paramName}}{{^required}}{{#optionalMethodArgument}} = null{{/optionalMethodArgument}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}});
|
||||
{{/operation}}
|
||||
#endregion Synchronous Operations
|
||||
{{#supportsAsync}}
|
||||
@@ -58,7 +58,7 @@ namespace {{packageName}}.{{apiPackage}}
|
||||
/// <exception cref="{{packageName}}.Client.ApiException">Thrown when fails to make API call</exception>
|
||||
{{#allParams}}/// <param name="{{paramName}}">{{description}}{{^required}} (optional{{#defaultValue}}, default to {{.}}{{/defaultValue}}){{/required}}</param>
|
||||
{{/allParams}}/// <returns>Task of {{#returnType}}{{returnType}}{{/returnType}}{{^returnType}}void{{/returnType}}</returns>
|
||||
{{#returnType}}System.Threading.Tasks.Task<{{{returnType}}}>{{/returnType}}{{^returnType}}System.Threading.Tasks.Task{{/returnType}} {{operationId}}Async ({{#allParams}}{{{dataType}}}{{^required}}{{^isNullable}}?{{/isNullable}}{{/required}} {{paramName}}{{^required}}{{#optionalMethodArgument}} = null{{/optionalMethodArgument}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}});
|
||||
{{#returnType}}System.Threading.Tasks.Task<{{{returnType}}}>{{/returnType}}{{^returnType}}System.Threading.Tasks.Task{{/returnType}} {{operationId}}Async ({{#allParams}}{{{dataType}}} {{paramName}}{{^required}}{{#optionalMethodArgument}} = null{{/optionalMethodArgument}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}});
|
||||
|
||||
/// <summary>
|
||||
/// {{summary}}
|
||||
@@ -69,7 +69,7 @@ namespace {{packageName}}.{{apiPackage}}
|
||||
/// <exception cref="{{packageName}}.Client.ApiException">Thrown when fails to make API call</exception>
|
||||
{{#allParams}}/// <param name="{{paramName}}">{{description}}{{^required}} (optional{{#defaultValue}}, default to {{.}}{{/defaultValue}}){{/required}}</param>
|
||||
{{/allParams}}/// <returns>Task of ApiResponse{{#returnType}} ({{returnType}}){{/returnType}}</returns>
|
||||
System.Threading.Tasks.Task<ApiResponse<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Object{{/returnType}}>> {{operationId}}AsyncWithHttpInfo ({{#allParams}}{{{dataType}}}{{^required}}{{^isNullable}}?{{/isNullable}}{{/required}} {{paramName}}{{^required}}{{#optionalMethodArgument}} = null{{/optionalMethodArgument}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}});
|
||||
System.Threading.Tasks.Task<ApiResponse<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Object{{/returnType}}>> {{operationId}}AsyncWithHttpInfo ({{#allParams}}{{{dataType}}} {{paramName}}{{^required}}{{#optionalMethodArgument}} = null{{/optionalMethodArgument}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}});
|
||||
{{/operation}}
|
||||
#endregion Asynchronous Operations
|
||||
{{/supportsAsync}}
|
||||
@@ -190,7 +190,7 @@ namespace {{packageName}}.{{apiPackage}}
|
||||
/// <exception cref="{{packageName}}.Client.ApiException">Thrown when fails to make API call</exception>
|
||||
{{#allParams}}/// <param name="{{paramName}}">{{description}}{{^required}} (optional{{#defaultValue}}, default to {{.}}{{/defaultValue}}){{/required}}</param>
|
||||
{{/allParams}}/// <returns>{{#returnType}}{{returnType}}{{/returnType}}</returns>
|
||||
public {{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}void{{/returnType}} {{operationId}} ({{#allParams}}{{{dataType}}}{{^required}}{{^isNullable}}?{{/isNullable}}{{/required}} {{paramName}}{{^required}}{{#optionalMethodArgument}} = null{{/optionalMethodArgument}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}})
|
||||
public {{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}void{{/returnType}} {{operationId}} ({{#allParams}}{{{dataType}}} {{paramName}}{{^required}}{{#optionalMethodArgument}} = null{{/optionalMethodArgument}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}})
|
||||
{
|
||||
{{#returnType}}ApiResponse<{{{returnType}}}> localVarResponse = {{operationId}}WithHttpInfo({{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}});
|
||||
return localVarResponse.Data;{{/returnType}}{{^returnType}}{{operationId}}WithHttpInfo({{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}});{{/returnType}}
|
||||
@@ -202,7 +202,7 @@ namespace {{packageName}}.{{apiPackage}}
|
||||
/// <exception cref="{{packageName}}.Client.ApiException">Thrown when fails to make API call</exception>
|
||||
{{#allParams}}/// <param name="{{paramName}}">{{description}}{{^required}} (optional{{#defaultValue}}, default to {{.}}{{/defaultValue}}){{/required}}</param>
|
||||
{{/allParams}}/// <returns>ApiResponse of {{#returnType}}{{returnType}}{{/returnType}}{{^returnType}}Object(void){{/returnType}}</returns>
|
||||
public ApiResponse<{{#returnType}} {{{returnType}}} {{/returnType}}{{^returnType}}Object{{/returnType}}> {{operationId}}WithHttpInfo ({{#allParams}}{{{dataType}}}{{^required}}{{^isNullable}}?{{/isNullable}}{{/required}} {{paramName}}{{^required}}{{#optionalMethodArgument}} = null{{/optionalMethodArgument}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}})
|
||||
public ApiResponse<{{#returnType}} {{{returnType}}} {{/returnType}}{{^returnType}}Object{{/returnType}}> {{operationId}}WithHttpInfo ({{#allParams}}{{{dataType}}} {{paramName}}{{^required}}{{#optionalMethodArgument}} = null{{/optionalMethodArgument}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}})
|
||||
{
|
||||
{{#allParams}}
|
||||
{{#required}}
|
||||
@@ -325,7 +325,7 @@ namespace {{packageName}}.{{apiPackage}}
|
||||
/// <exception cref="{{packageName}}.Client.ApiException">Thrown when fails to make API call</exception>
|
||||
{{#allParams}}/// <param name="{{paramName}}">{{description}}{{^required}} (optional{{#defaultValue}}, default to {{.}}{{/defaultValue}}){{/required}}</param>
|
||||
{{/allParams}}/// <returns>Task of {{#returnType}}{{returnType}}{{/returnType}}{{^returnType}}void{{/returnType}}</returns>
|
||||
{{#returnType}}public async System.Threading.Tasks.Task<{{{returnType}}}>{{/returnType}}{{^returnType}}public async System.Threading.Tasks.Task{{/returnType}} {{operationId}}Async ({{#allParams}}{{{dataType}}}{{^required}}{{^isNullable}}?{{/isNullable}}{{/required}} {{paramName}}{{^required}}{{#optionalMethodArgument}} = null{{/optionalMethodArgument}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}})
|
||||
{{#returnType}}public async System.Threading.Tasks.Task<{{{returnType}}}>{{/returnType}}{{^returnType}}public async System.Threading.Tasks.Task{{/returnType}} {{operationId}}Async ({{#allParams}}{{{dataType}}} {{paramName}}{{^required}}{{#optionalMethodArgument}} = null{{/optionalMethodArgument}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}})
|
||||
{
|
||||
{{#returnType}}ApiResponse<{{{returnType}}}> localVarResponse = await {{operationId}}AsyncWithHttpInfo({{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}});
|
||||
return localVarResponse.Data;{{/returnType}}{{^returnType}}await {{operationId}}AsyncWithHttpInfo({{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}});{{/returnType}}
|
||||
@@ -338,7 +338,7 @@ namespace {{packageName}}.{{apiPackage}}
|
||||
/// <exception cref="{{packageName}}.Client.ApiException">Thrown when fails to make API call</exception>
|
||||
{{#allParams}}/// <param name="{{paramName}}">{{description}}{{^required}} (optional{{#defaultValue}}, default to {{.}}{{/defaultValue}}){{/required}}</param>
|
||||
{{/allParams}}/// <returns>Task of ApiResponse{{#returnType}} ({{returnType}}){{/returnType}}</returns>
|
||||
public async System.Threading.Tasks.Task<ApiResponse<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Object{{/returnType}}>> {{operationId}}AsyncWithHttpInfo ({{#allParams}}{{{dataType}}}{{^required}}{{^isNullable}}?{{/isNullable}}{{/required}} {{paramName}}{{^required}}{{#optionalMethodArgument}} = null{{/optionalMethodArgument}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}})
|
||||
public async System.Threading.Tasks.Task<ApiResponse<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Object{{/returnType}}>> {{operationId}}AsyncWithHttpInfo ({{#allParams}}{{{dataType}}} {{paramName}}{{^required}}{{#optionalMethodArgument}} = null{{/optionalMethodArgument}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}})
|
||||
{
|
||||
{{#allParams}}
|
||||
{{#required}}
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
{{#description}}
|
||||
/// <value>{{description}}</value>
|
||||
{{/description}}
|
||||
[DataMember(Name="{{baseName}}", EmitDefaultValue={{emitDefaultValue}})]
|
||||
[DataMember(Name="{{baseName}}", EmitDefaultValue={{#isNullable}}true{{/isNullable}}{{^isNullable}}{{emitDefaultValue}}{{/isNullable}})]
|
||||
public {{#complexType}}{{{complexType}}}{{/complexType}}{{^complexType}}{{{datatypeWithEnum}}}{{/complexType}}{{^isContainer}}{{^required}}?{{/required}}{{/isContainer}} {{name}} { get; set; }
|
||||
{{/isEnum}}
|
||||
{{/vars}}
|
||||
@@ -70,7 +70,11 @@
|
||||
{
|
||||
this.{{name}} = {{#lambda.camelcase_param}}{{name}}{{/lambda.camelcase_param}};
|
||||
}
|
||||
|
||||
{{/required}}
|
||||
{{#isNullable}}
|
||||
this.{{name}} = {{#lambda.camelcase_param}}{{name}}{{/lambda.camelcase_param}};
|
||||
{{/isNullable}}
|
||||
{{/isReadOnly}}
|
||||
{{/isInherited}}
|
||||
{{/vars}}
|
||||
@@ -104,7 +108,7 @@ this.{{name}} = {{#lambda.camelcase_param}}{{name}}{{/lambda.camelcase_param}};
|
||||
/// {{^description}}Gets or Sets {{{name}}}{{/description}}{{#description}}{{description}}{{/description}}
|
||||
/// </summary>{{#description}}
|
||||
/// <value>{{description}}</value>{{/description}}
|
||||
[DataMember(Name="{{baseName}}", EmitDefaultValue={{emitDefaultValue}})]{{#isDate}}
|
||||
[DataMember(Name="{{baseName}}", EmitDefaultValue={{#isNullable}}true{{/isNullable}}{{^isNullable}}{{emitDefaultValue}}{{/isNullable}})]{{#isDate}}
|
||||
[JsonConverter(typeof(OpenAPIDateConverter))]{{/isDate}}
|
||||
public {{{dataType}}} {{name}} { get; {{#isReadOnly}}private {{/isReadOnly}}set; }
|
||||
{{/isEnum}}
|
||||
|
||||
+52
@@ -169,6 +169,58 @@ public class CSharpModelTest {
|
||||
Assert.assertFalse(property3.required);
|
||||
}
|
||||
|
||||
@Test(description = "convert a model with a non-nullable property")
|
||||
public void nonNullablePropertyTest() {
|
||||
final Schema model = new Schema()
|
||||
.description("a sample model")
|
||||
.addProperties("id", new IntegerSchema().format(SchemaTypeUtil.INTEGER64_FORMAT).nullable(false))
|
||||
.addProperties("urls", new ArraySchema()
|
||||
.items(new StringSchema()))
|
||||
.addProperties("name", new StringSchema().nullable(true))
|
||||
.addRequiredItem("id");
|
||||
final DefaultCodegen codegen = new CSharpClientCodegen();
|
||||
OpenAPI openAPI = TestUtils.createOpenAPIWithOneSchema("sample", model);
|
||||
codegen.setOpenAPI(openAPI);
|
||||
final CodegenModel cm = codegen.fromModel("sample", model);
|
||||
|
||||
Assert.assertEquals(cm.name, "sample");
|
||||
Assert.assertEquals(cm.classname, "Sample");
|
||||
Assert.assertEquals(cm.description, "a sample model");
|
||||
Assert.assertEquals(cm.vars.size(), 3);
|
||||
|
||||
final CodegenProperty property1 = cm.vars.get(0);
|
||||
Assert.assertEquals(property1.baseName, "id");
|
||||
Assert.assertEquals(property1.dataType, "long");
|
||||
Assert.assertEquals(property1.name, "Id");
|
||||
Assert.assertNull(property1.defaultValue);
|
||||
Assert.assertEquals(property1.baseType, "long");
|
||||
Assert.assertTrue(property1.hasMore);
|
||||
Assert.assertTrue(property1.required);
|
||||
Assert.assertTrue(property1.isPrimitiveType);
|
||||
|
||||
final CodegenProperty property2 = cm.vars.get(1);
|
||||
Assert.assertEquals(property2.baseName, "urls");
|
||||
Assert.assertEquals(property2.dataType, "List<string>");
|
||||
Assert.assertEquals(property2.name, "Urls");
|
||||
Assert.assertNull(property2.defaultValue);
|
||||
Assert.assertEquals(property2.baseType, "List");
|
||||
Assert.assertTrue(property2.hasMore);
|
||||
Assert.assertEquals(property2.containerType, "array");
|
||||
Assert.assertFalse(property2.required);
|
||||
Assert.assertTrue(property2.isPrimitiveType);
|
||||
Assert.assertTrue(property2.isContainer);
|
||||
|
||||
final CodegenProperty property3 = cm.vars.get(2);
|
||||
Assert.assertEquals(property3.baseName, "name");
|
||||
Assert.assertEquals(property3.dataType, "string");
|
||||
Assert.assertEquals(property3.name, "Name");
|
||||
Assert.assertNull(property3.defaultValue);
|
||||
Assert.assertEquals(property3.baseType, "string");
|
||||
Assert.assertFalse(property3.hasMore);
|
||||
Assert.assertFalse(property3.required);
|
||||
Assert.assertTrue(property3.isPrimitiveType);
|
||||
}
|
||||
|
||||
@Test(description = "convert a model with list property")
|
||||
public void listPropertyTest() {
|
||||
final Schema model = new Schema()
|
||||
|
||||
+12
@@ -8,6 +8,7 @@ using Org.OpenAPITools.Api;
|
||||
using Org.OpenAPITools.Model;
|
||||
using Org.OpenAPITools.Client;
|
||||
using System.Reflection;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Org.OpenAPITools.Test
|
||||
{
|
||||
@@ -101,6 +102,17 @@ namespace Org.OpenAPITools.Test
|
||||
// TODO: unit test for the property 'Status'
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test serialization
|
||||
/// </summary>
|
||||
[Test()]
|
||||
public void TestSerialization()
|
||||
{
|
||||
// create pet
|
||||
Pet p1 = new Pet(name: "Csharp test", photoUrls: new List<string> { "http://petstore.com/csharp_test" });
|
||||
Assert.AreEqual("{\"name\":\"Csharp test\",\"photoUrls\":[\"http://petstore.com/csharp_test\"]}", JsonConvert.SerializeObject(p1));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test Equal
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user