swagger-api / swagger-codegen

swagger-codegen contains a template-driven engine to generate documentation, API clients and server stubs in different languages by parsing your OpenAPI / Swagger definition.
http://swagger.io
Apache License 2.0
16.96k stars 6.04k forks source link

[JAVA] Bug generating models with enum discriminator #10441

Open KamasamaK opened 4 years ago

KamasamaK commented 4 years ago
Description

The model for an object with an enum discriminator generates a constructor that causes a compilation error.

The following is an example generated model with some irrelevant code removed.

package com.alianza.client.model;

// imports

public class RingFailoverAction {
  /**
   * Gets or Sets type
   */
  @JsonAdapter(TypeEnum.Adapter.class)
  public enum TypeEnum {
    // values

    private String value;

    TypeEnum(String value) {
      this.value = value;
    }

    public String getValue() {
      return value;
    }

    @Override
    public String toString() {
      return String.valueOf(value);
    }

    public static TypeEnum fromValue(String text) {
      for (TypeEnum b : TypeEnum.values()) {
        if (String.valueOf(b.value).equals(text)) {
          return b;
        }
      }
      return null;
    }

    public static class Adapter extends TypeAdapter<TypeEnum> {
      @Override
      public void write(final JsonWriter jsonWriter, final TypeEnum enumeration) throws IOException {
        jsonWriter.value(enumeration.getValue());
      }

      @Override
      public TypeEnum read(final JsonReader jsonReader) throws IOException {
        String value = jsonReader.nextString();
        return TypeEnum.fromValue(String.valueOf(value));
      }
    }
  }

  @SerializedName("@type")
  private TypeEnum type = null;

  public RingFailoverAction() {
    this.type = this.getClass().getSimpleName();
  }
  public RingFailoverAction type(TypeEnum type) {
    this.type = type;
    return this;
  }

   /**
   * Get type
   * @return type
  **/
  @ApiModelProperty(required = true, value = "")
  public TypeEnum getType() {
    return type;
  }

  public void setType(TypeEnum type) {
    this.type = type;
  }

  // equals

  // hashCode

  // toString

  // toIndentedString
}

The statement causing the error is this.type = this.getClass().getSimpleName(), which is attempting to assign a String to a TypeEnum.

Swagger-codegen version

2.4.15 (not a regression)

Swagger declaration file content or url

Full file: https://api.alianza.com/v2/apidocs/swagger.json

Relevant example section

"RingFailoverAction" : {
  "type" : "object",
  "required" : [ "@type" ],
  "discriminator" : "@type",
  "properties" : {
    "@type" : {
      "type" : "string",
      "enum" : [ "VoicemailRingFailoverAction", "BusyRingFailoverAction", "ForwardRingFailoverAction" ]
    }
  }
}
Command line used for generation
java -jar swagger-codegen-cli-2.4.15.jar generate -i https://api.alianza.com/v2/apidocs/swagger.json --api-package com.alianza.client.api --model-package com.alianza.client.model --invoker-package com.alianza.client.invoker --group-id com.alianza -l java -o ./generated_java_client --additional-properties dateLibrary=java8
Steps to reproduce
  1. Run the command line
  2. Attempt to compile
Related issues/PRs

https://github.com/swagger-api/swagger-codegen/issues/10196#issuecomment-659673863

Suggest a fix/enhancement

Wrapping this.getClass().getSimpleName() with the enum's valueOf() fixes the compilation error, but I don't know if this is the proper fix because I don't know what the use of that constructor even is.

alexnb commented 3 years ago

That issue is still reprocucible with version 3.0.27.

One important comment: the line this.type = this.getClass().getSimpleName() is not only wrong if enums are used. Without enums (remove the line "enum" : [ "... from openapi definition), this also prevents the correct type to be set on an object during deserialization (the generated code in JSON.java sees that the type is already set and does not set it to the mapped value)

In fact this seems to be a small change but is a showstopper if polymorphism is used.

DeegC commented 1 year ago

I'm getting this in 3.0.39. The only way for me to get around this is to set implementation = String.class in the schema for the discriminator. I think the fix is to remove the constructor (or at least remove the field assignment from the constructor).

isaac33zhang commented 1 year ago

Hi, I am seeing the same issue. I have to manually remove the assignment line from the constructor every time. I am not sure whether this is an issue with swagger and Enum discriminator or I am using it incorrectly. Any progress or ideas on this problem? Thanks