[BUG] [aspnetcore] Unable to set primitive datatypes (with default spec) to the defaults of the primitive data type
Created by: flobuc
Description
If you specify a primitive datatype model property (like boolean or number) with a default value in the OpenAPI Spec, then it is not possible to set this value to the default value of the primitive datatype. Sounds crazy, and it drives you crazy. For example if you specify a boolean with the default "true", you are not able to send this boolean to false. Or more confusing, if you specify a number with a default other than 0 (e.g. 12) then you can't send this number to 0 (all other values are working).
openapi-generator version
5.x and also 6.0.x
generators
aspnetcore , maybe also other C# generators (csharp, csharp-netcore)
OpenAPI declaration
components:
schemas:
TESTOBJECT:
type: object
properties:
TESTPROP1:
type: boolean
description: a boolean with default true
default: true
TESTPROP2:
type: number
format: int32
description: a number with default 12
default: 12
Generation Details
powershell docker run --rm -v %OUTPUT_DIRECTORY%:/out -v %INTERFACE_DIRECTORY%:/specs openapitools/openapi-generator-cli generate -i specs/%INTERFACE_FILE% -o /out -g aspnetcore --additional-properties aspnetCoreVersion=5.0,buildTarget=library,operationModifier=abstract,packageName=%PACKAGE_NAME%,packageVersion=%INTERFACE_VERSION%,enumValueSuffix=,removeEnumValuePrefix=false
Request-Json
{
"TESTPROP1": false,
"TESTPROP2": 0
}
Actual model values
TESTOBJECT {
TESTPROP1: true
TESTPROP2: 12
}
Expected model values
TESTOBJECT {
TESTPROP1: false
TESTPROP2: 0
}
Suggest a fix
The problem is that the generator is not handling the default values. Actual generated TESTOBJECT class:
[DataMember(Name="TESTPROP1", EmitDefaultValue=false)]
public bool TESTPROP1{ get; set; } = true;
[DataMember(Name="TESTPROP2", EmitDefaultValue=false)]
public decimal TESTPROP2{ get; set; } = 12;
Per default "EmitDefaultValue=false". So there is no mapping false for TESTPROP1, because false is the default value for a boolean. So it is not possible to set TESTPROP1 to false. Also 0 is not mapped for TESTPROP2, because 0 is the default value for a decimal.
The fix would be to change modle.mustache to generate:
[DataMember(Name="TESTPROP1", EmitDefaultValue=false)]
[DefaultValue(true)]
public bool TESTPROP1{ get; set; } = true;
[DataMember(Name="TESTPROP2", EmitDefaultValue=false)]
[DefaultValue(12)]
public decimal TESTPROP2{ get; set; } = 12;
So the default-value for the primitive data type is changed, and false and 0 would be mapped. So far i can test it, it was working with .NET 5.0
Workaround
If it is possible to change the OpenAPI-Spec, then you can also set nullable=true
:
components:
schemas:
TESTOBJECT:
type: object
properties:
TESTPROP1:
type: boolean
description: a boolean with default true
default: true
nullable: true
TESTPROP2:
type: number
format: int32
description: a number with default 12
default: 12
nullable: true
With this spec the current 5.x generator generates EmitDefaultValue=true
for the properties, so that all values (default or not are always mapped). But this has the drawback, that the generated properties are then nullable:
[DataMember(Name="TESTPROP1", EmitDefaultValue=true)]
public bool? TESTPROP1{ get; set; } = true;
[DataMember(Name="TESTPROP2", EmitDefaultValue=true)]
public decimal? TESTPROP2{ get; set; } = 12;
Related issues/PRs
https://github.com/OpenAPITools/openapi-generator/issues/3274 https://github.com/OpenAPITools/openapi-generator/issues/4346 https://github.com/OpenAPITools/openapi-generator/issues/9071