Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Csharp Client not generating valid enums #5352

Open
chidionuekwusi opened this issue Apr 7, 2017 · 5 comments
Open

Csharp Client not generating valid enums #5352

chidionuekwusi opened this issue Apr 7, 2017 · 5 comments

Comments

@chidionuekwusi
Copy link

chidionuekwusi commented Apr 7, 2017

Description

CSharp client generation does not generate valid c# for enums with int values. eg
enum Sex {
None=0,
Male=1,
Female=2
}

After running generate command with the below config

{ "packageName":"{ProjectName}"}

The resultant code:
[JsonConverter(typeof(StringEnumConverter))]
public enum Sex
{

    /// <summary>
    /// Enum NUMBER_0 for 0
    /// </summary>
    [EnumMember(Value = 0)]
    NUMBER_0,
    
    /// <summary>
    /// Enum NUMBER_1 for 1
    /// </summary>
    [EnumMember(Value = 1)]
    NUMBER_1,
    
    /// <summary>
    /// Enum NUMBER_2 for 2
    /// </summary>
    [EnumMember(Value = 2)]
    NUMBER_2,
    
    /// <summary>
    /// Enum NUMBER_3 for 3
    /// </summary>
    [EnumMember(Value = 3)]
    NUMBER_3
}
Swagger-codegen version

2.2.3

Swagger declaration file content or url
Command line used for generation

java -jar swagger-codegen-cli.jar generate -i %JSON_CONFIG% -l csharp -c "%APP_FOLDER%code-gen-config.json" -o "%APP_FOLDER%API"

Steps to reproduce
Related issues
Suggest a Fix
@wing328
Copy link
Contributor

wing328 commented Apr 10, 2017

@chidionuekwusi thanks for reporting the issue. What's the "correct" code look like?

I could find a test case here to cover integer enum in C#: https://github.com/swagger-api/swagger-codegen/blob/master/samples/client/petstore/csharp/SwaggerClient/src/IO.Swagger.Test/Model/EnumClassTests.cs#L66

@jimschubert
Copy link
Contributor

@wing328 It looks to me like the issue is more about how swagger definitions define enums.

For example, defining a gender enum like this in definition:

      gender:
        type: string
        enum:
          - none
          - male
          - female

Results in this enum:

        /// <summary>
        /// Gets or Sets Gender
        /// </summary>
        [JsonConverter(typeof(StringEnumConverter))]
        public enum GenderEnum
        {

            /// <summary>
            /// Enum None for "none"
            /// </summary>
            [EnumMember(Value = "none")]
            None,

            /// <summary>
            /// Enum Male for "male"
            /// </summary>
            [EnumMember(Value = "male")]
            Male,

            /// <summary>
            /// Enum Female for "female"
            /// </summary>
            [EnumMember(Value = "female")]
            Female
        }

Technically, this is correct and is the only way I know of to provide semantics to the enum's numbers. However, the enum is annotated with StringEnumConverter which means it is presented as none, male, or female to the api. This is correct, unfortunately.

If you define the enum as numbers with data type string:

      gender:
        type: string
        enum:
          - 0
          - 1
          - 2

You get the following enum (on master):


        /// <summary>
        /// Gets or Sets Gender
        /// </summary>
        [JsonConverter(typeof(StringEnumConverter))]
        public enum GenderEnum
        {

            /// <summary>
            /// Enum _0 for "0"
            /// </summary>
            [EnumMember(Value = "0")]
            _0,

            /// <summary>
            /// Enum _1 for "1"
            /// </summary>
            [EnumMember(Value = "1")]
            _1,

            /// <summary>
            /// Enum _2 for "2"
            /// </summary>
            [EnumMember(Value = "2")]
            _2
        }

Here you get numbers serialized to the API, but no semantics about what those numbers mean.

If you attempt to add semantics with numerical values:

  Gender:
    type: integer
    format: int32
    enum:
      - none
      - male
      - female

