Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
1 change: 1 addition & 0 deletions .github/workflows/samples-dotnet10.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ jobs:
- samples/client/petstore/csharp/generichost/latest/InlineEnumAnyOf
- samples/client/petstore/csharp/generichost/latest/Tags
- samples/client/petstore/csharp/generichost/latest/HelloWorld
- samples/client/petstore/csharp/generichost/latest/NullTypes
- samples/client/petstore/csharp/generichost/latest/OneOfList
- samples/client/petstore/csharp/generichost/net10/AllOf
- samples/client/petstore/csharp/generichost/net10/AnyOf
Expand Down
9 changes: 9 additions & 0 deletions bin/configs/csharp-generichost-latest-nullTypes.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# for csharp generichost
generatorName: csharp
outputDir: samples/client/petstore/csharp/generichost/latest/NullTypes
inputSpec: modules/openapi-generator/src/test/resources/3_1/csharp/null-types.yaml
templateDir: modules/openapi-generator/src/main/resources/csharp
additionalProperties:
packageGuid: '{321C8C3F-0156-40C1-AE42-D59761FB9B6C}'
modelPropertySorting: alphabetical
operationParameterSorting: alphabetical
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,16 @@ protected ImmutableMap.Builder<String, Lambda> addMustacheLambdas() {
@Override
public void postProcessModelProperty(CodegenModel model, CodegenProperty property) {
super.postProcessModelProperty(model, property);

// OAS 3.1: the 'null' type replaces the nullable flag. Convert null-typed properties
// to a nullable Object so that C# code generation remains consistent.
if ("null".equals(property.openApiType)) {
property.dataType = typeMapping.get("object");
property.datatypeWithEnum = property.dataType;
property.baseType = typeMapping.get("object");
property.isNullable = true;
}

if (property.isInnerEnum && property.items != null) {
// format maps of inner enums to include the classname eg: Dictionary<string, MapTest.InnerEnum>
property.datatypeWithEnum = property.datatypeWithEnum.replace(property.items.datatypeWithEnum, model.classname + "." + property.items.datatypeWithEnum);
Expand Down Expand Up @@ -539,6 +549,23 @@ public ModelsMap postProcessModels(ModelsMap objs) {
for (ModelMap mo : objs.getModels()) {
CodegenModel cm = mo.getModel();

// OAS 3.1: if oneOf or anyOf contains the 'null' type, mark the model as nullable
// and remove the 'Null' pseudo-type from the composed schema lists.
if (cm.oneOf != null && !cm.oneOf.isEmpty() && cm.oneOf.remove("Null")) {
cm.isNullable = true;
}
if (cm.anyOf != null && !cm.anyOf.isEmpty() && cm.anyOf.remove("Null")) {
cm.isNullable = true;
}
if (cm.getComposedSchemas() != null) {
if (cm.getComposedSchemas().getOneOf() != null) {
cm.getComposedSchemas().getOneOf().removeIf(o -> "Null".equals(o.dataType));
}
if (cm.getComposedSchemas().getAnyOf() != null) {
cm.getComposedSchemas().getAnyOf().removeIf(o -> "Null".equals(o.dataType));
}
}

if (cm.getComposedSchemas() != null) {
List<CodegenProperty> oneOf = cm.getComposedSchemas().getOneOf();
if (oneOf != null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
openapi: 3.1.0
info:
title: OAS 3.1 Null Type Test
version: 1.0.0
description: |
Tests OAS 3.1 null type handling for C# codegen.
In OAS 3.1, `nullable: true` was deprecated in favour of adding `null` to
the list of allowed types. The C# generator must convert any occurrence of
the bare `null` type to a nullable `Object`, and must strip `null` out of
oneOf / anyOf composed schemas while marking the parent model as nullable.
servers:
- url: http://api.example.com/v1
paths:
/widgets/{id}:
get:
operationId: getWidget
summary: Retrieve a widget
parameters:
- name: id
in: path
required: true
schema:
type: integer
format: int64
responses:
'200':
description: A widget
content:
application/json:
schema:
$ref: '#/components/schemas/Widget'
'404':
description: Not found
components:
schemas:

# ------------------------------------------------------------------
# Case 1: a direct property with type 'null'.
# Before the fix: this produced an unresolvable type and broken code.
# After the fix: dataType => "Object", isNullable => true.
# ------------------------------------------------------------------
NullTypeDirect:
type: object
description: >
Model with a property whose type is the bare 'null' type (OAS 3.1).
The generator should treat this as a nullable Object.
properties:
id:
type: integer
format: int64
alwaysNull:
type: "null"
description: >
This property can only ever be null. In OAS 3.1 you express that
with `type: null`. The C# generator must map this to a nullable
Object.

# ------------------------------------------------------------------
# Case 2: oneOf that includes the null type.
# This is the idiomatic OAS 3.1 replacement for `nullable: true`.
# The generator must mark the model as isNullable and drop the
# phantom "Null" entry from the composed-schema lists.
# ------------------------------------------------------------------
ShapeOrNull:
description: >
A value that is either a Shape or null.
OAS 3.1 expresses nullable via oneOf with a null member instead of
the deprecated `nullable: true` attribute.
oneOf:
- type: "null"
- $ref: '#/components/schemas/Shape'

# ------------------------------------------------------------------
# Case 3: anyOf that includes the null type.
# Same semantics as case 2 but using anyOf.
# ------------------------------------------------------------------
ColorOrNull:
description: >
A value that is either a Color, a string, or null.
Demonstrates nullable anyOf in OAS 3.1.
anyOf:
- type: "null"
- type: string
- $ref: '#/components/schemas/Color'

# ------------------------------------------------------------------
# Case 4: a well-rounded model that exercises all three patterns at
# once, to serve as an end-to-end code-generation regression target.
# ------------------------------------------------------------------
Widget:
type: object
description: >
A Widget demonstrating every OAS 3.1 null-type pattern that the
C# generator must handle correctly.
required:
- id
- name
properties:
id:
type: integer
format: int64
description: Unique identifier.
name:
type: string
description: Widget name.
# Case 1 inline: property typed as bare null
debugInfo:
type: "null"
description: >
Always null in production. Maps to nullable Object in C#.
# Case 2 inline: nullable via oneOf [ null, SomeRef ]
shape:
oneOf:
- type: "null"
- $ref: '#/components/schemas/Shape'
description: Optional shape; null when no shape is assigned.
# Case 3 inline: nullable via anyOf [ null, string ]
color:
anyOf:
- type: "null"
- type: string
description: Optional CSS color string; null when not set.

Shape:
type: object
description: A geometric shape.
required:
- shapeType
properties:
shapeType:
type: string
description: Discriminator value.
area:
type: number
format: double
description: Area in square units.

Color:
type: object
description: An RGB color triplet.
properties:
r:
type: integer
minimum: 0
maximum: 255
g:
type: integer
minimum: 0
maximum: 255
b:
type: integer
minimum: 0
maximum: 255
Loading
Loading