[BUG][Java] oneOf with enum discriminator fails to compile
Description
When using the oneOf expression with enums the code fails to compile because the interface has a function of type "public String getType();", while the children nodes have the implemented method defined as "public TypeEnum getType() {}" which doesn't match the contract. If I manually change the concrete classes to match the interface (ex changing the TypeEnum method to public String getType() { return type.value; } it compiles and works fine.
I'm wondering if I'm doing something wrong or what.
Example Components
TargetingExpression:
oneOf:
- $ref: "#/components/schemas/TargetingPredicate"
- $ref: "#/components/schemas/TargetingPredicateNested"
discriminator:
propertyName: "type"
mapping:
"views": "#/components/schemas/SDTargetingPredicateNested"
"asinSameAs": "#/components/schemas/TargetingPredicate"
TargetingPredicate:
type: "object"
required: ["type", "value"]
properties:
type:
type: "string"
enum:
- asinSameAs
value:
type: "string"
TargetingPredicateNested:
type: "object"
required: ["type", "value"]
properties:
type:
type: "string"
enum:
- views
value:
type: "array"
Which then generates this
@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2021-03-22T22:35:47.230-04:00[America/Toronto]")
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type", visible = true)
@JsonSubTypes({
@JsonSubTypes.Type(value = TargetingPredicate.class, name = "asinSameAs"),
@JsonSubTypes.Type(value = TargetingPredicateNested.class, name = "views"),
})
public interface TargetExpression {
public String getType();
}
//==============
@JsonPropertyOrder({
SDTargetingPredicateV31.JSON_PROPERTY_TYPE,
SDTargetingPredicateV31.JSON_PROPERTY_VALUE
})
@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2021-03-22T22:35:47.230-04:00[America/Toronto]")
public class TargetingPredicate implements SDTargetExpression {
/**
* Gets or Sets type
*/
public enum TypeEnum {
ASINSAMEAS("asinSameAs");
private String value;
TypeEnum(String value) {
this.value = value;
}
@JsonValue
public String getValue() {
return value;
}
@Override
public String toString() {
return String.valueOf(value);
}
@JsonCreator
public static TypeEnum fromValue(String value) {
for (TypeEnum b : TypeEnum.values()) {
if (b.value.equals(value)) {
return b;
}
}
throw new IllegalArgumentException("Unexpected value '" + value + "'");
}
}
public static final String JSON_PROPERTY_TYPE = "type";
private TypeEnum type;
public static final String JSON_PROPERTY_VALUE = "value";
private String value;
public TargetingPredicate type(TypeEnum type) {
this.type = type;
return this;
}
/**
* Get type
* @return type
**/
@NotNull
@ApiModelProperty(required = true, value = "")
@JsonProperty(JSON_PROPERTY_TYPE)
@JsonInclude(value = JsonInclude.Include.ALWAYS)
public TypeEnum getType() {
return type;
}
public void setType(TypeEnum type) {
this.type = type;
}
public TargetingPredicate value(String value) {
this.value = value;
return this;
}
/**
* The value to be targeted.
* @return value
**/
@NotNull
@ApiModelProperty(example = "B0123456789", required = true, value = "The value to be targeted.")
@JsonProperty(JSON_PROPERTY_VALUE)
@JsonInclude(value = JsonInclude.Include.ALWAYS)
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
@Override
public boolean equals(java.lang.Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
TargetingPredicate TargetingPredicate = (SDTargetingPredicateV31) o;
return Objects.equals(this.type, TargetingPredicate.type) &&
Objects.equals(this.value, TargetingPredicate.value);
}
@Override
public int hashCode() {
return Objects.hash(type, value);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("class SDTargetingPredicateV31 {\n");
sb.append(" type: ").append(toIndentedString(type)).append("\n");
sb.append(" value: ").append(toIndentedString(value)).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 ");
}
}
Configuration
{
"useBeanValidation": "true",
"serializationLibrary": "jackson",
"library": "jersey2",
"java8": "true",
"dateLibrary": "java8",
"sourceFolder": "",
"modelPackage": "com.models,
"legacyDiscriminatorBehavior": false
}
openapi-generator version
Openapi-generator-4.3.1
Please try newer stable version v5.1.0 instead.
Hi, I have the same issue with version 5.4.0.
This is my enum:
title: CashbookEntryType
type: string
nullable: true
enum:
- in
- out
description: Cashbook type.
And here's my model:
title: CashbookEntry
oneOf:
- $ref: ./CashbookEntryIn.yaml
- $ref: ./CashbookEntryOut.yaml
discriminator:
propertyName: type
mapping:
in: ./CashbookEntryIn.yaml
out: ./CashbookEntryOut.yaml
The problem is on the generated constructor:
public CashbookEntry() {
this.type = this.getClass().getSimpleName();
}
This is valid only for String discriminators, not with Enum ones. The correct version for Enum discriminators is the following one, using the fromValue method of the enum type:
public CashbookEntry() {
this.type = CashbookEntryType.fromValue(this.getClass().getSimpleName());
}
For now, I fixed creating a custom template and using this (really ugly, I added a futile loop on vars) fragment to modify the generated constructor method:
{{#discriminator}}
public {{classname}}() {
{{#vars}}
{{#isDiscriminator}}
{{#isString}}
this.{{{discriminatorName}}} = this.getClass().getSimpleName();
{{/isString}}
{{^isString}}
this.{{{discriminatorName}}} = {{{datatypeWithEnum}}}.fromValue(this.getClass().getSimpleName());
{{/isString}}
{{/isDiscriminator}}
{{/vars}}
}
{{/discriminator}}
but it would be way better to add a field to the "discriminator" variable to be able to select the correct instruction to insert in the generated code.
Is this going to be fixed sometime soon?