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

Child in hierarchy of more than one level doesn't inherit from its parent #3474

Closed
fiore-adrian opened this issue Jul 28, 2016 · 5 comments
Closed

Comments

@fiore-adrian
Copy link

Description

When you create a hierarchy with more than one level the generated java code of the child doesn't inherit (extends) from its parent

Swagger-codegen version

2.2.0

Swagger declaration file example
swagger: '2.0'
info:
  title: Enum Test
  description: Test enum inside array
  version: "1.0.0"
host: localhost:8080
schemes:
  - http
  - https
consumes:
  - "application/json"
produces:
  - "application/json"

paths: {}

definitions:

  example:
    type: object
    discriminator: example_type
    properties:
      id:
        type: string
      name:
        type: string
      example_type:
        type: string
        enum:
        - subexample
        - subsubexample
  subexample:
    type: object
    allOf:
    - $ref: '#/definitions/example'
    - type: object
  subsubexample:
    type: object
    allOf:
    - $ref: '#/definitions/subexample'
    - type: object
Hierarchy generated classes
public class ExampleModel {
    // ...
}
public class SubexampleModel extends ExampleModel {
    // ...
}
public class SubsubexampleModel {
    // ...
}
Error detected

SubsubexampleModel should extends from SubexampleModel

Suggested fix

First of all the parent property in a ComposedModel isn't set anymore in the parser. That's because of this issue and commit:
swagger-api/swagger-parser#245
swagger-api/swagger-parser@be6f068

Now you define the parent in swagger-codegen inside DefaultCodegen.fromModel method.
You set as the parent the first "interface" that has a discriminator. But in the case of a hierarchy with more than one level the discriminator would be in the root of the hierarchy and this condition would be false.
I change the code to first search for a parent with discriminator and if it does not exist, then I set as the parent the first of the ComposedModels inside the "interfaces".
I will add a pull request with my solution.

Thanks!
Regards,

Adrian

@pixelshaded
Copy link
Contributor

pixelshaded commented Aug 24, 2016

I am also getting this for typescript-node and typescript-angular. I'm guessing these changes to swagger-parser will affect every language since the responsibility of finding the parent has changed.

@wing328
Copy link
Contributor

wing328 commented Oct 3, 2016

PR (#3637) merged into master. Please pull the latest master to give it a try.

@wing328 wing328 closed this as completed Oct 3, 2016
@just-jeb
Copy link

Works fine when all the models are defined in a single file.
Still doesn't work with models split to several files. Consider the following scenario: there are multiple web services that share common resources. So there is a common models spec file, and a spec file for each service.
When the common specs file defined like this

{
"definitions": {
"ResourceDescriptor": {
    "description": "This object is a Resource Id",
    "type": "object",
    "properties": {
      "id": {
        "type": "string"
      },
      "resourceType": {
        "type": "string"
      }
    },
    "required": [
      "id",
      "resourceType"
    ]
  },
  "BaseResource": {
    "discriminator": "baseResType",
    "type": "object",
    "description": "This is base class for all resources",
    "properties": {
      "resourceDescriptor": {
        "$ref": "#/definitions/ResourceDescriptor"
      },
      "language": {
        "type": "string"
      },
      "baseResType": {
        "type": "string"
      }
    },
    "required": [
      "resourceDescriptor",
      "baseResType"
    ]
  },
  "Outcome": {
    "type": "object",
    "properties": {
      "responseString": {
        "type": "string"
      },
      "responseCode": {
        "type": "integer"
      },
      "resourceDescriptor": {
        "$ref": "#/definitions/ResourceDescriptor"
      }
    }
  },
  "Observation": {
    "allOf": [
      {
        "$ref": "#/definitions/BaseResource"
      },
      {
        "type": "object",
        "properties": {
          "subject": {
            "$ref": "#/definitions/ResourceDescriptor"
          },
          "effective": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "subject",
          "effective"
        ]
      }
    ]
  }
  }
 }

and in service file there is an inheritance from Observation (see the attachment) the code that is produced (with Java language) doesn't contain any extends. Neither for Observation (which resides in the same file with its parent) or MyCoolResource (which extends Observation and sits in a different file).
Here is even weirder thing:
If you do define an additional discriminator for Observation like this:

"Observation": {
    "allOf": [
      {
        "$ref": "#/definitions/BaseResource"
      },
      {
        "discriminator": "observationType",
        "type": "object",
        "properties": {
          "subject": {
            "$ref": "#/definitions/ResourceDescriptor"
          },
          "effective": {
            "type": "string",
            "format": "date-time"
          },
          "observationType": {
            "type": "string"
          }
        },
        "required": [
          "subject",
          "effective",
          "observationType"
        ]
      }
    ]
  }

the code that is produced for MyCoolResource does contain extends! Which is completely fine by me, I wouldn't mind adding another discriminator.
But the code that is produced for Observation still lacks extends of BaseResource

ModelsForGithub.json.txt
ServiceForGithub.json.txt

@sreeshas
Copy link
Contributor

sreeshas commented Dec 4, 2016

I'm little confused here. Can someone clarify my doubts?

My understanding is a subclass extends from baseclass if baseclass has declared a discriminator. Otherwise subclass just composes fields from baseclass with no parent child relationship.

example can be used in polymorphic way, because it declares a discriminator.
subexample "extends" from example ( because example can be used in a polymorphic way)

Shouldnt' subsubexample extend example because example was the one who defined the discriminator?
if subsubexample extends subexample, doesn't it mean subexample can be used in a polymorphic way (which was not intended)?
Isn't subsubexample "composing" from subexample, because subexample has not declared a discriminator ?

@jeff9finger
Copy link
Contributor

It is my understanding that when allOf: references another definition that does not contain a discriminator, that the Java class will "extend" the other definition, but there will not be Jackson annotations on the classes that will allow correct serialization and deserialization.

The discriminator in a definition enable the generation of the Jackson annotations on the Java classes.

Using the original example:

definitions:

  example:
    type: object
    discriminator: example_type
    properties:
      id:
        type: string
      name:
        type: string
      example_type:
        type: string
        enum:
        - subexample
        - subsubexample
  subexample:
    type: object
    allOf:
    - $ref: '#/definitions/example'
    - type: object
  subsubexample:
    type: object
    allOf:
    - $ref: '#/definitions/subexample'
    - type: object

In order to create Java classes that serialize/deserialize subsubexample as a subexample type, a unique discriminator must be declared on subexample.

  subexample:
    type: object
    allOf:
    - $ref: '#/definitions/example'
    - type: object
       discriminator: sub_example_type
       required:
       - sub_example_type
       properties:
         sub_example_type:
           type: string
       ...

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

6 participants