Skip to content

Commit d2366f6

Browse files
Anthony TODISCOAnthony TODISCO
authored andcommitted
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.
1 parent e86daf9 commit d2366f6

6 files changed

Lines changed: 142 additions & 3 deletions

File tree

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

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ public ProtobufSchemaCodegen() {
139139
apiTemplateFiles.put("api.mustache", ".proto");
140140
embeddedTemplateDir = templateDir = "protobuf-schema";
141141
hideGenerationTimestamp = Boolean.TRUE;
142-
modelPackage = "models";
142+
super.setModelPackage("models");
143143
apiPackage = "services";
144144

145145
defaultIncludes = new HashSet<>(
@@ -749,9 +749,11 @@ public void addImport(Map<String, ModelsMap> objs, CodegenModel cm, String impor
749749
String modelFileName = this.toModelFilename(importValue);
750750
boolean skipImport = isImportAlreadyPresentInModel(objs, cm, modelFileName);
751751
if (!skipImport) {
752-
this.addImport(cm, importValue);
752+
// Use toModelImport to get the correct import path with model package prefix
753+
String processedImport = this.toModelImport(importValue);
754+
this.addImport(cm, processedImport);
753755
Map<String, String> importItem = new HashMap<>();
754-
importItem.put(IMPORT, modelFileName);
756+
importItem.put(IMPORT, processedImport);
755757
objs.get(cm.getName()).getImports().add(importItem);
756758
}
757759
}
@@ -1041,6 +1043,11 @@ public String toModelImport(String name) {
10411043
if ("".equals(modelPackage())) {
10421044
return name;
10431045
} else {
1046+
// Check if the name already starts with the model package path to avoid duplication
1047+
String modelPath = modelPackage() + "/";
1048+
if (name.startsWith(modelPath)) {
1049+
return name;
1050+
}
10441051
return modelPackage() + "/" + underscore(name);
10451052
}
10461053
}

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

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,4 +296,41 @@ public void unspecifiedEnumValuesIgnoredIfAlreadyPresent() {
296296
Assert.assertEquals(enumVars1.get(1).get("value"), "FOO");
297297
Assert.assertEquals(enumVars1.get(1).get("isString"), false);
298298
}
299+
300+
@Test(description = "Support multiple level of inheritance for discriminator - ensures properties from indirect children are included")
301+
public void testCodeGenWithAllOfDiscriminatorMultipleLevels() throws IOException {
302+
// set line break to \n across all platforms
303+
System.setProperty("line.separator", "\n");
304+
305+
File output = Files.createTempDirectory("test").toFile();
306+
307+
final CodegenConfigurator configurator = new CodegenConfigurator()
308+
.setGeneratorName("protobuf-schema")
309+
.setInputSpec("src/test/resources/3_0/allOf_composition_discriminator_multiple_inheritance.yaml")
310+
.setOutputDir(output.getAbsolutePath().replace("\\", "/"));
311+
312+
final ClientOptInput clientOptInput = configurator.toClientOptInput();
313+
DefaultGenerator generator = new DefaultGenerator();
314+
List<File> files = generator.opts(clientOptInput).generate();
315+
316+
TestUtils.ensureContainsFile(files, output, "models/animal.proto");
317+
Path path = Paths.get(output + "/models/animal.proto");
318+
319+
// Verify the generated file contains all expected properties from multi-level inheritance
320+
String generatedContent = new String(Files.readAllBytes(path), StandardCharsets.UTF_8);
321+
322+
// Properties from discriminated classes should be included:
323+
// From Dog (direct child): bark
324+
Assert.assertTrue(generatedContent.contains("string bark"), "Animal should contain 'bark' property from Dog");
325+
// From Feline (direct child): name, furColor
326+
Assert.assertTrue(generatedContent.contains("string name"), "Animal should contain 'name' property from Feline");
327+
Assert.assertTrue(generatedContent.contains("string fur_color"), "Animal should contain 'fur_color' property from Feline");
328+
// From Cat (indirect child through Feline): isIndoor, careDetails
329+
Assert.assertTrue(generatedContent.contains("bool is_indoor"), "Animal should contain 'is_indoor' property from Cat (indirect child)");
330+
Assert.assertTrue(generatedContent.contains("CareDetails care_details"), "Animal should contain 'care_details' property from Cat (indirect child)");
331+
332+
assertFileEquals(path, Paths.get("src/test/resources/3_0/protobuf-schema/animal.proto"));
333+
334+
output.deleteOnExit();
335+
}
299336
}

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

Lines changed: 2 additions & 0 deletions
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'
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 bark = 3016376;
22+
23+
string name = 3373707;
24+
25+
string fur_color = 478695002;
26+
27+
bool is_indoor = 183319801;
28+
29+
CareDetails care_details = 176721135;
30+
31+
}

modules/openapi-generator/src/test/resources/3_0/protobuf-schema/pet.proto

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,16 @@ syntax = "proto3";
1212

1313
package openapitools;
1414

15+
import public "models/characteristics.proto";
16+
1517
message Pet {
1618

1719
string pet_type = 482112090;
1820

1921
string name = 3373707;
2022

23+
Characteristics characteristics = 455429578;
24+
2125
string bark = 3016376;
2226

2327
bool loves_rocks = 465093427;

0 commit comments

Comments
 (0)