Skip to content

Commit a42f90b

Browse files
Fix #12412 Use enum type for discriminator (#13846)
* Fix #12412 Use enum type for discriminator * Rename variable * Fix required property in test resource * Add example of enum mapping to samples * Generate samples * Generate samples after merging master * Regenerate samples * Fix raw use of parameterized class * Add test showing serialization and deserialization of classes with enum discriminator * Remove old generated files * Generate samples * Generate samples
1 parent b465d88 commit a42f90b

29 files changed

Lines changed: 1156 additions & 7 deletions

File tree

modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3526,22 +3526,30 @@ protected CodegenDiscriminator createDiscriminator(String schemaName, Schema sch
35263526
return null;
35273527
}
35283528
CodegenDiscriminator discriminator = new CodegenDiscriminator();
3529-
String discPropName = sourceDiscriminator.getPropertyName();
3530-
discriminator.setPropertyName(toVarName(discPropName));
3529+
String discriminatorPropertyName = sourceDiscriminator.getPropertyName();
3530+
discriminator.setPropertyName(toVarName(discriminatorPropertyName));
35313531
discriminator.setPropertyBaseName(sourceDiscriminator.getPropertyName());
35323532
discriminator.setPropertyGetter(toGetter(discriminator.getPropertyName()));
35333533

35343534
if (sourceDiscriminator.getExtensions() != null) {
35353535
discriminator.setVendorExtensions(sourceDiscriminator.getExtensions());
35363536
}
35373537

3538-
// FIXME: for now, we assume that the discriminator property is String
3539-
discriminator.setPropertyType(typeMapping.get("string"));
3538+
// FIXME: there are other ways to define the type of the discriminator property (inline
3539+
// for example). Handling those scenarios is too complicated for me, I'm leaving it for
3540+
// the future..
3541+
String propertyType =
3542+
Optional.ofNullable(schema.getProperties())
3543+
.map(p -> (Schema<?>) p.get(discriminatorPropertyName))
3544+
.map(Schema::get$ref)
3545+
.map(ModelUtils::getSimpleRef)
3546+
.orElseGet(() -> typeMapping.get("string"));
3547+
discriminator.setPropertyType(propertyType);
35403548

