Skip to content

Commit bda6bcc

Browse files
authored
[csharp] Support null types (#23260)
* support null types * remove unnecessary code
1 parent 153ac7b commit bda6bcc

64 files changed

Lines changed: 5308 additions & 0 deletions

Some content is hidden

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

.github/workflows/samples-dotnet10.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ jobs:
2727
- samples/client/petstore/csharp/generichost/latest/InlineEnumAnyOf
2828
- samples/client/petstore/csharp/generichost/latest/Tags
2929
- samples/client/petstore/csharp/generichost/latest/HelloWorld
30+
- samples/client/petstore/csharp/generichost/latest/NullTypes
3031
- samples/client/petstore/csharp/generichost/latest/OneOfList
3132
- samples/client/petstore/csharp/generichost/latest/UseDateTimeOffset
3233
- samples/client/petstore/csharp/generichost/net10/AllOf
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# for csharp generichost
2+
generatorName: csharp
3+
outputDir: samples/client/petstore/csharp/generichost/latest/NullTypes
4+
inputSpec: modules/openapi-generator/src/test/resources/3_1/csharp/null-types.yaml
5+
templateDir: modules/openapi-generator/src/main/resources/csharp
6+
additionalProperties:
7+
packageGuid: '{321C8C3F-0156-40C1-AE42-D59761FB9B6C}'
8+
modelPropertySorting: alphabetical
9+
operationParameterSorting: alphabetical

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,16 @@ protected ImmutableMap.Builder<String, Lambda> addMustacheLambdas() {
464464
@Override
465465
public void postProcessModelProperty(CodegenModel model, CodegenProperty property) {
466466
super.postProcessModelProperty(model, property);
467+
468+
// OAS 3.1: the 'null' type replaces the nullable flag. Convert null-typed properties
469+
// to a nullable Object so that C# code generation remains consistent.
470+
if ("null".equals(property.openApiType)) {
471+
property.dataType = typeMapping.get("object");
472+
property.datatypeWithEnum = property.dataType;
473+
property.baseType = typeMapping.get("object");
474+
property.isNullable = true;
475+
}
476+
467477
if (property.isInnerEnum && property.items != null) {
468478
// format maps of inner enums to include the classname eg: Dictionary<string, MapTest.InnerEnum>
469479
property.datatypeWithEnum = property.datatypeWithEnum.replace(property.items.datatypeWithEnum, model.classname + "." + property.items.datatypeWithEnum);
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
openapi: 3.1.0
2+
info:
3+
title: OAS 3.1 Null Type Test
4+
version: 1.0.0
5+
description: |
6+
Tests OAS 3.1 null type handling for C# codegen.
7+
In OAS 3.1, `nullable: true` was deprecated in favour of adding `null` to
8+
the list of allowed types. The C# generator must convert any occurrence of
9+
the bare `null` type to a nullable `Object`, and must strip `null` out of
10+
oneOf / anyOf composed schemas while marking the parent model as nullable.
11+
servers:
12+
- url: http://api.example.com/v1
13+
paths:
14+
/widgets/{id}:
15+
get:
16+
operationId: getWidget
17+
summary: Retrieve a widget
18+
parameters:
19+
- name: id
20+
in: path
21+
required: true
22+
schema:
23+
type: integer
24+
format: int64
25+
responses:
26+
'200':
27+
description: A widget
28+
content:
29+
application/json:
30+
schema:
31+
$ref: '#/components/schemas/Widget'
32+
'404':
33+
description: Not found
34+
components:
35+
schemas:
36+
37+
# ------------------------------------------------------------------
38+
# Case 1: a direct property with type 'null'.
39+
# Before the fix: this produced an unresolvable type and broken code.
40+
# After the fix: dataType => "Object", isNullable => true.
41+
# ------------------------------------------------------------------
42+
NullTypeDirect:
43+
type: object
44+
description: >
45+
Model with a property whose type is the bare 'null' type (OAS 3.1).
46+
The generator should treat this as a nullable Object.
47+
properties:
48+
id:
49+
type: integer
50+
format: int64
51+
alwaysNull:
52+
type: "null"
53+
description: >
54+
This property can only ever be null. In OAS 3.1 you express that
55+
with `type: null`. The C# generator must map this to a nullable
56+
Object.
57+
58+
# ------------------------------------------------------------------
59+
# Case 2: oneOf that includes the null type.
60+
# This is the idiomatic OAS 3.1 replacement for `nullable: true`.
61+
# The generator must mark the model as isNullable and drop the
62+
# phantom "Null" entry from the composed-schema lists.
63+
# ------------------------------------------------------------------
64+
ShapeOrNull:
65+
description: >
66+
A value that is either a Shape or null.
67+
OAS 3.1 expresses nullable via oneOf with a null member instead of
68+
the deprecated `nullable: true` attribute.
69+
oneOf:
70+
- type: "null"
71+
- $ref: '#/components/schemas/Shape'
72+
73+
# ------------------------------------------------------------------
74+
# Case 3: anyOf that includes the null type.
75+
# Same semantics as case 2 but using anyOf.
76+
# ------------------------------------------------------------------
77+
ColorOrNull:
78+
description: >
79+
A value that is either a Color, a string, or null.
80+
Demonstrates nullable anyOf in OAS 3.1.
81+
anyOf:
82+
- type: "null"
83+
- type: string
84+
- $ref: '#/components/schemas/Color'
85+
86+
# ------------------------------------------------------------------
87+
# Case 4: a well-rounded model that exercises all three patterns at
88+
# once, to serve as an end-to-end code-generation regression target.
89+
# ------------------------------------------------------------------
90+
Widget:
91+
type: object
92+
description: >
93+
A Widget demonstrating every OAS 3.1 null-type pattern that the
94+
C# generator must handle correctly.
95+
required:
96+
- id
97+
- name
98+
properties:
99+
id:
100+
type: integer
101+
format: int64
102+
description: Unique identifier.
103+
name:
104+
type: string
105+
description: Widget name.
106+
# Case 1 inline: property typed as bare null
107+
debugInfo:
108+
type: "null"
109+
description: >
110+
Always null in production. Maps to nullable Object in C#.
111+
# Case 2 inline: nullable via oneOf [ null, SomeRef ]
112+
shape:
113+
oneOf:
114+
- type: "null"
115+
- $ref: '#/components/schemas/Shape'
116+
description: Optional shape; null when no shape is assigned.
117+
# Case 3 inline: nullable via anyOf [ null, string ]
118+
color:
119+
anyOf:
120+
- type: "null"
121+
- type: string
122+
description: Optional CSS color string; null when not set.
123+
124+
Shape:
125+
type: object
126+
description: A geometric shape.
127+
required:
128+
- shapeType
129+
properties:
130+
shapeType:
131+
type: string
132+
description: Discriminator value.
133+
area:
134+
type: number
135+
format: double
136+
description: Area in square units.
137+
138+
Color:
139+
type: object
140+
description: An RGB color triplet.
141+
properties:
142+
r:
143+
type: integer
144+
minimum: 0
145+
maximum: 255
146+
g:
147+
type: integer
148+
minimum: 0
149+
maximum: 255
150+
b:
151+
type: integer
152+
minimum: 0
153+
maximum: 255

0 commit comments

Comments
 (0)