Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@ public abstract class AbstractCSharpCodegen extends DefaultCodegen implements Co
protected Set<String> collectionTypes;
protected Set<String> mapTypes;

// true if support nullable type
protected boolean supportNullable = Boolean.FALSE;

// nullable type
protected Set<String> nullableType = new HashSet<String>();

private static final Logger LOGGER = LoggerFactory.getLogger(AbstractCSharpCodegen.class);

public AbstractCSharpCodegen() {
Expand Down Expand Up @@ -130,19 +136,26 @@ public AbstractCSharpCodegen() {
"String",
"string",
"bool?",
"bool",
"double?",
"double",
"decimal?",
"decimal",
"int?",
"int",
"long?",
"long",
"float?",
"float",
"byte[]",
"ICollection",
"Collection",
"List",
"Dictionary",
"DateTime?",
"DateTime",
"DateTimeOffset?",
"String",
"DataTimeOffset",
"Boolean",
"Double",
"Int32",
Expand All @@ -157,6 +170,7 @@ public AbstractCSharpCodegen() {
instantiationTypes.put("list", "List");
instantiationTypes.put("map", "Dictionary");


// Nullable types here assume C# 2 support is not part of base
typeMapping = new HashMap<String, String>();
typeMapping.put("string", "string");
Expand All @@ -176,6 +190,11 @@ public AbstractCSharpCodegen() {
typeMapping.put("map", "Dictionary");
typeMapping.put("object", "Object");
typeMapping.put("UUID", "Guid?");

// nullable type
nullableType = new HashSet<String>(
Arrays.asList("decimal", "bool", "int", "float", "long", "double", "DateTime", "Guid")
);
}

public void setReturnICollection(boolean returnICollection) {
Expand Down Expand Up @@ -209,8 +228,7 @@ public void useDateTimeOffset(boolean flag) {
this.useDateTimeOffsetFlag = flag;
if (flag) {
typeMapping.put("DateTime", "DateTimeOffset?");
}
else {
} else {
typeMapping.put("DateTime", "DateTime?");
}
}
Expand Down Expand Up @@ -421,8 +439,8 @@ private void postProcessEnumRefs(final Map<String, Object> models) {
}

for (Map.Entry<String, Object> entry : models.entrySet()) {
String swaggerName = entry.getKey();
CodegenModel model = ModelUtils.getModelByName(swaggerName, models);
String openAPIName = entry.getKey();
CodegenModel model = ModelUtils.getModelByName(openAPIName, models);
if (model != null) {
for (CodegenProperty var : model.allVars) {
if (enumRefs.containsKey(var.dataType)) {
Expand Down Expand Up @@ -483,7 +501,7 @@ private void postProcessEnumRefs(final Map<String, Object> models) {
}
}
} else {
LOGGER.warn("Expected to retrieve model %s by name, but no model was found. Check your -Dmodels inclusions.", swaggerName);
LOGGER.warn("Expected to retrieve model %s by name, but no model was found. Check your -Dmodels inclusions.", openAPIName);
}
}
}
Expand Down Expand Up @@ -573,28 +591,30 @@ public Map<String, Object> postProcessOperationsWithModels(Map<String, Object> o
}
}

for (CodegenParameter parameter: operation.allParams) {
CodegenModel model = null;
for(Object modelHashMap: allModels) {
CodegenModel codegenModel = ((HashMap<String, CodegenModel>) modelHashMap).get("model");
if (codegenModel.getClassname().equals(parameter.dataType)) {
model = codegenModel;
break;
if (!isSupportNullable()) {
for (CodegenParameter parameter : operation.allParams) {
CodegenModel model = null;
for (Object modelHashMap : allModels) {
CodegenModel codegenModel = ((HashMap<String, CodegenModel>) modelHashMap).get("model");
if (codegenModel.getClassname().equals(parameter.dataType)) {
model = codegenModel;
break;
}
}
}

if (model == null) {
// Primitive data types all come already marked
parameter.isNullable = true;
} else {
// Effectively mark enum models as enums and non-nullable
if (model.isEnum) {
parameter.isEnum = true;
parameter.allowableValues = model.allowableValues;
parameter.isPrimitiveType = true;
parameter.isNullable = false;
} else {
if (model == null) {
// Primitive data types all come already marked
parameter.isNullable = true;
} else {
// Effectively mark enum models as enums and non-nullable
if (model.isEnum) {
parameter.isEnum = true;
parameter.allowableValues = model.allowableValues;
parameter.isPrimitiveType = true;
parameter.isNullable = false;
} else {
parameter.isNullable = true;
}
}
}
}
Expand Down Expand Up @@ -792,6 +812,14 @@ protected boolean isReservedWord(String word) {
return reservedWords.contains(word);
}

public String getNullableType(Schema p, String type) {
if (languageSpecificPrimitives.contains(type)) {
return type;
} else {
return null;
}
}

@Override
public String getSchemaType(Schema p) {
String openAPIType = super.getSchemaType(p);
Expand All @@ -804,8 +832,9 @@ public String getSchemaType(Schema p) {

if (typeMapping.containsKey(openAPIType)) {
type = typeMapping.get(openAPIType);
if (languageSpecificPrimitives.contains(type)) {
return type;
String languageType = getNullableType(p, type);
if (languageType != null) {
return languageType;
}
} else {
type = openAPIType;
Expand Down Expand Up @@ -950,6 +979,14 @@ public void setInterfacePrefix(final String interfacePrefix) {
this.interfacePrefix = interfacePrefix;
}

public boolean isSupportNullable() {
return supportNullable;
}

public void setSupportNullable(final boolean supportNullable) {
this.supportNullable = supportNullable;
}

@Override
public String toEnumValue(String value, String datatype) {
// C# only supports enums as literals for int, int?, long, long?, byte, and byte?. All else must be treated as strings.
Expand Down Expand Up @@ -1011,7 +1048,9 @@ public String escapeUnsafeCharacters(String input) {
@Override
public boolean isDataTypeString(String dataType) {
// also treat double/decimal/float as "string" in enum so that the values (e.g. 2.8) get double-quoted
return "String".equalsIgnoreCase(dataType) || "double?".equals(dataType) || "decimal?".equals(dataType) || "float?".equals(dataType);
return "String".equalsIgnoreCase(dataType) ||
"double?".equals(dataType) || "decimal?".equals(dataType) || "float?".equals(dataType) ||
"double".equals(dataType) || "decimal".equals(dataType) || "float".equals(dataType);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -776,7 +776,6 @@ public String getNameUsingModelPropertyNaming(String name) {
}
}


public void setPackageName(String packageName) {
this.packageName = packageName;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.google.common.collect.ImmutableMap;
import com.samskivert.mustache.Mustache;

import io.swagger.v3.oas.models.media.ArraySchema;
import io.swagger.v3.oas.models.media.Schema;

import org.openapitools.codegen.CliOption;
Expand All @@ -32,6 +33,7 @@
import org.openapitools.codegen.CodegenProperty;
import org.openapitools.codegen.CodegenType;
import org.openapitools.codegen.SupportingFile;
import org.openapitools.codegen.utils.ModelUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -84,19 +86,39 @@ public class CSharpRefactorClientCodegen extends AbstractCSharpCodegen {
// By default, generated code is considered public
protected boolean nonPublicApi = Boolean.FALSE;


public CSharpRefactorClientCodegen() {
super();

// mapped non-nullable type without ?
typeMapping = new HashMap<String, String>();
typeMapping.put("string", "string");
typeMapping.put("binary", "byte[]");
typeMapping.put("ByteArray", "byte[]");
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("file", "System.IO.Stream");
typeMapping.put("array", "List");
typeMapping.put("list", "List");
typeMapping.put("map", "Dictionary");
typeMapping.put("object", "Object");
typeMapping.put("UUID", "Guid");

setSupportNullable(Boolean.TRUE);
hideGenerationTimestamp = Boolean.TRUE;
supportsInheritance = true;
modelTemplateFiles.put("model.mustache", ".cs");
apiTemplateFiles.put("api.mustache", ".cs");

modelDocTemplateFiles.put("model_doc.mustache", ".md");
apiDocTemplateFiles.put("api_doc.mustache", ".md");

embeddedTemplateDir = templateDir = "csharp-refactor";

hideGenerationTimestamp = Boolean.TRUE;

cliOptions.clear();

// CLI options
Expand Down Expand Up @@ -223,7 +245,6 @@ public void processOpts() {
setModelPropertyNaming((String) additionalProperties.get(CodegenConstants.MODEL_PROPERTY_NAMING));
}


if (isEmpty(apiPackage)) {
setApiPackage("Api");
}
Expand Down Expand Up @@ -609,6 +630,10 @@ public void setPackageGuid(String packageGuid) {
public void postProcessParameter(CodegenParameter parameter) {
postProcessPattern(parameter.pattern, parameter.vendorExtensions);
super.postProcessParameter(parameter);

if (!parameter.required && nullableType.contains(parameter.dataType)) { //optional
parameter.dataType = parameter.dataType + "?";
}
}

@Override
Expand Down Expand Up @@ -852,4 +877,17 @@ public Mustache.Compiler processCompiler(Mustache.Compiler compiler) {
// To avoid unexpected behaviors when options are passed programmatically such as { "supportsAsync": "" }
return super.processCompiler(compiler).emptyStringIsFalse(true);
}

@Override
public String getNullableType(Schema p, String type) {
if (languageSpecificPrimitives.contains(type)) {
if (isSupportNullable() && ModelUtils.isNullable(p) && nullableType.contains(type)) {
return type + "?";
} else {
return type;
}
} else {
return null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ namespace {{packageName}}.{{apiPackage}}
/// </summary>
{{>visibility}} interface {{interfacePrefix}}{{classname}} : {{interfacePrefix}}{{classname}}Sync{{#supportsAsync}}, {{interfacePrefix}}{{classname}}Async{{/supportsAsync}}
{

}

/// <summary>
Expand All @@ -94,7 +94,7 @@ namespace {{packageName}}.{{apiPackage}}
{{>visibility}} partial class {{classname}} : {{interfacePrefix}}{{classname}}
{
private {{packageName}}.Client.ExceptionFactory _exceptionFactory = (name, response) => null;

/// <summary>
/// Initializes a new instance of the <see cref="{{classname}}"/> class.
/// </summary>
Expand Down Expand Up @@ -151,7 +151,7 @@ namespace {{packageName}}.{{apiPackage}}
if(asyncClient == null) throw new ArgumentNullException("asyncClient");
{{/supportsAsync}}
if(configuration == null) throw new ArgumentNullException("configuration");

this.Client = client;
{{#supportsAsync}}
this.AsynchronousClient = asyncClient;
Expand Down Expand Up @@ -225,13 +225,15 @@ namespace {{packageName}}.{{apiPackage}}
public {{packageName}}.Client.ApiResponse<{{#returnType}} {{{returnType}}} {{/returnType}}{{^returnType}}Object{{/returnType}}> {{operationId}}WithHttpInfo ({{#allParams}}{{{dataType}}} {{paramName}}{{^required}}{{#optionalMethodArgument}} = null{{/optionalMethodArgument}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}})
{
{{#allParams}}
{{^isNullable}}
{{#required}}
// verify the required parameter '{{paramName}}' is set
if ({{paramName}} == null)
throw new {{packageName}}.Client.ApiException(400, "Missing required parameter '{{paramName}}' when calling {{classname}}->{{operationId}}");

{{/required}}
{{/isNullable}}
{{/allParams}}

{{packageName}}.Client.RequestOptions requestOptions = new {{packageName}}.Client.RequestOptions();

String[] @contentTypes = new String[] {
Expand Down Expand Up @@ -362,11 +364,14 @@ namespace {{packageName}}.{{apiPackage}}
public async System.Threading.Tasks.Task<{{packageName}}.Client.ApiResponse<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Object{{/returnType}}>> {{operationId}}AsyncWithHttpInfo ({{#allParams}}{{{dataType}}} {{paramName}}{{^required}}{{#optionalMethodArgument}} = null{{/optionalMethodArgument}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}})
{
{{#allParams}}
{{^isNullable}}
{{#required}}
// verify the required parameter '{{paramName}}' is set
if ({{paramName}} == null)
throw new {{packageName}}.Client.ApiException(400, "Missing required parameter '{{paramName}}' when calling {{classname}}->{{operationId}}");

{{/required}}
{{/isNullable}}
{{/allParams}}

{{packageName}}.Client.RequestOptions requestOptions = new {{packageName}}.Client.RequestOptions();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
{{#vars}}
{{^isInherited}}
{{^isReadOnly}}
{{^isNullable}}
{{#required}}
{{^isEnum}}
// to ensure "{{#lambda.camelcase_param}}{{name}}{{/lambda.camelcase_param}}" is required (not null)
Expand All @@ -74,6 +75,7 @@
this.{{name}} = {{#lambda.camelcase_param}}{{name}}{{/lambda.camelcase_param}};
{{/isEnum}}
{{/required}}
{{/isNullable}}
{{/isReadOnly}}
{{/isInherited}}
{{/vars}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**Code** | **int?** | | [optional]
**Code** | **int** | | [optional]
**Type** | **string** | | [optional]
**Message** | **string** | | [optional]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**ArrayArrayNumber** | **List&lt;List&lt;decimal?&gt;&gt;** | | [optional]
**ArrayArrayNumber** | **List&lt;List&lt;decimal&gt;&gt;** | | [optional]

[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

Loading