Skip to content

Commit 53be847

Browse files
committed
Add options to aggregate protos to one file
1 parent 1655275 commit 53be847

19 files changed

Lines changed: 208 additions & 290 deletions

File tree

bin/configs/protobuf-schema-config.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ additionalProperties:
88
numberedFieldNumberList: true
99
startEnumsWithUnspecified: true
1010
wrapComplexType: false
11+
aggregateModelsName: data
1112
typeMappings:
1213
object: "google.protobuf.Struct"
1314
importMappings:

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

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@
4242
import java.util.*;
4343
import java.util.Map.Entry;
4444
import java.util.regex.Pattern;
45+
import java.util.stream.Collectors;
46+
4547
import com.google.common.base.CaseFormat;
4648

4749
import static org.openapitools.codegen.utils.StringUtils.*;
@@ -64,10 +66,14 @@ public class ProtobufSchemaCodegen extends DefaultCodegen implements CodegenConf
6466

6567
public static final String WRAP_COMPLEX_TYPE = "wrapComplexType";
6668

69+
public static final String AGGREGATE_MODELS_NAME = "aggregateModelsName";
70+
6771
private final Logger LOGGER = LoggerFactory.getLogger(ProtobufSchemaCodegen.class);
6872

6973
@Setter protected String packageName = "openapitools";
7074

75+
@Setter protected String aggregateModelsName = null;
76+
7177
private boolean numberedFieldNumberList = false;
7278

7379
private boolean startEnumsWithUnspecified = false;
@@ -186,6 +192,7 @@ public ProtobufSchemaCodegen() {
186192
addSwitch(START_ENUMS_WITH_UNSPECIFIED, "Introduces \"UNSPECIFIED\" as the first element of enumerations.", startEnumsWithUnspecified);
187193
addSwitch(ADD_JSON_NAME_ANNOTATION, "Append \"json_name\" annotation to message field when the specification name differs from the protobuf field name", addJsonNameAnnotation);
188194
addSwitch(WRAP_COMPLEX_TYPE, "Generate Additional message for complex type", wrapComplexType);
195+
addOption(AGGREGATE_MODELS_NAME, "Aggregated model filename. If set, all generated models will be combined into this single file.", null);
189196
}
190197

191198
@Override
@@ -228,6 +235,10 @@ public void processOpts() {
228235
this.wrapComplexType = convertPropertyToBooleanAndWriteBack(WRAP_COMPLEX_TYPE);
229236
}
230237

238+
if (additionalProperties.containsKey(AGGREGATE_MODELS_NAME)) {
239+
this.setAggregateModelsName((String) additionalProperties.get(AGGREGATE_MODELS_NAME));
240+
}
241+
231242
supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));
232243
}
233244

@@ -650,7 +661,35 @@ public Map<String, ModelsMap> postProcessAllModels(Map<String, ModelsMap> objs)
650661
.forEach(importFromList -> this.addImport(objs, parentCM, importFromList));
651662
}
652663
}
653-
return objs;
664+
return aggregateModelsName == null ? objs : aggregateModels(objs);
665+
}
666+
667+
/**
668+
* Aggregates all individual model definitions into a single entry.
669+
*
670+
* @param objs the original map of model names to their respective entries
671+
* @return a new {@link Map} containing a single entry keyed by {@code aggregateModelsName} with
672+
* combined models and imports from all provided entries
673+
*/
674+
public Map<String, ModelsMap> aggregateModels(Map<String, ModelsMap> objs) {
675+
Map<String, ModelsMap> objects = new HashMap<>();
676+
ModelsMap aggregateObj = objs.values().stream()
677+
.findFirst()
678+
.orElse(new ModelsMap());
679+
680+
List<ModelMap> models = objs.values().stream()
681+
.flatMap(modelsMap -> modelsMap.getModels().stream())
682+
.collect(Collectors.toList());
683+
684+
Set<Map<String, String>> imports = objs.values().stream()
685+
.flatMap(modelsMap -> modelsMap.getImports().stream())
686+
.filter(importMap -> !importMap.get("import").startsWith("models/"))
687+
.collect(Collectors.toSet());
688+
689+
aggregateObj.setModels(models);
690+
aggregateObj.setImports(new ArrayList<>(imports));
691+
objects.put(this.aggregateModelsName, aggregateObj);
692+
return objects;
654693
}
655694

656695
public void addImport(Map<String, ModelsMap> objs, CodegenModel cm, String importValue) {
@@ -907,6 +946,11 @@ public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List<Mo
907946
}
908947
}
909948

949+
if (this.aggregateModelsName != null) {
950+
List<Map<String, String>> aggregate_imports = Collections.singletonList(Collections
951+
.singletonMap(IMPORT, toModelImport(this.aggregateModelsName)));
952+
objs.setImports(aggregate_imports);
953+
}
910954
return objs;
911955
}
912956

samples/config/petstore/protobuf-schema-config/.openapi-generator/FILES

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,5 @@
11
README.md
2-
models/api_response.proto
3-
models/cat.proto
4-
models/category.proto
5-
models/dog.proto
6-
models/order.proto
7-
models/other_test.proto
8-
models/pet.proto
9-
models/pets_get_request.proto
10-
models/pets_post_request.proto
11-
models/tag.proto
12-
models/user.proto
2+
models/data.proto
133
services/default_service.proto
144
services/pet_service.proto
155
services/store_service.proto

