@@ -1019,35 +1019,35 @@ public void preprocessOpenAPI(OpenAPI openAPI) {
10191019 for (Map .Entry <String , PathItem > entry : openAPI .getPaths ().entrySet ()) {
10201020 String pathStr = entry .getKey ();
10211021 PathItem path = entry .getValue ();
1022- List <Operation > getOps = divideOperationsByContentType (pathStr , PathItem .HttpMethod .GET , path .getGet ());
1022+ List <Operation > getOps = divideOperationsByContentType (openAPI , pathStr , PathItem .HttpMethod .GET , path .getGet ());
10231023 if (!getOps .isEmpty ()) {
10241024 path .addExtension ("x-get" , getOps );
10251025 }
1026- List <Operation > putOps = divideOperationsByContentType (pathStr , PathItem .HttpMethod .PUT , path .getPut ());
1026+ List <Operation > putOps = divideOperationsByContentType (openAPI , pathStr , PathItem .HttpMethod .PUT , path .getPut ());
10271027 if (!putOps .isEmpty ()) {
10281028 path .addExtension ("x-put" , putOps );
10291029 }
1030- List <Operation > postOps = divideOperationsByContentType (pathStr , PathItem .HttpMethod .POST , path .getPost ());
1030+ List <Operation > postOps = divideOperationsByContentType (openAPI , pathStr , PathItem .HttpMethod .POST , path .getPost ());
10311031 if (!postOps .isEmpty ()) {
10321032 path .addExtension ("x-post" , postOps );
10331033 }
1034- List <Operation > deleteOps = divideOperationsByContentType (pathStr , PathItem .HttpMethod .DELETE , path .getDelete ());
1034+ List <Operation > deleteOps = divideOperationsByContentType (openAPI , pathStr , PathItem .HttpMethod .DELETE , path .getDelete ());
10351035 if (!deleteOps .isEmpty ()) {
10361036 path .addExtension ("x-delete" , deleteOps );
10371037 }
1038- List <Operation > optionsOps = divideOperationsByContentType (pathStr , PathItem .HttpMethod .OPTIONS , path .getOptions ());
1038+ List <Operation > optionsOps = divideOperationsByContentType (openAPI , pathStr , PathItem .HttpMethod .OPTIONS , path .getOptions ());
10391039 if (!optionsOps .isEmpty ()) {
10401040 path .addExtension ("x-options" , optionsOps );
10411041 }
1042- List <Operation > headOps = divideOperationsByContentType (pathStr , PathItem .HttpMethod .HEAD , path .getHead ());
1042+ List <Operation > headOps = divideOperationsByContentType (openAPI , pathStr , PathItem .HttpMethod .HEAD , path .getHead ());
10431043 if (!headOps .isEmpty ()) {
10441044 path .addExtension ("x-head" , headOps );
10451045 }
1046- List <Operation > patchOps = divideOperationsByContentType (pathStr , PathItem .HttpMethod .PATCH , path .getPatch ());
1046+ List <Operation > patchOps = divideOperationsByContentType (openAPI , pathStr , PathItem .HttpMethod .PATCH , path .getPatch ());
10471047 if (!patchOps .isEmpty ()) {
10481048 path .addExtension ("x-patch" , patchOps );
10491049 }
1050- List <Operation > traceOps = divideOperationsByContentType (pathStr , PathItem .HttpMethod .TRACE , path .getTrace ());
1050+ List <Operation > traceOps = divideOperationsByContentType (openAPI , pathStr , PathItem .HttpMethod .TRACE , path .getTrace ());
10511051 if (!traceOps .isEmpty ()) {
10521052 path .addExtension ("x-trace" , traceOps );
10531053 }
@@ -1135,24 +1135,29 @@ public void preprocessOpenAPI(OpenAPI openAPI) {
11351135 }
11361136 }
11371137
1138- private List <Operation > divideOperationsByContentType (String path , PathItem .HttpMethod httpMethod , Operation op ) {
1138+ private List <Operation > divideOperationsByContentType (OpenAPI openAPI , String path , PathItem .HttpMethod httpMethod , Operation op ) {
11391139
11401140 if (op == null ) {
11411141 return Collections .emptyList ();
11421142 }
11431143
1144+ var operationIndexes = new HashMap <String , Integer >();
1145+ operationIndexes .put (getOrGenerateOperationId (op , path , httpMethod .name ()), 0 );
1146+
11441147 var additionalOps = new ArrayList <Operation >();
1145- divideOperationByRequestBody (path , httpMethod , op , additionalOps );
1148+ divideOperationByRequestBody (openAPI , path , httpMethod , op , additionalOps , operationIndexes );
11461149
11471150 // Check responses content types and divide operations by them
11481151
11491152 var responses = op .getResponses ();
11501153 if (responses == null || responses .isEmpty ()) {
11511154 return additionalOps ;
11521155 }
1156+ var unwrappedResponses = new ApiResponses ();
11531157 var allPossibleContentTypes = new ArrayList <String >();
11541158 for (var responseEntry : responses .entrySet ()) {
1155- var apiResponse = responseEntry .getValue ();
1159+ var apiResponse = ModelUtils .getReferencedApiResponse (openAPI , responseEntry .getValue ());
1160+ unwrappedResponses .put (responseEntry .getKey (), apiResponse );
11561161 if (apiResponse .getContent () == null ) {
11571162 continue ;
11581163 }
@@ -1166,6 +1171,8 @@ private List<Operation> divideOperationsByContentType(String path, PathItem.Http
11661171 if (allPossibleContentTypes .isEmpty () || allPossibleContentTypes .size () == 1 ) {
11671172 return additionalOps ;
11681173 }
1174+ op .setResponses (unwrappedResponses );
1175+ responses = unwrappedResponses ;
11691176
11701177 var apiResponsesByContentType = new HashMap <String , ApiResponses >();
11711178 for (var contentType : allPossibleContentTypes ) {
@@ -1184,7 +1191,7 @@ private List<Operation> divideOperationsByContentType(String path, PathItem.Http
11841191 .description (response .getDescription ())
11851192 .headers (response .getHeaders ())
11861193 .links (response .getLinks ())
1187- .extensions (response .getExtensions ())
1194+ .extensions (response .getExtensions () != null ? new LinkedHashMap <>( response . getExtensions ()) : new LinkedHashMap <>() )
11881195 .$ref (response .get$ref ())
11891196 .content (new Content ()
11901197 .addMediaType (contentType , mediaType )
@@ -1194,21 +1201,34 @@ private List<Operation> divideOperationsByContentType(String path, PathItem.Http
11941201 apiResponsesByContentType .put (contentType , apiResponses );
11951202 }
11961203
1204+ var addedContentTypes = new ArrayList <String >();
11971205 var finalAdditionalOps = new ArrayList <Operation >();
1198- divideOperationByResponses (path , httpMethod , op , apiResponsesByContentType , finalAdditionalOps );
1206+ divideOperationByResponses (path , httpMethod , op , apiResponsesByContentType , finalAdditionalOps , addedContentTypes , operationIndexes );
11991207 for (var additionalOp : additionalOps ) {
12001208 finalAdditionalOps .add (additionalOp );
1201- divideOperationByResponses (path , httpMethod , additionalOp , apiResponsesByContentType , finalAdditionalOps );
1209+ divideOperationByResponses (path , httpMethod , additionalOp , apiResponsesByContentType , finalAdditionalOps , addedContentTypes , operationIndexes );
1210+ }
1211+
1212+ // remove correct processed contentTypes
1213+ apiResponsesByContentType .entrySet ().removeIf (stringMediaTypeEntry -> addedContentTypes .contains (stringMediaTypeEntry .getKey ()));
1214+
1215+ if (!apiResponsesByContentType .isEmpty ()) {
1216+ appendCommonResponseMediaTypes (op , apiResponsesByContentType .values ());
1217+ for (var additionalOp : additionalOps ) {
1218+ appendCommonResponseMediaTypes (additionalOp , apiResponsesByContentType .values ());
1219+ }
12021220 }
12031221
12041222 return finalAdditionalOps ;
12051223 }
12061224
1207- private void divideOperationByRequestBody (String path , PathItem .HttpMethod httpMethod , Operation op , List <Operation > additionalOps ) {
1208- RequestBody body = op .getRequestBody ();
1225+ private void divideOperationByRequestBody (OpenAPI openAPI , String path , PathItem .HttpMethod httpMethod , Operation op ,
1226+ List <Operation > additionalOps , Map <String , Integer > operationIndexes ) {
1227+ RequestBody body = ModelUtils .getReferencedRequestBody (openAPI , op .getRequestBody ());
12091228 if (body == null || body .getContent () == null ) {
12101229 return ;
12111230 }
1231+ op .setRequestBody (body );
12121232 Content content = body .getContent ();
12131233 if (content .size () <= 1 ) {
12141234 return ;
@@ -1224,28 +1244,34 @@ private void divideOperationByRequestBody(String path, PathItem.HttpMethod httpM
12241244 var foundSameOpSignature = false ;
12251245 // group by response content type
12261246 if (groupByResponseContentType ) {
1227- for (var additionalOp : additionalOps ) {
1228- RequestBody additionalBody = additionalOp .getRequestBody ();
1229- if (additionalBody == null || additionalBody .getContent () == null ) {
1230- return ;
1247+ if (firstEntry .getValue ().equals (mediaType )) {
1248+ if (!groupByRequestAndResponseContentType ) {
1249+ foundSameOpSignature = true ;
12311250 }
1232- for (var addContentEntry : additionalBody .getContent ().entrySet ()) {
1233- if (addContentEntry .getValue ().equals (mediaType )) {
1234- foundSameOpSignature = true ;
1251+ } else {
1252+ for (var additionalOp : additionalOps ) {
1253+ RequestBody additionalBody = ModelUtils .getReferencedRequestBody (openAPI , additionalOp .getRequestBody ());
1254+ if (additionalBody == null || additionalBody .getContent () == null ) {
1255+ return ;
1256+ }
1257+ for (var addContentEntry : additionalBody .getContent ().entrySet ()) {
1258+ if (addContentEntry .getValue ().equals (mediaType )) {
1259+ foundSameOpSignature = true ;
1260+ break ;
1261+ }
1262+ }
1263+ if (foundSameOpSignature ) {
1264+ additionalBody .getContent ().put (contentType , mediaType );
12351265 break ;
12361266 }
12371267 }
1238- if (foundSameOpSignature ) {
1239- additionalBody .getContent ().put (contentType , mediaType );
1240- break ;
1241- }
12421268 }
12431269 }
12441270
1245- mediaTypesToRemove .add (contentType );
12461271 if (groupByResponseContentType && foundSameOpSignature ) {
12471272 continue ;
12481273 }
1274+ mediaTypesToRemove .add (contentType );
12491275
12501276 var apiResponsesCopy = new ApiResponses ();
12511277 apiResponsesCopy .putAll (op .getResponses ());
@@ -1254,9 +1280,9 @@ private void divideOperationByRequestBody(String path, PathItem.HttpMethod httpM
12541280 .deprecated (op .getDeprecated ())
12551281 .callbacks (op .getCallbacks ())
12561282 .description (op .getDescription ())
1257- .extensions (op .getExtensions ())
1283+ .extensions (op .getExtensions () != null ? new LinkedHashMap <>( op . getExtensions ()) : new LinkedHashMap <>() )
12581284 .externalDocs (op .getExternalDocs ())
1259- .operationId (getOrGenerateOperationId ( op , path , httpMethod . name () ))
1285+ .operationId (calcOperationId ( path , httpMethod , op , operationIndexes ))
12601286 .parameters (op .getParameters ())
12611287 .responses (apiResponsesCopy )
12621288 .security (op .getSecurity ())
@@ -1276,13 +1302,33 @@ private void divideOperationByRequestBody(String path, PathItem.HttpMethod httpM
12761302 }
12771303 }
12781304
1305+ private String calcOperationId (String path , PathItem .HttpMethod httpMethod , Operation op , Map <String , Integer > operationIndexes ) {
1306+ var operationId = getOrGenerateOperationId (op , path , httpMethod .name ());
1307+ var index = operationIndexes .get (operationId );
1308+ if (index != null ) {
1309+ index ++;
1310+ operationId += "_" + index ;
1311+ operationIndexes .put (operationId , index );
1312+ } else {
1313+ operationIndexes .put (operationId , 0 );
1314+ }
1315+ return operationId ;
1316+ }
1317+
12791318 private void divideOperationByResponses (
12801319 String path ,
12811320 PathItem .HttpMethod httpMethod ,
12821321 Operation op ,
12831322 Map <String , ApiResponses > apiResponsesByContentType ,
1284- List <Operation > additionalOps
1323+ List <Operation > additionalOps ,
1324+ List <String > addedContentTypes ,
1325+ Map <String , Integer > operationIndexes
12851326 ) {
1327+
1328+ if (!groupByResponseContentType ) {
1329+ return ;
1330+ }
1331+
12861332 var isFirst = true ;
12871333 for (var entry : apiResponsesByContentType .entrySet ()) {
12881334 var contentType = entry .getKey ();
@@ -1295,6 +1341,7 @@ private void divideOperationByResponses(
12951341 && !requestBody .getContent ().containsKey (contentType )) {
12961342 continue ;
12971343 }
1344+ addedContentTypes .add (contentType );
12981345 if (isFirst ) {
12991346 op .setResponses (apiResponses );
13001347 isFirst = false ;
@@ -1307,7 +1354,7 @@ private void divideOperationByResponses(
13071354 .description (op .getDescription ())
13081355 .extensions (op .getExtensions ())
13091356 .externalDocs (op .getExternalDocs ())
1310- .operationId (getOrGenerateOperationId ( op , path , httpMethod . name () ))
1357+ .operationId (calcOperationId ( path , httpMethod , op , operationIndexes ))
13111358 .parameters (op .getParameters ())
13121359 .responses (apiResponses )
13131360 .security (op .getSecurity ())
@@ -1319,6 +1366,30 @@ private void divideOperationByResponses(
13191366 }
13201367 }
13211368
1369+ private void appendCommonResponseMediaTypes (Operation op , Collection <ApiResponses > commonResponsesList ) {
1370+ if (commonResponsesList .isEmpty ()) {
1371+ return ;
1372+ }
1373+
1374+ for (var commonResponses : commonResponsesList ) {
1375+ var adOpResponses = op .getResponses ();
1376+ for (var responseEntry : adOpResponses .entrySet ()) {
1377+ var content = responseEntry .getValue ().getContent ();
1378+ var commonResponse = commonResponses .get (responseEntry .getKey ());
1379+ if (commonResponse != null && commonResponse .getContent () != null ) {
1380+ if (content == null ) {
1381+ content = new Content ();
1382+ }
1383+ for (var commonResponseEntry : commonResponse .getContent ().entrySet ()) {
1384+ if (!content .containsKey (commonResponseEntry .getKey ())) {
1385+ content .addMediaType (commonResponseEntry .getKey (), commonResponseEntry .getValue ());
1386+ }
1387+ }
1388+ }
1389+ }
1390+ }
1391+ }
1392+
13221393 // override with any special handling of the entire OpenAPI spec document
13231394 @ Override
13241395 @ SuppressWarnings ("unused" )
0 commit comments