You end up with a broken enum:

    /// <summary>
    /// Defines Gender
    /// </summary>
    [JsonConverter(typeof(StringEnumConverter))]
    public enum Gender
    {

        /// <summary>
        /// Enum NUMBER_none for none
        /// </summary>
        [EnumMember(Value = none)]
        NUMBER_none,

        /// <summary>
        /// Enum NUMBER_male for male
        /// </summary>
        [EnumMember(Value = male)]
        NUMBER_male,

        /// <summary>
        /// Enum NUMBER_female for female
        /// </summary>
        [EnumMember(Value = female)]
        NUMBER_female
    }

Interestingly, the above doesn't cause a parsing issue (type is number, value is non-number).

Sounds like the issue report expects the generator to accept the above definition and have this result in:

    /// <summary>
    /// Defines Gender
    /// </summary>
    public enum Gender
    {
        /// <summary>
        /// Enum NUMBER_none for none
        /// </summary>
        None = 0,

        /// <summary>
        /// Enum NUMBER_male for male
        /// </summary>
        Male = 1,

        /// <summary>
        /// Enum NUMBER_female for female
        /// </summary>
        Female = 2
    }

The problem is: if you look at the OpenAPI spec, it points to: https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.5.1 for the spec on enum definition and enum validation.

5.5.1. enum

5.5.1.1. Valid values

The value of this keyword MUST be an array. This array MUST have at
least one element. Elements in the array MUST be unique.

Elements in the array MAY be of any type, including null.

5.5.1.2. Conditions for successful validation

An instance validates successfully against this keyword if its value
is equal to one of the elements in this keyword's array value.

So, if we accept none,male,female as values in an enum and transform those to 0, 1, 2... not only would this break validation as defined in 5.5.1.2 above, but it would be unintuitive whether the API accepts "0", 0, or none for a specific enum value.

I did a little more investigation and this seems to be a common issue with OpenAPI specification, and is in progress. You can follow the discussion here: OAI/OpenAPI-Specification#681.

We've had this reported on other generators (see #2690), but it's unfortunately a limitation of the specification.

@wing328 should we consider supporting this via vendor extension? That seems a bit hacky to me, but it would work considering the semantics (none, male, female) are only metadata at a code level.

@wing328
Copy link
Contributor

wing328 commented Jul 2, 2017

@wing328 should we consider supporting this via vendor extension? That seems a bit hacky to me, but it would work considering the semantics (none, male, female) are only metadata at a code level.

Sorry for late reply on this. Previously I did consider using vendor extension to support this but the one who reported the issue previously was not interested in using vendor extension as a solution.

If there are more demand for a solution addressing this issue, we'll guide the community on how to fix it to begin with.

@larssb
Copy link

larssb commented Oct 10, 2017

I have a very similar issue as this one. Therefore, I allow myself to post it in this issue instead of creating an extra issue for something so similar.

Issue
This spec.: https://gist.github.com/larssb/d00e4cf200d85423152df75703d84076 <-- is not interpreted correctly regarding enums. I executed java -jar swagger-codegen-cli-2.2.3.jar generate -i ./octopusDeploy.json -l csharp -o FolderName -c config.json and the config.json file contains { "packageName": "Octopus.Deploy.API" } e.g. in the "UserRoleResource.cs" file the enum syntax is /// <summary> /// Enum _5 for "5" /// </summary> [EnumMember(Value = ""5"")] _5 = "5",

  1. The "" before and after value is not accepted syntax.
  2. _5 = "5" <-- gives me IDE warnings that [Int] could not be type casted to a [String].
  3. Furthermore when building I get: "error CS1026: ) was expected" as well as "error CS1519: illegal token '=' in class declaration, structure or interface" (roughly translated as my output is in another language.). This happens for many files. As an example let's take the "UserRoleResource.cs" file.

Looking forward to hear from you and thank you very much.

@jimschubert
Copy link
Contributor

@larssb I opened #6887 in an attempt to clean up the differences between string based enums in specs and those integral types that are directly supported by C#. I was wondering if you could take a look?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants