Skip to content

[Java] Option to generate Enum values as public static final constants? #6286

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

Open
stevecookform3 opened this issue Aug 10, 2017 · 10 comments
Open

Comments

@stevecookform3
Copy link
Contributor

stevecookform3 commented Aug 10, 2017

Description

I'd like to introduce an option to the java codegen that would generate constants rather than enums where enums are defined in swagger.

So as an example, the following model has a simple enum:

              cat_gender:
                type: string
                enum:
                  - Male
                  - Female

This currently generates the following enum:

  @JsonProperty("cat_gender")
  private CatGenderEnum catGender = null;

  /**
   * Gets or Sets catGender
   */
  public enum CatGenderEnum {
    MALE("Male"),
    
    FEMALE("Female");

    private String value;

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

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

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

I'd like to add a codegen option that would allow you to generate simply:

  @JsonProperty("cat_gender")
  private String catGender = null;

    public static final String CATGENDER_MALE = "Male";
    public static final String CATGENDER_FEMALE = "Female";

The advantage to building this as a String is flexibility, especially when swagger is generating client code.

With the existing generation where an enum in swagger is turned into a strict Enum in java, if the server API changes to add a new value in cat_gender that is neither male nor female (e.g. MALE_NEUTERED), any existing client implementation will just see a value of null (or if #5950 is implemented, this could be possibly an UNKNOWN enum value or just throwing an Exception).

If the enum on the client is interpreted as a String, then the value can still be captured and used (for example, in log/error messages).

I couldnt find any existing option, and for the sake of backwards compatibility I'd suggest adding this as a new code generation option (initially for client java generation) using CodegenConstants.

Any thoughts/comments?

Swagger-codegen version

Latest HEAD

Command line used for generation

swagger-codegen-cli.jar -l spring

@stevecookform3
Copy link
Contributor Author

Adding @wing328 for his comments..

@cbornet
Copy link
Contributor

cbornet commented Aug 11, 2017

I'm not sure of what you want to do here... If what you get from the server is not an enum, just use a regular string !

@stevecookform3
Copy link
Contributor Author

We use the same swagger definition to generate both client & server. Ideally we'd like to use enums, but that means we have to do big-bang upgrades of every client every time we introduce a new server enum. This will be worse in the future if swagger implements the current suggestion in #5950 of throwing an exception when deserialising into an undefined enum.

So what we do currently is (as you suggest) to use a string. But then it's difficult to track what different string constants are being used.

Hence the suggestion that we have an alternate generation mode that allows us to define what the constants are in the swagger (so they are clearly documented, and can be used by other teams that want to generate clients from the definition), but would still be readable (and not simply null or throw an exception) if captured by the client.

@cbornet
Copy link
Contributor

cbornet commented Aug 11, 2017

#5950 is not about making throwing an exception the default but an option. What I mean is that if an older client uses an older definition it won't know what to do with a new value anyway, so it'doesn't really need to know what's inside the value and null should be enough. Unless I'm missing something...

@stevecookform3
Copy link
Contributor Author

Its still an issue in that on the client side, you wont be able to tell the difference between the value not passed (null), and a new unknown value (null). And in the case of a new unknown value, you cant even log an error to say 'got an unknown value x' because you just get null (not the original value).

@cbornet
Copy link
Contributor

cbornet commented Aug 11, 2017

Good point. We should indeed have a default enum value UNKNOWN to differenciate with "not present"

@maverickmicky
Copy link

I reached this thread while looking for how to define constants in swagger. I have a request which uses map of key:value. Keys will be constants and I want to share it among server and client. Is it possible to do it somehow?

@kevinmic
Copy link

I could also use this feature. It is not good enough to have a "default enum value UNKNOWN" because you still lose the value of the enum being passed.

I need to consume someone else's swagger api and they use enums all over the place. I don't want to consume these fields as enums, I want to consume them as Strings so that I future proof my client against the possibility of them adding new enums to the api in the future. It would be a bonus on top of that to have the known values to be "public static final String" constants.

At a minimum it would be nice to ignore enum values and just use a String instead, but I haven't found this feature in swagger codegen either.

@slarti-b
Copy link
Contributor

slarti-b commented Jul 4, 2018

@cbornet: I don't think the generator should specify any fixed valid enum. What about if you have UNKNOWN as one option in your enum already? I think one of the following would be better (I'm assuming here that strict enum validation is not used and example type MyEnum and field myEnumField):

  1. Set the myEnumField null and have an additional field, not rendered in the Json called myEnumFieldSubmittedValue which is String that the client can access if it needs to know the value
  2. Set the myEnumField null and have an additional boolean field myEnumFieldIsInvalid which is set if an invalid value is submitted
  3. Allow specifying the default enum value to use in the spec - but this requires a change to the swagger spec I guess. poor mans solution would be (against a setting) to use the first specified value as the default if an invalid one is submitted.

@ajaygautam
Copy link

Any status on this?

We switched from enums to custom classes with public static final constants.
Now swagger docs are broken.
Would be great to have a tag on the class - something like "EnumImposter" :)

Thanks

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

7 participants