86
86
import java .util .stream .Collectors ;
87
87
import java .util .stream .Stream ;
88
88
89
+ import static org .openapitools .codegen .CodegenConstants .DIVIDE_OPERATIONS_BY_CONTENT_TYPE ;
89
90
import static org .openapitools .codegen .CodegenConstants .UNSUPPORTED_V310_SPEC_MSG ;
90
91
import static org .openapitools .codegen .utils .CamelizeOption .LOWERCASE_FIRST_LETTER ;
91
92
import static org .openapitools .codegen .utils .OnceLogger .once ;
@@ -392,7 +393,7 @@ public void processOpts() {
392
393
convertPropertyToBooleanAndWriteBack (CodegenConstants .DISALLOW_ADDITIONAL_PROPERTIES_IF_NOT_PRESENT , this ::setDisallowAdditionalPropertiesIfNotPresent );
393
394
convertPropertyToBooleanAndWriteBack (CodegenConstants .ENUM_UNKNOWN_DEFAULT_CASE , this ::setEnumUnknownDefaultCase );
394
395
convertPropertyToBooleanAndWriteBack (CodegenConstants .AUTOSET_CONSTANTS , this ::setAutosetConstants );
395
- }
396
+ }
396
397
397
398
398
399
/***
@@ -999,6 +1000,49 @@ public void postProcessParameter(CodegenParameter parameter) {
999
1000
@ Override
1000
1001
@ SuppressWarnings ("unused" )
1001
1002
public void preprocessOpenAPI (OpenAPI openAPI ) {
1003
+
1004
+ var divideOperationsByContentType = Boolean .parseBoolean (GlobalSettings .getProperty (DIVIDE_OPERATIONS_BY_CONTENT_TYPE , "false" ));
1005
+
1006
+ if (divideOperationsByContentType && openAPI .getPaths () != null && !openAPI .getPaths ().isEmpty ()) {
1007
+
1008
+ for (Map .Entry <String , PathItem > entry : openAPI .getPaths ().entrySet ()) {
1009
+ String pathStr = entry .getKey ();
1010
+ PathItem path = entry .getValue ();
1011
+ List <Operation > getOps = divideOperationsByContentType (pathStr , PathItem .HttpMethod .GET , path .getGet ());
1012
+ if (!getOps .isEmpty ()) {
1013
+ path .addExtension ("x-get" , getOps );
1014
+ }
1015
+ List <Operation > putOps = divideOperationsByContentType (pathStr , PathItem .HttpMethod .PUT , path .getPut ());
1016
+ if (!putOps .isEmpty ()) {
1017
+ path .addExtension ("x-put" , putOps );
1018
+ }
1019
+ List <Operation > postOps = divideOperationsByContentType (pathStr , PathItem .HttpMethod .POST , path .getPost ());
1020
+ if (!postOps .isEmpty ()) {
1021
+ path .addExtension ("x-post" , postOps );
1022
+ }
1023
+ List <Operation > deleteOps = divideOperationsByContentType (pathStr , PathItem .HttpMethod .DELETE , path .getDelete ());
1024
+ if (!deleteOps .isEmpty ()) {
1025
+ path .addExtension ("x-delete" , deleteOps );
1026
+ }
1027
+ List <Operation > optionsOps = divideOperationsByContentType (pathStr , PathItem .HttpMethod .OPTIONS , path .getOptions ());
1028
+ if (!optionsOps .isEmpty ()) {
1029
+ path .addExtension ("x-options" , optionsOps );
1030
+ }
1031
+ List <Operation > headOps = divideOperationsByContentType (pathStr , PathItem .HttpMethod .HEAD , path .getHead ());
1032
+ if (!headOps .isEmpty ()) {
1033
+ path .addExtension ("x-head" , headOps );
1034
+ }
1035
+ List <Operation > patchOps = divideOperationsByContentType (pathStr , PathItem .HttpMethod .PATCH , path .getPatch ());
1036
+ if (!patchOps .isEmpty ()) {
1037
+ path .addExtension ("x-patch" , patchOps );
1038
+ }
1039
+ List <Operation > traceOps = divideOperationsByContentType (pathStr , PathItem .HttpMethod .TRACE , path .getTrace ());
1040
+ if (!traceOps .isEmpty ()) {
1041
+ path .addExtension ("x-trace" , traceOps );
1042
+ }
1043
+ }
1044
+ }
1045
+
1002
1046
if (useOneOfInterfaces && openAPI .getComponents () != null ) {
1003
1047
// we process the openapi schema here to find oneOf schemas and create interface models for them
1004
1048
Map <String , Schema > schemas = new HashMap <>(openAPI .getComponents ().getSchemas ());
@@ -1080,6 +1124,77 @@ public void preprocessOpenAPI(OpenAPI openAPI) {
1080
1124
}
1081
1125
}
1082
1126
1127
+ private List <Operation > divideOperationsByContentType (String path , PathItem .HttpMethod httpMethod , Operation op ) {
1128
+
1129
+ if (op == null ) {
1130
+ return Collections .emptyList ();
1131
+ }
1132
+
1133
+ var additionalOps = new ArrayList <Operation >();
1134
+
1135
+ RequestBody body = op .getRequestBody ();
1136
+ if (body == null || body .getContent () == null ) {
1137
+ return Collections .emptyList ();
1138
+ }
1139
+ Content content = body .getContent ();
1140
+ if (content .size () <= 1 ) {
1141
+ return Collections .emptyList ();
1142
+ }
1143
+ var firstEntry = content .entrySet ().iterator ().next ();
1144
+ var mediaTypesToRemove = new ArrayList <String >();
1145
+ for (var entry : content .entrySet ()) {
1146
+ if (mediaTypesToRemove .contains (entry .getKey ()) || entry .getKey ().equals (firstEntry .getKey ()) || entry .getValue ().equals (firstEntry .getValue ())) {
1147
+ continue ;
1148
+ }
1149
+ var foundSameOpSignature = false ;
1150
+ for (var additionalOp : additionalOps ) {
1151
+ RequestBody additionalBody = additionalOp .getRequestBody ();
1152
+ if (additionalBody == null || additionalBody .getContent () == null ) {
1153
+ return Collections .emptyList ();
1154
+ }
1155
+ for (var addContentEntry : additionalBody .getContent ().entrySet ()) {
1156
+ if (addContentEntry .getValue ().equals (entry .getValue ())) {
1157
+ foundSameOpSignature = true ;
1158
+ break ;
1159
+ }
1160
+ }
1161
+ if (foundSameOpSignature ) {
1162
+ additionalBody .getContent ().put (entry .getKey (), entry .getValue ());
1163
+ break ;
1164
+ }
1165
+ }
1166
+ mediaTypesToRemove .add (entry .getKey ());
1167
+ if (foundSameOpSignature ) {
1168
+ continue ;
1169
+ }
1170
+ additionalOps .add (new Operation ()
1171
+ .deprecated (op .getDeprecated ())
1172
+ .callbacks (op .getCallbacks ())
1173
+ .description (op .getDescription ())
1174
+ .extensions (op .getExtensions ())
1175
+ .externalDocs (op .getExternalDocs ())
1176
+ .operationId (getOrGenerateOperationId (op , path , httpMethod .name ()))
1177
+ .parameters (op .getParameters ())
1178
+ .responses (op .getResponses ())
1179
+ .security (op .getSecurity ())
1180
+ .servers (op .getServers ())
1181
+ .summary (op .getSummary ())
1182
+ .tags (op .getTags ())
1183
+ .requestBody (new RequestBody ()
1184
+ .description (body .getDescription ())
1185
+ .extensions (body .getExtensions ())
1186
+ .content (new Content ()
1187
+ .addMediaType (entry .getKey (), entry .getValue ()))
1188
+ )
1189
+ );
1190
+ }
1191
+ if (!mediaTypesToRemove .isEmpty ()) {
1192
+ content .entrySet ().removeIf (stringMediaTypeEntry -> mediaTypesToRemove .contains (stringMediaTypeEntry .getKey ()));
1193
+ }
1194
+
1195
+ return additionalOps ;
1196
+ }
1197
+
1083
1198
// override with any special handling of the entire OpenAPI spec document
1084
1199
@ Override
1085
1200
@ SuppressWarnings ("unused" )
@@ -1164,8 +1279,7 @@ public String encodePath(String input) {
1164
1279
*/
1165
1280
@ Override
1166
1281
public String escapeUnsafeCharacters (String input ) {
1167
- LOGGER .warn ("escapeUnsafeCharacters should be overridden in the code generator with proper logic to escape " +
1168
- "unsafe characters" );
1282
+ LOGGER .warn ("escapeUnsafeCharacters should be overridden in the code generator with proper logic to escape unsafe characters" );
1169
1283
// doing nothing by default and code generator should implement
1170
1284
// the logic to prevent code injection
1171
1285
// later we'll make this method abstract to make sure
@@ -1181,8 +1295,7 @@ public String escapeUnsafeCharacters(String input) {
1181
1295
*/
1182
1296
@ Override
1183
1297
public String escapeQuotationMark (String input ) {
1184
- LOGGER .warn ("escapeQuotationMark should be overridden in the code generator with proper logic to escape " +
1185
- "single/double quote" );
1298
+ LOGGER .warn ("escapeQuotationMark should be overridden in the code generator with proper logic to escape single/double quote" );
1186
1299
return input .replace ("\" " , "\\ \" " );
1187
1300
}
1188
1301
0 commit comments