-
-
Notifications
You must be signed in to change notification settings - Fork 6.7k
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
Use enum type for discriminator #13846
Use enum type for discriminator #13846
Conversation
@cachescrubber (2022/02) @welshm (2022/02) @MelleD (2022/02) @atextor (2022/02) @manedev79 (2022/02) @javisst (2022/02) @borsch (2022/02) @banlevente (2022/02) @Zomzog (2022/09) |
Any chance of this PR being merged soon? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code itself seems good, I think we'll need to see what the regenerated samples look like for other servers
// FIXME: there are other ways to define the type of the discriminator property (inline | ||
// for example). Handling those scenarios is too complicated for me, I'm leaving it for | ||
// the future.. | ||
String propertyType = | ||
Optional.ofNullable(schema.getProperties()) | ||
.map(p -> (Schema) p.get(discPropName)) | ||
.map(Schema::get$ref) | ||
.map(ModelUtils::getSimpleRef) | ||
.orElseGet(() -> typeMapping.get("string")); | ||
discriminator.setPropertyType(propertyType); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will impact more than just the JavaSpring generation - can you regenerate the samples and tests to see what impact this has on other clients?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@welshm I've run the commands in the PR instructions above. No files changed to commit to Git. I'm not certain that it worked properly, but the scripts seemed to run without errors.
// the future.. | ||
String propertyType = | ||
Optional.ofNullable(schema.getProperties()) | ||
.map(p -> (Schema) p.get(discPropName)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I know this isn't a variable you named, but I think full naming is better to disambiguate. discriminatorPropertyName
might be more clear what the variable clearly represents
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Variable has been renamed, please review again
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code look great! Can you run the commands in the PR template to regenerate the samples?
@wing328 will need to approve running the tests
properties: | ||
fruitType: | ||
$ref: "#/components/schemas/FruitTypeEnum" | ||
required: fruitType |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The required property must be an array.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I see the problem now. I've pushed a fix.
- $ref: '#/components/schemas/BananaOneOfEnumMappingDisc' | ||
discriminator: | ||
propertyName: fruitType | ||
mapping: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The mapping to the enum value might cause problems with the auto generated JsonSubType.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I actually generated a sample Project:
@JsonIgnoreProperties(
value = "fruitType", // ignore manually set fruitType, it will be automatically generated by Jackson during serialization
allowSetters = true // allows the fruitType to be set during deserialization
)
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "fruitType", visible = true)
@JsonSubTypes({
@JsonSubTypes.Type(value = AppleOneOfEnumMappingDisc.class, name = "APPLE"),
@JsonSubTypes.Type(value = AppleOneOfEnumMappingDisc.class, name = "AppleOneOfEnumMappingDisc"),
@JsonSubTypes.Type(value = BananaOneOfEnumMappingDisc.class, name = "BANANA"),
@JsonSubTypes.Type(value = BananaOneOfEnumMappingDisc.class, name = "BananaOneOfEnumMappingDisc")
})
@Generated(value = "org.openapitools.codegen.languages.SpringCodegen", date = "2022-11-03T09:30:55.032940+01:00[Europe/Berlin]")
public interface FruitOneOfEnumMappingDisc {
public FruitTypeEnum getFruitType();
}
@welshm Isn't there another issue / pr dealing with duplicated JsonSubTypes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bernie-schelberg-mywave Could you please add a enum based discriminator to Ione of the generated sample projects (for example bin/configs/spring-boot-oneof.yaml
)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I actually generated a sample Project:
@JsonIgnoreProperties( value = "fruitType", // ignore manually set fruitType, it will be automatically generated by Jackson during serialization allowSetters = true // allows the fruitType to be set during deserialization ) @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "fruitType", visible = true) @JsonSubTypes({ @JsonSubTypes.Type(value = AppleOneOfEnumMappingDisc.class, name = "APPLE"), @JsonSubTypes.Type(value = AppleOneOfEnumMappingDisc.class, name = "AppleOneOfEnumMappingDisc"), @JsonSubTypes.Type(value = BananaOneOfEnumMappingDisc.class, name = "BANANA"), @JsonSubTypes.Type(value = BananaOneOfEnumMappingDisc.class, name = "BananaOneOfEnumMappingDisc") }) @Generated(value = "org.openapitools.codegen.languages.SpringCodegen", date = "2022-11-03T09:30:55.032940+01:00[Europe/Berlin]") public interface FruitOneOfEnumMappingDisc { public FruitTypeEnum getFruitType(); }
@welshm Isn't there another issue / pr dealing with duplicated JsonSubTypes?
I'm running openapi-generator version 6.2.0 and the above is the current behaviour when you add a mapping to the discriminator. Both the derived classes and the mapping values are added as JsonSubTypes.
The documentations seems to indicate that this is the expected behaviour.
The mapping in the discriminator includes any descendent schemas that allOf inherit from self, any oneOf schemas, any anyOf schemas, any x-discriminator-values, and the discriminator mapping schemas in the OAS document AND Codegen validates that oneOf and anyOf schemas contain the required discriminator and throws an error if the discriminator is missing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cachescrubber Yes, there's another project for duplicated JsonSubTypes: #13815
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done (added enum based discriminator to samples)
@welshm @cachescrubber @wing328 Sorry for the delay, I've managed to generate samples (I added an example using an enum mapping), please review again. |
Thanks a ton for this @bernie-schelberg-mywave, this will help us out a ton at Hasura with our public SDK types, which currently fail to generate properly due to having a lot of polymorphic types using enum discriminants. We have a query language IR where we distinguish between types of operations like This fails pretty miserably in OpenAPI Generator currently: "Expression": {
"discriminator": {
"mapping": {
"and": "AndExpression",
"binary_arr_op": "ApplyBinaryArrayComparisonOperator",
"binary_op": "ApplyBinaryComparisonOperator",
"exists": "ExistsExpression",
"not": "NotExpression",
"or": "OrExpression",
"unary_op": "ApplyUnaryComparisonOperator"
},
"propertyName": "type"
},
"oneOf": [
{
"$ref": "#/components/schemas/ExistsExpression"
},
// <SNIPPED>
]
},
"BinaryComparisonOperator": {
"additionalProperties": true,
"anyOf": [
{
"enum": [
"less_than",
"less_than_or_equal",
"greater_than",
"greater_than_or_equal",
"equal"
],
"type": "string"
},
{
"type": "string"
}
]
}, |
@welshm @cachescrubber @wing328 is there anything else I can do to help move this PR forward? |
cc @OpenAPITools/generator-core-team as the change impacts default codegen. |
@wing328 thanks for running the workflows, I saw there was a failure, so merged the |
Hi @bernie-schelberg-mywave thanks again for the PR. Can you please PM me via Slack for some quick questions if you don't mind? ref: https://join.slack.com/t/openapi-generator/shared_invite/zt-12jxxd7p2-XUeQM~4pzsU9x~eGLQqX2g |
@wing328 is there any timeline for having this in any release?? |
Hi, do we have any progress here? We miss this functionality and it would help us a lot! |
Is this planned to be merged? Seems like a key missing functionality? Is there a workaround for it that anyone is aware of (other than leaving the discriminator as String)? |
Any updates on this? 👀 |
As a workaround, I'm using a custom template for the |
As far as I know, the plan is to include this as part of the version 7.0 release. |
# Conflicts: # modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java
# Conflicts: # samples/openapi3/server/petstore/spring-boot-oneof/src/main/java/org/openapitools/model/Foo.java # samples/openapi3/server/petstore/spring-boot-oneof/src/main/java/org/openapitools/model/FooRef.java
...t/petstore/swift5/validation/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift
Outdated
Show resolved
Hide resolved
...t/petstore/swift5/validation/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift
Outdated
Show resolved
Hide resolved
...t/petstore/swift5/validation/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift
Outdated
Show resolved
Hide resolved
...t/petstore/swift5/validation/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift
Outdated
Show resolved
Hide resolved
...t/petstore/swift5/validation/PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift
Outdated
Show resolved
Hide resolved
...les/openapi3/server/petstore/spring-boot-oneof/src/main/java/org/openapitools/model/Foo.java
Outdated
Show resolved
Hide resolved
*/ | ||
public Apple(Integer seeds) { | ||
this.seeds = seeds; | ||
this.fruitType = fruitType; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Initialising fruitType
like this is weird, but is a separate issue I think. If a class implements an interface which has a oneOf with a discriminator, the discriminator property is only half considered "required". The template adds initialisation of the field, but omits the constructor parameter. Arguably, the field should be initialised with the correct discriminator value, it should not be a constructor parameter at all.
I've switched the branch from cc @wing328 @jimschubert @cbornet @jmini @etherealjoy @spacether |
I was so excited to find this pull request 🙏 very eager to have this functionality added Thanks for your continued work on this @bernie-schelberg-mywave |
Hi @wing328 @jimschubert @cbornet @jmini @etherealjoy @spacether, I don't mean to be a pest, but is there a timeline we can expect to have this change merged? Without this fix generators like the Each entry in the union creates a file that looks like this (the output of the The union itself creates a file with the invalid operations and missing references. specifically:
|
@bernie-schelberg-mywave thanks again for the PR. would you be able to resolve the merge conflicts for the last time? I'll merge it once the merge conflicts have been resolved. |
# Conflicts: # modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java
as discussed the CI failure is not related to this change. i'll look into the CI failures after merging this PR. |
Hi @wing328 This fix isn't in 7.0.0-Beta? I am not seeing the changes there - it still says string required for me. |
Today when using discriminator a new type is generated. How can I use it and reference it to the original type?
Now when using discriminator with union (python) I am getting a whole new enum with a super long name,which has nothing to do with the original enum type |
As described in #12412, it's reasonably common to define the valid options for a discriminator property as an enum. However, the current versions of the generator assume the discriminator property is always
string
. This change uses the specified type when it is explicitly defined as a separate type in the schema. I attempted to also handle the scenario where the enum property was specified inline, but it was too complicated for me.PR checklist
This is important, as CI jobs will verify all generator outputs of your HEAD commit as it would merge with master.
These must match the expectations made by your contribution.
You may regenerate an individual generator by passing the relevant config(s) as an argument to the script, for example
./bin/generate-samples.sh bin/configs/java*
.For Windows users, please run the script in Git BASH.
master
(6.1.0) (minor release - breaking changes with fallbacks),7.0.x
(breaking changes without fallbacks)