Skip to content

[BUG][CSHARP] Enums are always generated as strings, even if type is integer #21618

@alexaka1

Description

@alexaka1

Bug Report Checklist

  • Have you provided a full/minimal spec to reproduce the issue?
  • Have you validated the input using an OpenAPI validator?
  • Have you tested with the latest master to confirm the issue still exists?
  • Have you searched for related issues/PRs?
  • What's the actual output vs expected output?
  • [Optional] Sponsorship to speed up the bug fix or feature request (example)
Description

Enums are always generated to be strings. Even when the type is integer. This generates code like

public static MyEnum? FromStringOrDefault(string value)
        {
            if (value.Equals((0).ToString()))
                return MyEnum.None;

            if (value.Equals((1).ToString()))
                return MyEnum.Some;

            return null;
        }

which is on one hand silly (is actually needed to support floating point enums, valid in OpenAPI spec, but invalid in C#), on the other this actually causes fatal issues.

openapi-generator version

docker:openapitools/openapi-generator-cli:v7.14.0@sha256:a620610d9fabf7ce05310c648417ba168125aac2f4517580030e115921ac1a52

OpenAPI declaration file content or url
Openapi spec
{
  "openapi": "3.0.1",
  "info": {
    "title": "Example",
    "version": "v1"
  },
  "paths": {
    "/some/api": {
      "get": {
        "tags": [
          "Example"
        ],
        "description": "",
        "operationId": "ExampleApi",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json;charset=utf-8": {
                "schema": {
                  "$ref": "#/components/schemas/MyEnum"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "MyEnum": {
        "enum": [
          0,
          1
        ],
        "type": "integer",
        "description": "description",
        "format": "int32",
        "x-enum-varnames": [
          "None",
          "Some"
        ],
        "x-enum-descriptions": [
          "This is none",
          "this is some"
        ]
      }
    }
  },
  "tags": [
    {
      "name": "Example"
    }
  ]
}
Generation Details
 docker run --rm -v "${PWD}":/local openapitools/openapi-generator-cli:v7.14.0@sha256:a620610d9fabf7ce05310c648417ba168125aac2f4517580030e115921ac1a52 generate -i /local/openapi.json -g csharp -o /local/artifacts/out
Steps to reproduce

create the above json and run the above command

Related issues/PRs

#21204
#15204
#8458

at this point I stopped looking

Actual vs expected

The spec describes an integer enum, the code handles it like a string. Since the default c# mode is generichost which uses System.Text.Json, it uses Utf8JsonReader and for very low level optimisation reason the reader differentiates string values from number values.

The problematic code is in MyEnumJsonConverter which does:

public override MyEnum Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
    string? rawValue = reader.GetString(); // <--- this line throws exception

    MyEnum? result = rawValue == null
        ? null
        : MyEnumValueConverter.FromStringOrDefault(rawValue);

    if (result != null)
        return result.Value;

    throw new JsonException();
}

the exception:

System.InvalidOperationException: Cannot get the value of a token type 'Number' as a string.
   at System.Text.Json.ThrowHelper.ThrowInvalidOperationException_ExpectedString(JsonTokenType tokenType)
   at System.Text.Json.Utf8JsonReader.GetString()

The same principle applies to the Write method. It gets written as a string, which violates the spec!

Suggest a fix

The generator should respect the "type": "integer" in the openapi spec and handle the underlying type as such.

OR give us the option to tell it which type it should use.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions