Skip to content

Commit 6f211a2

Browse files
OcsidotAnthony TODISCO
andauthored
[Protobuf] Fix Discriminator Issue and add capability Enum Extraction (#22740)
* fix(protobuf-codegen): Fix protobuf import path with discriminator This PR fixes a critical bug in the protobuf schema generator where models using discriminators with �llOf composition were generating invalid import paths when child schemas contained references to other models. * fix: Add missing element in OpenAPI discriminator test case * feat(protobuf-generator): Improve protobuf generation * Improve management of inheritance * Improve management of discriminator * Allow to separate inline enums in external files * Add unit test * fix: Improve logic when extracting enums to avoid collision in enum values * fix: Manage case with Enum in lists * fix: Fix issue on enum extraction Fix issue linked to enum in array when there is inheritance or discriminator * doc: Add documentation for new parameter * chore: Update protobuf samples --------- Co-authored-by: Anthony TODISCO <Anthony.TODISCO+amadeus@amadeus.com>
1 parent 82ad061 commit 6f211a2

18 files changed

Lines changed: 1837 additions & 55 deletions

File tree

docs/generators/protobuf-schema.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
2222
|aggregateModelsName|Aggregated model filename. If set, all generated models will be combined into this single file.| |null|
2323
|customOptionsApi|Custom options for the api files.| |null|
2424
|customOptionsModel|Custom options for the model files.| |null|
25+
|extractEnumsToSeparateFiles|Extract enums to separate protobuf files and import them in models| |false|
2526
|numberedFieldNumberList|Field numbers in order.| |false|
2627
|startEnumsWithUnspecified|Introduces &quot;UNSPECIFIED&quot; as the first element of enumerations.| |false|
2728
|supportMultipleResponses|Support multiple responses| |true|

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,10 @@ public MappedModel(String mappingName, String modelName, boolean explicitMapping
8888
this.explicitMapping = explicitMapping;
8989
}
9090

91+
public boolean isExplicitMapping() {
92+
return explicitMapping;
93+
}
94+
9195
public MappedModel(String mappingName, String modelName) {
9296
this(mappingName, modelName, false);
9397
}

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

Lines changed: 872 additions & 39 deletions
Large diffs are not rendered by default.
Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,26 @@
1-
enum {{classname}} {
2-
{{#allowableValues}}
3-
{{#enumVars}}
4-
{{{name}}} = {{{protobuf-enum-index}}};
5-
{{/enumVars}}
6-
{{/allowableValues}}
1+
{{!
2+
Generates an extracted enum wrapped in a message container.
3+
4+
This wrapper pattern is used to prevent enum value name collisions
5+
in the Protocol Buffers global enum namespace. Multiple enums can
6+
have values with the same name when wrapped in separate messages.
7+
8+
Generated format:
9+
message EnumName {
10+
enum Enum {
11+
VALUE1 = 0;
12+
VALUE2 = 1;
13+
}
14+
}
15+
16+
Usage in models: EnumName.Enum field_name = 1;
17+
}}
18+
message {{classname}} {
19+
enum Enum {
20+
{{#allowableValues}}
21+
{{#enumVars}}
22+
{{{name}}} = {{{protobuf-enum-index}}};
23+
{{/enumVars}}
24+
{{/allowableValues}}
25+
}
726
}

modules/openapi-generator/src/main/resources/protobuf-schema/model.mustache

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import public "{{{.}}}.proto";
3737
{{#vendorExtensions.x-protobuf-type}}{{{.}}} {{/vendorExtensions.x-protobuf-type}}{{{vendorExtensions.x-protobuf-data-type}}} {{{name}}} = {{vendorExtensions.x-protobuf-index}}{{#vendorExtensions.x-protobuf-packed}} [packed=true]{{/vendorExtensions.x-protobuf-packed}}{{#vendorExtensions.x-protobuf-json-name}} [json_name="{{vendorExtensions.x-protobuf-json-name}}"]{{/vendorExtensions.x-protobuf-json-name}};
3838
{{/isEnum}}
3939
{{#isEnum}}
40+
{{^vendorExtensions.x-protobuf-enum-reference-import}}
4041
enum {{enumName}} {
4142
{{#allowableValues}}
4243
{{#enumVars}}
@@ -45,7 +46,8 @@ import public "{{{.}}}.proto";
4546
{{/allowableValues}}
4647
}
4748

48-
{{enumName}} {{name}} = {{vendorExtensions.x-protobuf-index}};
49+
{{/vendorExtensions.x-protobuf-enum-reference-import}}
50+
{{#vendorExtensions.x-protobuf-type}}{{{.}}} {{/vendorExtensions.x-protobuf-type}}{{{vendorExtensions.x-protobuf-data-type}}} {{name}} = {{vendorExtensions.x-protobuf-index}};
4951
{{/isEnum}}
5052

5153
{{/vars}}

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

Lines changed: 655 additions & 0 deletions
Large diffs are not rendered by default.

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ components:
4848
properties:
4949
name:
5050
type: string
51+
characteristics:
52+
$ref: '#/components/schemas/Characteristics'
5153
Reptile:
5254
allOf:
5355
- $ref: '#/components/schemas/Pet'
@@ -78,7 +80,7 @@ components:
7880
- $ref: '#/components/schemas/Lizard'
7981
discriminator:
8082
propertyName: petType
81-
# per https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#discriminatorObject
83+
# per https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#discriminator-object
8284
# this discriminator must be included to use it as a hint to pick a schema
8385
MyPetsNoDisc:
8486
oneOf:
@@ -101,3 +103,8 @@ components:
101103
C:
102104
allOf:
103105
- $ref: '#/components/schemas/B'
106+
Characteristics:
107+
type: object
108+
properties:
109+
canHunt:
110+
type: boolean
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
openapi: 3.0.3
2+
info:
3+
title: OAI Specification example for Polymorphism
4+
version: 1.0.0
5+
paths:
6+
/status:
7+
get:
8+
responses:
9+
'201':
10+
description: desc
11+
12+
components:
13+
schemas:
14+
Animal:
15+
type: object
16+
required:
17+
- petType
18+
properties:
19+
petType:
20+
type: string
21+
discriminator:
22+
propertyName: petType
23+
mapping:
24+
dog: '#/components/schemas/Dog'
25+
cat: '#/components/schemas/Cat'
26+
Feline:
27+
allOf:
28+
- $ref: '#/components/schemas/Animal'
29+
- type: object
30+
properties:
31+
name:
32+
type: string
33+
furColor:
34+
type: string
35+
Cat:
36+
allOf:
37+
- $ref: '#/components/schemas/Feline'
38+
- type: object
39+
properties:
40+
isIndoor:
41+
type: boolean
42+
careDetails:
43+
$ref: '#/components/schemas/CareDetails'
44+
Dog:
45+
allOf:
46+
- $ref: '#/components/schemas/Animal'
47+
- type: object
48+
properties:
49+
bark:
50+
type: string
51+
CareDetails:
52+
type: object
53+
properties:
54+
veterinarian:
55+
type: string
56+
lastVetVisit:
57+
type: string
58+
format: date
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
OAI Specification example for Polymorphism
3+
4+
No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
5+
6+
The version of the OpenAPI document: 1.0.0
7+
8+
Generated by OpenAPI Generator: https://openapi-generator.tech
9+
*/
10+
11+
syntax = "proto3";
12+
13+
package openapitools;
14+
15+
import public "models/care_details.proto";
16+
17+
message Animal {
18+
19+
string pet_type = 482112090;
20+
21+
string name = 3373707;
22+
23+
string fur_color = 478695002;
24+
25+
bool is_indoor = 183319801;
26+
27+
CareDetails care_details = 176721135;
28+
29+
string bark = 3016376;
30+
31+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
openapi: 3.0.0
2+
info:
3+
title: Enum extraction test
4+
version: '2.0'
5+
paths: {}
6+
components:
7+
schemas:
8+
SeparatedEnum:
9+
type: string
10+
enum:
11+
- VALUE1
12+
- VALUE2
13+
ModelWithEnums:
14+
type: object
15+
properties:
16+
referenceEnumProperty:
17+
$ref: "#/components/schemas/SeparatedEnum"
18+
inlineEnumProperty:
19+
type: string
20+
enum:
21+
- VALUE2
22+
- VALUE3
23+
- VALUE4
24+
listOfEnums:
25+
type: array
26+
items:
27+
type: string
28+
enum:
29+
- VALUE10
30+
- VALUE11
31+
AllOfModelWithEnums:
32+
allOf:
33+
- $ref: "#/components/schemas/ModelWithEnums"
34+
- type: object
35+
properties:
36+
anotherInlineEnumProperty:
37+
type: string
38+
enum:
39+
- VALUE5
40+
- VALUE6
41+
listOfReferencedEnums:
42+
type: array
43+
items:
44+
$ref: '#/components/schemas/SeparatedEnum'
45+
DiscriminatedModel:
46+
type: object
47+
properties:
48+
commonProperty:
49+
type: string
50+
modelType:
51+
type: string
52+
discriminator:
53+
propertyName: modelType
54+
mapping:
55+
typeA: "#/components/schemas/ModelTypeAWithInlineEnum"
56+
typeB: "#/components/schemas/ModelTypeBWithInlineEnum"
57+
ModelTypeAWithInlineEnum:
58+
allOf:
59+
- $ref: "#/components/schemas/DiscriminatedModel"
60+
- type: object
61+
properties:
62+
specificPropertyA:
63+
type: string
64+
inlineEnumProperty:
65+
type: string
66+
enum:
67+
- VALUE7
68+
- VALUE8
69+
ModelTypeBWithInlineEnum:
70+
allOf:
71+
- $ref: "#/components/schemas/DiscriminatedModel"
72+
- type: object
73+
properties:
74+
specificPropertyB:
75+
type: string
76+
referenceEnumPropertyB:
77+
$ref: "#/components/schemas/SeparatedEnum"

0 commit comments

Comments
 (0)