swagger-api / swagger-api/swagger-codegen

[CSHARP] Missing base class parameters in derived class contractor for multi level inheritance scenarios

Open
#11,905 0 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Mustache
Stars
17.8k
Forks
6k
PR merge metrics
No merged PRs in 30d

Description

Description

As inheritance is transitive in C#, it allows you to define an inheritance hierarchy for a set of types. In other words, type D can inherit from type C, which inherits from type B, which inherits from the base class type A. Because inheritance is transitive, the members of type A are available to type D.

Swagger codegen currently only support single level inheritance e.g types from A is available to B but types from A is currently not available to C or D. This cause runtime exceptions when trying to deserialize C if A has mandatory properties even though the values are avialable in the JSON payload.

And unfortunately this is not picked up during a build, unless we add integration test to deserialise D and C for scenarios where A and B has mandatory properties.

Swagger-codegen version

3.0.35

Swagger declaration file content or url

I prefer to use examples that are close to the real world, so rather then using type A, B, C & D I have created a sample schema to replicate this issue using hotel property models. See below table for a relationship link between the scenairo described above and the schema. Basically the PropertyDetail model in the inheritance example above is of type C etc.

Type Model Name
A PropertyID
B Property
C PropertyDetail
D PropertyFullDetail
openapi: 3.0.0
info:
  version: '1.0'
  title: Test
paths:
  /search:
    get:
      responses:
        200:
          description: OK - Successful
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PropertyDetail'
components:
  schemas:
    PropertyID:
      required:
        - '@type'
        - PropertyKey
      properties:
        '@type':
          type: string
        id:
          type: string
    Property:
      allOf:
        - $ref: '#/components/schemas/PropertyID'
        - required:
            - name
          properties:
            name:
              maxLength: 128
              type: string
              description: Property name
            description:
              maxItems: 5
              type: array
              items:
                type: string
    PropertyDetail:
      allOf:
        - $ref: '#/components/schemas/Property'
        - required:
            - address
          properties:
            address:
              maxItems: 5
              minItems: 1
              type: array
              items:
                maxLength: 128
                type: string
            telephone:
              maxItems: 5
              minItems: 1
              type: array
              items:
                maxLength: 128
                type: string
    PropertyFullDetail:
      allOf:
        - $ref: '#/components/schemas/PropertyDetail'
        - required:
            - address
          properties:
            rating:
              type: number
            images:
              type: array
              items:
                maxLength: 128
                type: string
Command line used for generation

java -jar swagger-codegen-cli-3.0.35.jar generate -l csharp -i "path-to-spec"

Steps to reproduce
  1. Generate the C# files using the command line above
  2. Build the project
  3. Add below code to the PropertyFullDetailInstanceTest method in PropertyFullDetailTest.cs
        /// <summary>
        /// Test an instance of PropertyFullDetail
        /// </summary>
        [Test]
        public void PropertyFullDetailInstanceTest()
        {
            var json = "{\"name\": \"Hilton\",\"address\": [\"50 Hilton Avenue\"],\"description\": [\"Testing\"],\"@type\": \"PropertyFullDetail\",\"id\": \"HI001\"}";
            var instance = JsonConvert.DeserializeObject<PropertyFullDetail>(json);
        }
  1. The test will fail with "System.IO.InvalidDataException : type is a required property for PropertyID and cannot be null".

Please note that type is set in the JSON payload, it is just ignored by the PropertyFullDetail constructor.

Actual result

Example of the generated PropertyDetail and PropertyFullDetail constructor.

PropertyDetail (type C) is missing type and id from the base class (type A) and PropertyFullDetail (type D) is missing name and description (from type B) and also type and id (from type A).

public PropertyDetail(List<string> address = default(List<string>), List<string> telephone = default(List<string>), string name = default(string), List<string> description = default(List<string>)) : base(name, description)

public PropertyFullDetail(decimal? rating = default(decimal?), List<string> images = default(List<string>), List<string> address = default(List<string>), List<string> telephone = default(List<string>)) : base(address, telephone)
      
Expected result

Example of expected PropertyDetail and PropertyFullDetail constructor with parameters inherited from the base class.

public PropertyDetail(List<string> address = default(List<string>), List<string> telephone = default(List<string>), string name = default(string), List<string> description = default(List<string>), string type = default(string), string id = default(string)) : base(name, description, type, id)

public PropertyFullDetail(decimal? rating = default(decimal?), List<string> images = default(List<string>), List<string> address = default(List<string>), List<string> telephone = default(List<string>), string name = default(string), List<string> description = default(List<string>), string type = default(string), string id = default(string)) : base(address, telephone, name, description, type, id)

      
Related issues/PRs

Unable to find one, sorry! 🙃

Suggest a fix/enhancement

If a base class has mandatory properties, any derived class in a multi level inheritance hierarchy will cause runtime deserialization exceptions.

This is critical issue for the project that I am currently working on that has a schema that generates over 400 models. So far I have identified 8 models that experience this issue. But I have not received payload samples from the vendor to get code coverage for all models.

I currently manually edit the constructors after generating my classes, but I am worried about the classes that we are not discovering during the development or UAT phase of the project that might cause runtime exceptions in production later on.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the provided OpenAPI schema and generate the C# models using the documented swagger-codegen CLI command. Inspect the generated PropertyDetail and PropertyFullDetail constructors, then reproduce the failure in PropertyFullDetailTest.cs with the supplied JSON. Done means inherited parameters from Property and PropertyID are included through the multi-level constructor chain and deserialization succeeds.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
devtools
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.