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

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

Closed
ErikGrimes opened this issue Dec 16, 2018 · 3 comments
Milestone

Comments

@ErikGrimes
Copy link

ErikGrimes commented Dec 16, 2018

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
@stephanpelikan
Copy link
Contributor

I have the same problem. Is there a workaround? In 3.3.3 it was working but I need 4.0 for other types (typescript-fetch).

@stephanpelikan
Copy link
Contributor

I tried to use 3.3.3 only for the spring generator but now I run into #1551. So no version is working well 👎

@jimschubert
Copy link
Member

Fixed by #4503 please evaluate and let us know if it needs to be reopened.

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

3 participants