forked from loafle/openapi-generator-original
Add nullable annotation support to AspNetCoreServer (#9620)
* Add nullable annotation support to AspNetCoreServer * Adjust naming for compatability with PR #9235 by @dehl-labs
This commit is contained in:
@@ -19,6 +19,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|
||||
|licenseUrl|The URL of the license| |http://localhost|
|
||||
|modelClassModifier|Model Class Modifier can be nothing or partial| |partial|
|
||||
|newtonsoftVersion|Version for Microsoft.AspNetCore.Mvc.NewtonsoftJson for ASP.NET Core 3.0+| |3.0.0|
|
||||
|nullableReferenceTypes|Annotate Project with <Nullable>annotations</Nullable> and use ? annotation on all nullable attributes. Only supported on C# 8 / ASP.NET Core 3.0 or newer.| |false|
|
||||
|operationIsAsync|Set methods to async or sync (default).| |false|
|
||||
|operationModifier|Operation Modifier can be virtual or abstract|<dl><dt>**virtual**</dt><dd>Keep method virtual</dd><dt>**abstract**</dt><dd>Make method abstract</dd></dl>|virtual|
|
||||
|operationResultTask|Set methods result to Task<>.| |false|
|
||||
|
||||
@@ -60,6 +60,7 @@ public class AspNetCoreServerCodegen extends AbstractCSharpCodegen {
|
||||
public static final String USE_NEWTONSOFT = "useNewtonsoft";
|
||||
public static final String USE_DEFAULT_ROUTING = "useDefaultRouting";
|
||||
public static final String NEWTONSOFT_VERSION = "newtonsoftVersion";
|
||||
public static final String NULLABLE_REFERENCE_TYPES = "nullableReferenceTypes";
|
||||
|
||||
private String packageGuid = "{" + randomUUID().toString().toUpperCase(Locale.ROOT) + "}";
|
||||
private String userSecretsGuid = randomUUID().toString();
|
||||
@@ -84,6 +85,7 @@ public class AspNetCoreServerCodegen extends AbstractCSharpCodegen {
|
||||
private boolean useFrameworkReference = false;
|
||||
private boolean useNewtonsoft = true;
|
||||
private boolean useDefaultRouting = true;
|
||||
private boolean nullableReferenceTypes = false;
|
||||
private String newtonsoftVersion = "3.0.0";
|
||||
|
||||
public AspNetCoreServerCodegen() {
|
||||
@@ -249,6 +251,11 @@ public class AspNetCoreServerCodegen extends AbstractCSharpCodegen {
|
||||
"Use default routing for the ASP.NET Core version.",
|
||||
useDefaultRouting);
|
||||
|
||||
addSwitch(NULLABLE_REFERENCE_TYPES,
|
||||
"Annotate Project with <Nullable>annotations</Nullable> and use ? annotation on all nullable attributes. " +
|
||||
"Only supported on C# 8 / ASP.NET Core 3.0 or newer.",
|
||||
nullableReferenceTypes);
|
||||
|
||||
addOption(CodegenConstants.ENUM_NAME_SUFFIX,
|
||||
CodegenConstants.ENUM_NAME_SUFFIX_DESC,
|
||||
enumNameSuffix);
|
||||
@@ -366,6 +373,7 @@ public class AspNetCoreServerCodegen extends AbstractCSharpCodegen {
|
||||
setIsFramework();
|
||||
setUseNewtonsoft();
|
||||
setUseEndpointRouting();
|
||||
setNullableReferenceTypes();
|
||||
|
||||
supportingFiles.add(new SupportingFile("build.sh.mustache", "", "build.sh"));
|
||||
supportingFiles.add(new SupportingFile("build.bat.mustache", "", "build.bat"));
|
||||
@@ -520,7 +528,7 @@ public class AspNetCoreServerCodegen extends AbstractCSharpCodegen {
|
||||
@Override
|
||||
public String getNullableType(Schema p, String type) {
|
||||
if (languageSpecificPrimitives.contains(type)) {
|
||||
if (isSupportNullable() && ModelUtils.isNullable(p) && nullableType.contains(type)) {
|
||||
if (isSupportNullable() && ModelUtils.isNullable(p) && (nullableType.contains(type) || nullableReferenceTypes)) {
|
||||
return type + "?";
|
||||
} else {
|
||||
return type;
|
||||
@@ -649,6 +657,19 @@ public class AspNetCoreServerCodegen extends AbstractCSharpCodegen {
|
||||
}
|
||||
}
|
||||
|
||||
private void setNullableReferenceTypes() {
|
||||
if (additionalProperties.containsKey(NULLABLE_REFERENCE_TYPES)) {
|
||||
if (aspnetCoreVersion.getOptValue().startsWith("2.")) {
|
||||
LOGGER.warn("Nullable annotation are not supported in ASP.NET core version 2. Setting " + NULLABLE_REFERENCE_TYPES + " to false");
|
||||
additionalProperties.put(NULLABLE_REFERENCE_TYPES, false);
|
||||
} else {
|
||||
nullableReferenceTypes = convertPropertyToBooleanAndWriteBack(NULLABLE_REFERENCE_TYPES);
|
||||
}
|
||||
} else {
|
||||
additionalProperties.put(NULLABLE_REFERENCE_TYPES, nullableReferenceTypes);
|
||||
}
|
||||
}
|
||||
|
||||
private void setOperationIsAsync() {
|
||||
if (isLibrary) {
|
||||
operationIsAsync = false;
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<PreserveCompilationContext>true</PreserveCompilationContext>
|
||||
<Version>{{packageVersion}}</Version>
|
||||
{{#nullableReferenceTypes}}
|
||||
<Nullable>annotations</Nullable>
|
||||
{{/nullableReferenceTypes}}
|
||||
{{#isLibrary}}
|
||||
<OutputType>Library</OutputType>
|
||||
{{/isLibrary}}
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.openapitools.codegen.CodegenModel;
|
||||
import org.openapitools.codegen.CodegenProperty;
|
||||
import org.openapitools.codegen.DefaultCodegen;
|
||||
import org.openapitools.codegen.TestUtils;
|
||||
import org.openapitools.codegen.languages.AspNetCoreServerCodegen;
|
||||
import org.openapitools.codegen.languages.CSharpClientCodegen;
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.Test;
|
||||
@@ -264,6 +265,126 @@ public class CSharpModelTest {
|
||||
Assert.assertTrue(property3.isPrimitiveType);
|
||||
}
|
||||
|
||||
@Test(description = "convert a model with a nullable property without nullable annotation")
|
||||
public void nullablePropertyWithoutNullableReferenceTypesTest() {
|
||||
final Schema model = new Schema()
|
||||
.description("a sample model")
|
||||
.addProperties("id", new IntegerSchema().format(SchemaTypeUtil.INTEGER64_FORMAT).nullable(true))
|
||||
.addProperties("urls", new ArraySchema()
|
||||
.items(new StringSchema()).nullable(true))
|
||||
.addProperties("name", new StringSchema().nullable(true))
|
||||
.addProperties("subObject", new Schema().addProperties("name", new StringSchema()).nullable(true))
|
||||
.addRequiredItem("id");
|
||||
final DefaultCodegen codegen = new AspNetCoreServerCodegen();
|
||||
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(), 4);
|
||||
|
||||
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.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.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.required);
|
||||
Assert.assertTrue(property3.isPrimitiveType);
|
||||
|
||||
final CodegenProperty property4 = cm.vars.get(3);
|
||||
Assert.assertEquals(property4.baseName, "subObject");
|
||||
Assert.assertEquals(property4.dataType, "Object");
|
||||
Assert.assertEquals(property4.name, "SubObject");
|
||||
Assert.assertNull(property4.defaultValue);
|
||||
Assert.assertEquals(property4.baseType, "Object");
|
||||
Assert.assertFalse(property4.required);
|
||||
Assert.assertTrue(property4.isPrimitiveType);
|
||||
}
|
||||
|
||||
@Test(description = "convert a model with a nullable property using nullable annotation")
|
||||
public void nullablePropertyWithNullableReferenceTypesTest() {
|
||||
final Schema model = new Schema()
|
||||
.description("a sample model")
|
||||
.addProperties("id", new IntegerSchema().format(SchemaTypeUtil.INTEGER64_FORMAT).nullable(true))
|
||||
.addProperties("urls", new ArraySchema()
|
||||
.items(new StringSchema()).nullable(true))
|
||||
.addProperties("name", new StringSchema().nullable(true))
|
||||
.addProperties("subObject", new Schema().addProperties("name", new StringSchema()).nullable(true))
|
||||
.addRequiredItem("id");
|
||||
final DefaultCodegen codegen = new AspNetCoreServerCodegen();
|
||||
codegen.additionalProperties().put(AspNetCoreServerCodegen.NULLABLE_REFERENCE_TYPES, true);
|
||||
codegen.processOpts();
|
||||
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(), 4);
|
||||
|
||||
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.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.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.required);
|
||||
Assert.assertFalse(property3.isPrimitiveType);
|
||||
|
||||
final CodegenProperty property4 = cm.vars.get(3);
|
||||
Assert.assertEquals(property4.baseName, "subObject");
|
||||
Assert.assertEquals(property4.dataType, "Object?");
|
||||
Assert.assertEquals(property4.name, "SubObject");
|
||||
Assert.assertNull(property4.defaultValue);
|
||||
Assert.assertEquals(property4.baseType, "Object?");
|
||||
Assert.assertFalse(property4.required);
|
||||
Assert.assertFalse(property4.isPrimitiveType);
|
||||
}
|
||||
|
||||
@Test(description = "convert a model with list property")
|
||||
public void listPropertyTest() {
|
||||
final Schema model = new Schema()
|
||||
|
||||
Reference in New Issue
Block a user