OpenAPITools / openapi-generator

OpenAPI Generator allows generation of API client libraries (SDK generation), server stubs, documentation and configuration automatically given an OpenAPI Spec (v2, v3)
https://openapi-generator.tech
Apache License 2.0
21.48k stars 6.5k forks source link

[BUG][Java] The client generated by version 3.3.4 hasn't properties generated as concrete Java class but as generic Object class #2366

Open bednar opened 5 years ago

bednar commented 5 years ago

Bug Report Checklist

Description

If i generate client with version 3.0.3 the Cat class is:

public class Cat extends Pet {
  public static final String SERIALIZED_NAME_HUNTS = "hunts";
  @SerializedName(SERIALIZED_NAME_HUNTS)
  private Boolean hunts = null;

  public static final String SERIALIZED_NAME_AGE = "age";
  @SerializedName(SERIALIZED_NAME_AGE)
  private Integer age = null;

  public static final String SERIALIZED_NAME_LINKS = "links";
  @SerializedName(SERIALIZED_NAME_LINKS)
  private CatLinks links = null;

  public Cat hunts(Boolean hunts) {
    this.hunts = hunts;
    return this;
  }

but if I generate client with version 3.3.4 than the Cat class is:

public class Cat extends Pet {
  public static final String SERIALIZED_NAME_HUNTS = "hunts";
  @SerializedName(SERIALIZED_NAME_HUNTS)
  private Boolean hunts;

  public static final String SERIALIZED_NAME_AGE = "age";
  @SerializedName(SERIALIZED_NAME_AGE)
  private Integer age;

  public static final String SERIALIZED_NAME_LINKS = "links";
  @SerializedName(SERIALIZED_NAME_LINKS)
  private Object links = null;

The expected output is that the links is a CatLinks class not Object class.

openapi-generator version

It is regression between 3.3.4 and 3.0.3 of the openapi-generator-maven-plugin.

OpenAPI declaration file content or url
openapi: 3.0.0
info:
  title: My demo
  version: 0.1.0
servers:
  - url: /api/v2
paths:
  /pets:
    patch:
      requestBody:
        content:
          application/json:
            schema:
              oneOf:
                - $ref: '#/components/schemas/Cat'
                - $ref: '#/components/schemas/Dog'
              discriminator:
                propertyName: pet_type
      responses:
        '200':
          description: Updated
components:
  schemas:
    Pet:
      type: object
      required:
        - pet_type
      properties:
        pet_type:
          type: string
      discriminator:
        propertyName: pet_type
    Dog:     # "Dog" is a value for the pet_type property (the discriminator value)
      allOf: # Combines the main `Pet` schema with `Dog`-specific properties 
        - $ref: '#/components/schemas/Pet'
        - type: object
          # all other properties specific to a `Dog`
          properties:
            bark:
              type: boolean
            breed:
              type: string
              enum: [Dingo, Husky, Retriever, Shepherd]
    Cat:     # "Cat" is a value for the pet_type property (the discriminator value)
      allOf: # Combines the main `Pet` schema with `Cat`-specific properties 
        - $ref: '#/components/schemas/Pet'
        - type: object
          # all other properties specific to a `Cat`
          properties:
            hunts:
              type: boolean
            age:
              type: integer
            links:
              type: object
              example:
                self: "/api/v2/scrapers/1"
                owners: "/api/v2/scrapers/1/owners"
                members: "/api/v2/scrapers/1/members"
              properties:
                self:
                  $ref: "#/components/schemas/Link"
                members:
                  $ref: "#/components/schemas/Link"
                owners:
                  $ref: "#/components/schemas/Link"
    Link:
      type: string
      format: uri
      readOnly: true
      description: URI of resource.
Command line used for generation

Generate client via:

mvn org.openapitools:openapi-generator-maven-plugin:generate
Steps to reproduce

The maven plugin configuration:

<plugin>
                <groupId>org.openapitools</groupId>
                <artifactId>openapi-generator-maven-plugin</artifactId>
                <version>3.0.3</version>
                <configuration>
                    <inputSpec>${project.basedir}/src/main/resources/swagger.yml</inputSpec>
                    <generatorName>java</generatorName>
                    <configOptions>
                        <sourceFolder>java</sourceFolder>
                        <dateLibrary>java8</dateLibrary>
                    </configOptions>
                    <generateModelDocumentation>false</generateModelDocumentation>
                    <generateApis>false</generateApis>
                    <generateSupportingFiles>false</generateSupportingFiles>
                    <verbose>false</verbose>
                    <output>${project.basedir}/src/generated</output>
                    <addCompileSourceRoot>false</addCompileSourceRoot>
                    <modelPackage>com.example.api.model</modelPackage>
                </configuration>
            </plugin>
Related issues/PRs
Suggest a fix
wing328 commented 5 years ago

@bednar can you try the latest master (snapshot), which has better support for inheritance?

bednar commented 5 years ago

@wing328

I tried it over 4.0.0-beta2 and results it:

public class Cat extends Pet {
  public static final String SERIALIZED_NAME_HUNTS = "hunts";
  @SerializedName(SERIALIZED_NAME_HUNTS)
  private Boolean hunts;

  public static final String SERIALIZED_NAME_AGE = "age";
  @SerializedName(SERIALIZED_NAME_AGE)
  private Integer age;

  public static final String SERIALIZED_NAME_LINKS = "links";
  @SerializedName(SERIALIZED_NAME_LINKS)
  private Object links = null;

  public Cat hunts(Boolean hunts) {
    this.hunts = hunts;
    return this;
  }

For self builded 4.0.0-SNAPSHOT is the result also same:

public class Cat extends Pet {
  public static final String SERIALIZED_NAME_HUNTS = "hunts";
  @SerializedName(SERIALIZED_NAME_HUNTS)
  private Boolean hunts;

  public static final String SERIALIZED_NAME_AGE = "age";
  @SerializedName(SERIALIZED_NAME_AGE)
  private Integer age;

  public static final String SERIALIZED_NAME_LINKS = "links";
  @SerializedName(SERIALIZED_NAME_LINKS)
  private Object links = null;

  public Cat hunts(Boolean hunts) {
    this.hunts = hunts;
    return this;
  }
wing328 commented 5 years ago

This is a limitation with the inline model resolver. As a workaround, please use $ref to define the following instead of defning it inline:

            links:
              type: object
              example:
                self: "/api/v2/scrapers/1"
                owners: "/api/v2/scrapers/1/owners"
                members: "/api/v2/scrapers/1/members"
              properties:
                self:
                  $ref: "#/components/schemas/Link"
                members:
                  $ref: "#/components/schemas/Link"
                owners:
                  $ref: "#/components/schemas/Link"
bednar commented 5 years ago

@wing328 Thanks for your advice.

Is there any other solution than rewrite the swagger definition?

We use the OpenAPI Generator to generate client for the this swagger: https://github.com/influxdata/influxdb/blob/master/http/swagger.yml and the links definition is pretty common.

wing328 commented 5 years ago

Let me see what we can do for you.

bednar commented 5 years ago

Thx @wing328

We are able to write a "custom handler" or something like this (it this option is here).