Skip to content
GitLab
Projects Groups Snippets
  • /
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
    • Contribute to GitLab
  • Sign in / Register
  • O openapi-generator
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
  • Issues 3,476
    • Issues 3,476
    • List
    • Boards
    • Service Desk
    • Milestones
  • Merge requests 402
    • Merge requests 402
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
  • Deployments
    • Deployments
    • Environments
    • Releases
  • Packages and registries
    • Packages and registries
    • Package Registry
    • Infrastructure Registry
  • Monitor
    • Monitor
    • Incidents
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Repository
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • OpenAPI Tools
  • openapi-generator
  • Issues
  • #1685
Closed
Open
Issue created Dec 16, 2018 by Administrator@rootContributor

[BUG] [Java] [Spring] openapi-generator generates incorrect type information for multilevel inheritance

Created by: ErikGrimes

Description

The openapi-generator spring generator generates incorrect @JsonSubTypes for multilevel inheritance

class Animal
class Dog extends Animal
class BigDog extends Dog
class Cat extends Animal
openapi-generator version

3.3.4

OpenAPI declaration file content or url

api.yaml

openapi: 3.0.0
info:
  title: Sample API
  description: API description in Markdown.
  version: 1.0.0
paths:
  /animals:
    get:
      summary: Returns all animals.
      description: Optional extended description in Markdown.
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Animal'
components:
  schemas:
    Dog:
        allOf:
          - $ref: '#/components/schemas/Animal'
          - type: object
            properties:
              breed:
                type: string
    Cat:
        allOf:
          - $ref: '#/components/schemas/Animal'
          - type: object
            properties:
              breed:
                type: string                
    BigDog:
        allOf:
          - $ref: '#/components/schemas/Dog'
          - type: object
            discriminator:
              propertyName: dogType
              required:
              - dogType 
            properties:
              dogType:
                type: string
              declawed:
                type: boolean
    Animal:
        type: object
        discriminator:
          propertyName: className
        required:
        - className
        properties:
          className:
            type: string
          color:
            type: string
            default: red
               
Command line used for generation
openapi-generator generate -g spring -i api.yaml -o generated -DdelegatePattern=true,hideGenerationTimestamp=true
Steps to reproduce

Invoke the command line about with the provided api.yaml

Expected Output:

Animal.java

package org.openapitools.model;

import java.util.Objects;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import javax.validation.Valid;
import javax.validation.constraints.*;

/**
 * Animal
 */

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "className", visible = true)
@JsonSubTypes({
  @JsonSubTypes.Type(value = Dog.class, name = "BigDog"),
  @JsonSubTypes.Type(value = Cat.class, name = "Cat"),
})

public class Animal   {
  @JsonProperty("className")
  private String className;

  @JsonProperty("color")
  private String color = "red";

  public Animal className(String className) {
    this.className = className;
    return this;
  }

  /**
   * Get className
   * @return className
  */
  @ApiModelProperty(required = true, value = "")
  @NotNull


  public String getClassName() {
    return className;
  }

  public void setClassName(String className) {
    this.className = className;
  }

  public Animal color(String color) {
    this.color = color;
    return this;
  }

  /**
   * Get color
   * @return color
  */
  @ApiModelProperty(value = "")


  public String getColor() {
    return color;
  }

  public void setColor(String color) {
    this.color = color;
  }


  @Override
  public boolean equals(java.lang.Object o) {
    if (this == o) {
      return true;
    }
    if (o == null || getClass() != o.getClass()) {
      return false;
    }
    Animal animal = (Animal) o;
    return Objects.equals(this.className, animal.className) &&
        Objects.equals(this.color, animal.color);
  }

  @Override
  public int hashCode() {
    return Objects.hash(className, color);
  }

  @Override
  public String toString() {
    StringBuilder sb = new StringBuilder();
    sb.append("class Animal {\n");
    
    sb.append("    className: ").append(toIndentedString(className)).append("\n");
    sb.append("    color: ").append(toIndentedString(color)).append("\n");
    sb.append("}");
    return sb.toString();
  }

  /**
   * Convert the given object to string with each line indented by 4 spaces
   * (except the first line).
   */
  private String toIndentedString(java.lang.Object o) {
    if (o == null) {
      return "null";
    }
    return o.toString().replace("\n", "\n    ");
  }
}

Dog.java

public abstract class Dog extends Animal {

}

BigDog.java

public class BigDog extends Dog {

}

Cat.java

public class Cat extends Animal {

}
Actual Output

Animal.java

package org.openapitools.model;

import java.util.Objects;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import javax.validation.Valid;
import javax.validation.constraints.*;

/**
 * Animal
 */

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "className", visible = true)
@JsonSubTypes({
  @JsonSubTypes.Type(value = Dog.class, name = "Dog"),
  @JsonSubTypes.Type(value = Cat.class, name = "Cat"),
})

public class Animal   {
  @JsonProperty("className")
  private String className;

  @JsonProperty("color")
  private String color = "red";

  public Animal className(String className) {
    this.className = className;
    return this;
  }

  /**
   * Get className
   * @return className
  */
  @ApiModelProperty(required = true, value = "")
  @NotNull


  public String getClassName() {
    return className;
  }

  public void setClassName(String className) {
    this.className = className;
  }

  public Animal color(String color) {
    this.color = color;
    return this;
  }

  /**
   * Get color
   * @return color
  */
  @ApiModelProperty(value = "")


  public String getColor() {
    return color;
  }

  public void setColor(String color) {
    this.color = color;
  }


  @Override
  public boolean equals(java.lang.Object o) {
    if (this == o) {
      return true;
    }
    if (o == null || getClass() != o.getClass()) {
      return false;
    }
    Animal animal = (Animal) o;
    return Objects.equals(this.className, animal.className) &&
        Objects.equals(this.color, animal.color);
  }

  @Override
  public int hashCode() {
    return Objects.hash(className, color);
  }

  @Override
  public String toString() {
    StringBuilder sb = new StringBuilder();
    sb.append("class Animal {\n");
    
    sb.append("    className: ").append(toIndentedString(className)).append("\n");
    sb.append("    color: ").append(toIndentedString(color)).append("\n");
    sb.append("}");
    return sb.toString();
  }

  /**
   * Convert the given object to string with each line indented by 4 spaces
   * (except the first line).
   */
  private String toIndentedString(java.lang.Object o) {
    if (o == null) {
      return "null";
    }
    return o.toString().replace("\n", "\n    ");
  }
}

Dog.java

public class Dog extends Animal {

}

BigDog.java

public class BigDog extends Dog {

}

Cat.java

public class Cat extends Animal {

}
Suggest a fix
  1. Update DefaultCodegen.createDiscriminator to add a model for each Schema that is descended from schemaName.
  2. Allow the schema consumer to provide configuration to the code generator to obtain the desired @JsonSubTypes behavior either by designating the desired values explicitly or by indicating the models in the inheritance hierarchy that should be abstract and ignored (similar to the way that JPA uses @MappedSuperclass and @Entity).
  3. Update the Maven plugin to support the new config options.

mappedSupermodels

openapi-generator generate -g spring -i api.yaml -o generated -DdelegatePattern=true,hideGenerationTimestamp=true -DmappedSupermodel=Dog

subtypeModels

openapi-generator generate -g spring -i api.yaml -o generated -DdelegatePattern=true,hideGenerationTimestamp=true -DsubtypeModels=Cat,BigDog
Assignee
Assign to
Time tracking