samples/config/petstore/protobuf-schema-config/README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# gPRC for petstore
1+
# gPRC for openapitools
22

33
This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
44

@@ -17,15 +17,15 @@ Below are some usage examples for Go and Ruby. For other languages, please refer
1717
### Go
1818
```
1919
# assuming `protoc-gen-go` has been installed with `go get -u github.com/golang/protobuf/protoc-gen-go`
20-
mkdir /var/tmp/go/petstore
21-
protoc --go_out=/var/tmp/go/petstore services/*
22-
protoc --go_out=/var/tmp/go/petstore models/*
20+
mkdir /var/tmp/go/openapitools
21+
protoc --go_out=/var/tmp/go/openapitools services/*
22+
protoc --go_out=/var/tmp/go/openapitools models/*
2323
```
2424

2525
### Ruby
2626
```
2727
# assuming `grpc_tools_ruby_protoc` has been installed via `gem install grpc-tools`
28-
RUBY_OUTPUT_DIR="/var/tmp/ruby/petstore"
28+
RUBY_OUTPUT_DIR="/var/tmp/ruby/openapitools"
2929
mkdir $RUBY_OUTPUT_DIR
3030
grpc_tools_ruby_protoc --ruby_out=$RUBY_OUTPUT_DIR --grpc_out=$RUBY_OUTPUT_DIR/lib services/*
3131
grpc_tools_ruby_protoc --ruby_out=$RUBY_OUTPUT_DIR --grpc_out=$RUBY_OUTPUT_DIR/lib models/*

samples/config/petstore/protobuf-schema-config/models/api_response.proto

Lines changed: 0 additions & 24 deletions
This file was deleted.

samples/config/petstore/protobuf-schema-config/models/cat.proto

Lines changed: 0 additions & 22 deletions
This file was deleted.

samples/config/petstore/protobuf-schema-config/models/category.proto

Lines changed: 0 additions & 22 deletions
This file was deleted.
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
/*
2+
OpenAPI Petstore
3+
4+
This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
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 "google/protobuf/struct.proto";
16+
17+
message ApiResponse {
18+
19+
int32 code = 1;
20+
21+
string type = 2;
22+
23+
string message = 3;
24+
25+
}
26+
message Cat {
27+
28+
bool hunts = 1;
29+
30+
int32 age = 2;
31+
32+
}
33+
message Category {
34+
35+
int64 id = 1;
36+
37+
string name = 2;
38+
39+
}
40+
message Dog {
41+
42+
bool bark = 1;
43+
44+
enum Breed {
45+
BREED_UNSPECIFIED = 0;
46+
BREED_DINGO = 1;
47+
BREED_HUSKY = 2;
48+
BREED_RETRIEVER = 3;
49+
BREED_SHEPHERD = 4;
50+
}
51+
52+
Breed breed = 2;
53+
54+
}
55+
message Order {
56+
57+
int64 id = 1;
58+
59+
int64 pet_id = 2 [json_name="petId"];
60+
61+
int32 quantity = 3;
62+
63+
string ship_date = 4 [json_name="shipDate"];
64+
65+
// Order Status
66+
enum Status {
67+
STATUS_UNSPECIFIED = 0;
68+
STATUS_PLACED = 1;
69+
STATUS_APPROVED = 2;
70+
STATUS_DELIVERED = 3;
71+
}
72+
73+
Status status = 5;
74+
75+
bool complete = 6;
76+
77+
google.protobuf.Struct meta = 7;
78+
79+
}
80+
message OtherTest {
81+
82+
repeated string set_test = 1;
83+
84+
}
85+
message Pet {
86+
87+
int64 id = 1;
88+
89+
Category category = 2;
90+
91+
string name = 3;
92+
93+
repeated string photo_urls = 4 [json_name="photoUrls"];
94+
95+
repeated Tag tags = 5;
96+
97+
// pet status in the store
98+
enum Status {
99+
STATUS_UNSPECIFIED = 0;
100+
STATUS_AVAILABLE = 1;
101+
STATUS_PENDING = 2;
102+
STATUS_SOLD = 3;
103+
}
104+
105+
Status status = 6;
106+
107+
}
108+
message PetsGetRequest {
109+
110+
oneof pets_get_request {
111+
Cat cat = 1;
112+
Dog dog = 2;
113+
}
114+
}
115+
message PetsPostRequest {
116+
117+
Cat cat = 1;
118+
119+
Dog dog = 2;
120+
121+
}
122+
message Tag {
123+
124+
int64 id = 1;
125+
126+
string name = 2;
127+
128+
}
129+
message User {
130+
131+
int64 id = 1;
132+
133+
string username = 2;
134+
135+
string first_name = 3 [json_name="firstName"];
136+
137+
string last_name = 4 [json_name="lastName"];
138+
139+
string email = 5;
140+
141+
string password = 6;
142+
143+
string phone = 7;
144+
145+
// User Status
146+
int32 user_status = 8 [json_name="userStatus"];
147+
148+
}

samples/config/petstore/protobuf-schema-config/models/dog.proto

Lines changed: 0 additions & 30 deletions
This file was deleted.

0 commit comments

Comments
 (0)