35413549
// check to see if the discriminator property is an enum string
35423550
if (schema.getProperties() != null &&
3543-
schema.getProperties().get(discPropName) instanceof StringSchema) {
3544-
StringSchema s = (StringSchema) schema.getProperties().get(discPropName);
3551+
schema.getProperties().get(discriminatorPropertyName) instanceof StringSchema) {
3552+
StringSchema s = (StringSchema) schema.getProperties().get(discriminatorPropertyName);
35453553
if (s.getEnum() != null && !s.getEnum().isEmpty()) { // it's an enum string
35463554
discriminator.setIsEnum(true);
35473555
}
@@ -3586,7 +3594,7 @@ protected CodegenDiscriminator createDiscriminator(String schemaName, Schema sch
35863594
}
35873595
// if there are composed oneOf/anyOf schemas, add them to this discriminator
35883596
if (ModelUtils.isComposedSchema(schema) && !this.getLegacyDiscriminatorBehavior()) {
3589-
List<MappedModel> otherDescendants = getOneOfAnyOfDescendants(schemaName, discPropName, (ComposedSchema) schema, openAPI);
3597+
List<MappedModel> otherDescendants = getOneOfAnyOfDescendants(schemaName, discriminatorPropertyName, (ComposedSchema) schema, openAPI);
35903598
for (MappedModel otherDescendant : otherDescendants) {
35913599
if (!uniqueDescendants.contains(otherDescendant)) {
35923600
uniqueDescendants.add(otherDescendant);

modules/openapi-generator/src/test/java/org/openapitools/codegen/DefaultCodegenTest.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
import java.util.stream.Collectors;
5757

5858
import static junit.framework.Assert.assertEquals;
59+
import static org.assertj.core.api.Assertions.assertThat;
5960
import static org.testng.Assert.*;
6061

6162
public class DefaultCodegenTest {
@@ -1509,6 +1510,12 @@ public void testComposedSchemaOneOfDiscriminatorMap() {
15091510
hs.add(new CodegenDiscriminator.MappedModel(mn, mn));
15101511
Assert.assertEquals(cm.discriminator.getMappedModels(), hs);
15111512

1513+
// ref oneOf models with enum property discriminator
1514+
modelName = "FruitOneOfEnumMappingDisc";
1515+
sc = openAPI.getComponents().getSchemas().get(modelName);
1516+
cm = codegen.fromModel(modelName, sc);
1517+
assertThat(cm.discriminator.getPropertyType()).isEqualTo("FruitTypeEnum");
1518+
15121519
// ref oneOf models with discriminator in the grandparent schemas of those oneof models
15131520
modelName = "FruitGrandparentDisc";
15141521
sc = openAPI.getComponents().getSchemas().get(modelName);

modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1538,6 +1538,55 @@ public void testDiscriminatorWithoutMappingIssue14731() throws IOException {
15381538
assertFileContains(Paths.get(outputPath + "/src/main/java/org/openapitools/model/ChildWithoutMappingBDTO.java"), "@JsonTypeName");
15391539
}
15401540

1541+
@Test
1542+
void testOneOfWithEnumDiscriminator() throws IOException {
1543+
File output = Files.createTempDirectory("test").toFile().getCanonicalFile();
1544+
output.deleteOnExit();
1545+
String outputPath = output.getAbsolutePath().replace('\\', '/');
1546+
OpenAPI openAPI = new OpenAPIParser()
1547+
.readLocation("src/test/resources/3_0/oneOfDiscriminator.yaml", null, new ParseOptions()).getOpenAPI();
1548+
1549+
SpringCodegen codegen = new SpringCodegen();
1550+
codegen.setOutputDir(output.getAbsolutePath());
1551+
codegen.additionalProperties().put(CXFServerFeatures.LOAD_TEST_DATA_FROM_FILE, "true");
1552+
codegen.setUseOneOfInterfaces(true);
1553+
1554+
ClientOptInput input = new ClientOptInput();
1555+
input.openAPI(openAPI);
1556+
input.config(codegen);
1557+
1558+
DefaultGenerator generator = new DefaultGenerator();
1559+
codegen.setHateoas(true);
1560+
generator.setGeneratorPropertyDefault(CodegenConstants.MODELS, "true");
1561+
//generator.setGeneratorPropertyDefault(CodegenConstants.USE_ONEOF_DISCRIMINATOR_LOOKUP, "true");
1562+
generator.setGeneratorPropertyDefault(CodegenConstants.LEGACY_DISCRIMINATOR_BEHAVIOR, "false");
1563+
1564+
codegen.setUseOneOfInterfaces(true);
1565+
codegen.setLegacyDiscriminatorBehavior(false);
1566+
1567+
generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_TESTS, "false");
1568+
generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_DOCS, "false");
1569+
generator.setGeneratorPropertyDefault(CodegenConstants.APIS, "true");
1570+
generator.setGeneratorPropertyDefault(CodegenConstants.SUPPORTING_FILES, "false");
1571+
1572+
generator.opts(input).generate();
1573+
1574+
assertFileContains(
1575+
Paths.get(outputPath + "/src/main/java/org/openapitools/model/FruitOneOfEnumMappingDisc.java"),
1576+
"public FruitTypeEnum getFruitType();"
1577+
);
1578+
assertFileContains(
1579+
Paths.get(outputPath + "/src/main/java/org/openapitools/model/AppleOneOfEnumMappingDisc.java"),
1580+
"private FruitTypeEnum fruitType;",
1581+
"public FruitTypeEnum getFruitType() {"
1582+
);
1583+
assertFileContains(
1584+
Paths.get(outputPath + "/src/main/java/org/openapitools/model/BananaOneOfEnumMappingDisc.java"),
1585+
"private FruitTypeEnum fruitType;",
1586+
"public FruitTypeEnum getFruitType() {"
1587+
);
1588+
}
1589+
15411590
@Test
15421591
public void testTypeMappings() {
15431592
final SpringCodegen codegen = new SpringCodegen();

modules/openapi-generator/src/test/resources/3_0/oneOfDiscriminator.yaml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,38 @@ components:
170170
type: integer
171171
oneOf:
172172
- $ref: '#/components/schemas/FruitType'
173+
FruitTypeEnum:
174+
type: string
175+
enum: [APPLE, BANANA]
176+
FruitOneOfEnumMappingDisc:
177+
type: object
178+
properties:
179+
fruitType:
180+
$ref: "#/components/schemas/FruitTypeEnum"
181+
required:
182+
- fruitType
183+
oneOf:
184+
- $ref: '#/components/schemas/AppleOneOfEnumMappingDisc'
185+
- $ref: '#/components/schemas/BananaOneOfEnumMappingDisc'
186+
discriminator:
187+
propertyName: fruitType
188+
mapping:
189+
APPLE: '#/components/schemas/AppleOneOfEnumMappingDisc'
190+
BANANA: '#/components/schemas/BananaOneOfEnumMappingDisc'
191+
AppleOneOfEnumMappingDisc:
192+
type: object
193+
required:
194+
- seeds
195+
properties:
196+
seeds:
197+
type: integer
198+
BananaOneOfEnumMappingDisc:
199+
type: object
200+
required:
201+
- length
202+
properties:
203+
length:
204+
type: integer
173205
FruitGrandparentDisc:
174206
oneOf:
175207
- $ref: '#/components/schemas/AppleGrandparentDisc'

modules/openapi-generator/src/test/resources/3_0/oneof_polymorphism_and_inheritance.yaml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,38 @@ components:
177177
type: string
178178
allOf:
179179
- $ref: '#/components/schemas/Pizza'
180+
FruitType:
181+
type: string
182+
enum: [APPLE, BANANA]
183+
Fruit:
184+
type: object
185+
properties:
186+
fruitType:
187+
$ref: "#/components/schemas/FruitType"
188+
required:
189+
- fruitType
190+
oneOf:
191+
- $ref: '#/components/schemas/Apple'
192+
- $ref: '#/components/schemas/Banana'
193+
discriminator:
194+
propertyName: fruitType
195+
mapping:
196+
APPLE: '#/components/schemas/Apple'
197+
BANANA: '#/components/schemas/Banana'
198+
Apple:
199+
type: object
200+
required:
201+
- seeds
202+
properties:
203+
seeds:
204+
type: integer
205+
Banana:
206+
type: object
207+
required:
208+
- length
209+
properties:
210+
length:
211+
type: integer
180212

181213
requestBodies:
182214
Foo:

samples/openapi3/client/petstore/dart-dio/oneof_polymorphism_and_inheritance/.openapi-generator/FILES

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
README.md
33
analysis_options.yaml
44
doc/Addressable.md
5+
doc/Apple.md
6+
doc/Banana.md
57
doc/Bar.md
68
doc/BarApi.md
79
doc/BarCreate.md
@@ -14,6 +16,8 @@ doc/Foo.md
1416
doc/FooApi.md
1517
doc/FooRef.md
1618
doc/FooRefOrValue.md
19+
doc/Fruit.md
20+
doc/FruitType.md
1721
doc/Pasta.md
1822
doc/Pizza.md
1923
doc/PizzaSpeziale.md
@@ -29,6 +33,8 @@ lib/src/auth/bearer_auth.dart
2933
lib/src/auth/oauth.dart
3034
lib/src/date_serializer.dart
3135
lib/src/model/addressable.dart
36+
lib/src/model/apple.dart
37+
lib/src/model/banana.dart
3238
lib/src/model/bar.dart
3339
lib/src/model/bar_create.dart
3440
lib/src/model/bar_ref.dart
@@ -40,6 +46,8 @@ lib/src/model/extensible.dart
4046
lib/src/model/foo.dart
4147
lib/src/model/foo_ref.dart
4248
lib/src/model/foo_ref_or_value.dart
49+
lib/src/model/fruit.dart
50+
lib/src/model/fruit_type.dart
4351
lib/src/model/pasta.dart
4452
lib/src/model/pizza.dart
4553
lib/src/model/pizza_speziale.dart

samples/openapi3/client/petstore/dart-dio/oneof_polymorphism_and_inheritance/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ Class | Method | HTTP request | Description
7373
## Documentation For Models
7474

7575
- [Addressable](doc/Addressable.md)
76+
- [Apple](doc/Apple.md)
77+
- [Banana](doc/Banana.md)
7678
- [Bar](doc/Bar.md)
7779
- [BarCreate](doc/BarCreate.md)
7880
- [BarRef](doc/BarRef.md)
@@ -83,6 +85,8 @@ Class | Method | HTTP request | Description
8385
- [Foo](doc/Foo.md)
8486
- [FooRef](doc/FooRef.md)
8587
- [FooRefOrValue](doc/FooRefOrValue.md)
88+
- [Fruit](doc/Fruit.md)
89+
- [FruitType](doc/FruitType.md)
8690
- [Pasta](doc/Pasta.md)
8791
- [Pizza](doc/Pizza.md)
8892
- [PizzaSpeziale](doc/PizzaSpeziale.md)
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# openapi.model.Apple
2+
3+
## Load the model package
4+
```dart
5+
import 'package:openapi/api.dart';
6+
```
7+
8+
## Properties
9+
Name | Type | Description | Notes
10+
------------ | ------------- | ------------- | -------------
11+
**seeds** | **int** | |
12+
13+
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
14+
15+
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# openapi.model.Banana
2+
3+
## Load the model package
4+
```dart
5+
import 'package:openapi/api.dart';
6+
```
7+
8+
## Properties
9+
Name | Type | Description | Notes
10+
------------ | ------------- | ------------- | -------------
11+
**length** | **int** | |
12+
13+
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
14+
15+
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# openapi.model.Fruit
2+
3+
## Load the model package
4+
```dart
5+
import 'package:openapi/api.dart';
6+
```
7+
8+
## Properties
9+
Name | Type | Description | Notes
10+
------------ | ------------- | ------------- | -------------
11+
**fruitType** | [**FruitType**](FruitType.md) | |
12+
**seeds** | **int** | |
13+
**length** | **int** | |
14+
15+
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
16+
17+

0 commit comments

Comments
 (0)