Repository: swagger-api/swagger-parser (java)

Issue:
Parser is not resolving the requestBody to make it inline as its doing for responses 
**MetaData** :
- Swagger Parser Version : 2.0.31
- OAS Version: 3.0.0
- Simple Reproducible Spec is pasted at the end

**Reproducible Code Snippet** :
```
io.swagger.v3.parser.core.models.ParseOptions parseOptions = new io.swagger.v3.parser.core.models.ParseOptions();
parseOptions.setResolve(true);
parseOptions.setFlatten(true);
SwaggerParseResult result = new OpenAPIParser().readLocation("<PATH TO SPEC>\\OAS3_Inline_Request_Response_Usecase.json", null, parseOptions);
```

**Context** : 
We're using the above snippet for the following reasons and explanation against it -
1. resolve is true: We have usecases where there are external json references and resolve is best fit for us to solve the problem of localizing the external references.
2. flatten is true: We have some usecases that have inline schema definitions for requestBody and responses in an operation. And we need to make them ref locally from components section. And for this flatten is the best fit.

**Issue and Observations** :
- We basically were using the spec below expecting Swagger Parser to flatten up the inline schemas for my referenced requestBody and response, and  then make them refer from components section. 
- We observed that the SwaggerParser works fine for responses in flattening up but NOT for requestBody.
- We debugged the flatten implementation, and was shocked that it only fattens the _path inline_ schemas and the schemas under _components/schema_ section, then how is it working for responses. 
- We then suspected that there's something in the _resolve_ implementation that is making responses work.
- And bingo, we found it was the exact case and [here's](https://github.com/swagger-api/swagger-parser/blob/e29a4f44ea53afe35a32c5fc8bf49012a857593f/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/processors/OperationProcessor.java#L54) the link pointing to that code. I dug deep to find the commit and here it is --> [commit](https://github.com/swagger-api/swagger-parser/commit/ab0fbe9f56f12c3399a1d71df87465344e7c612d#diff-8ea24f208841d2105efdceef4d2b24f670cff0b6d06c29dda48dd3a11125a612)
- So its not doing the same for request.
- Hey @gracekarina, I also have a fix for the same, its on the similar lines as its done for responses, I'll raise the PR soon.

**Impact and why we can't use ResolveFully** :
- This very crucial for our Q2 roadmap items.
- We are not able to resolve the inline schemas for the referenced requestBody from components section.
- We can't use resolveFully because it will make everything inline and then we intend to flatten every inline thing, which will rename the older models local references that were not inline, to the newer flattened up naming local reference. I am afraid that using resolveFully and then flatten will lead us to some regressions in our product. Making use of resolve and flatten is the best combination for us, or rather the correct one as we don't wan't to unnecessarily over process using resolveFully.
- The sample we've attached is very basic, and we have very complex usecases that have this inline flavour of referenced requestBody.
- Hey @gracekarina, Please request to help merge the similar changes I am raising in the PR for the requestBody.

**OAS3 Spec** :
```
{
	"openapi": "3.0.0",
	"info": {
		"version": "1.0",
		"title": "Resource service",
		"description": "Resource service"
	},
	"servers": [
		{
			"url": "http://localhost:8088/"
		}
	],
	"paths": {
		"/resource": {
			"post": {
				"summary": "postResource",
				"description": "postResource",
				"operationId": "post-resource",
				"parameters": [],
				"requestBody": {
					"$ref": "#/components/requestBodies/ResourceBodyPost"
				},
				"responses": {
					"200": {
						"$ref": "#/components/responses/ResourceSuccessResponse"
					}
				}
			}
		}
	},
	"components": {
		"requestBodies": {
			"ResourceBodyPost": {
				"content": {
					"application/json": {
						"schema": {
							"type": "object",
							"required": [
								"rqname"
							],
							"properties": {
								"rqname": {
									"type": "string"
								},
								"rqnumber": {
									"type": "integer",
									"format": "int32"
								},
								"rqflag": {
									"type": "boolean"
								}
							}
						}
					}
				}
			}
		},
		"responses": {
			"ResourceSuccessResponse": {
				"description": "a Element to be returned",
				"content": {
					"application/json": {
						"schema": {
							"type": "object",
							"required": [
								"rname"
							],
							"properties": {
								"rname": {
									"type": "string"
								},
								"rnumber": {
									"type": "integer",
									"format": "int32"
								},
								"rflag": {
									"type": "boolean"
								}
							}
						}
					}
				}
			}
		},
		"schemas": {}
	}
}
```

Pull request:
Fixed #1706
This makes the request body inline as we're already doing it for responses.
This will help flatten api to leverage the inline schema for this resolved request body which has an inline schema inside it.

Patch:
diff --git a/.gitignore b/.gitignore
index 9af33e6d..846589f1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,3 +12,4 @@ modules/swagger-parser/src/test/resources/relative-file-references/yaml
 **/test-output/*
 dependency-reduced-pom.xml
 *.pyc
+/bin/
diff --git a/README.md b/README.md
index 7019fb33..9d40a969 100644
--- a/README.md
+++ b/README.md
@@ -261,7 +261,7 @@ components:
       example: Example value
 ```
 
-#### 3. flatten : 
+#### 3. flatten: 
 
 ```java
 ParseOptions parseOptions = new ParseOptions();
diff --git a/modules/swagger-parser-core/src/main/java/io/swagger/v3/parser/core/models/ParseOptions.java b/modules/swagger-parser-core/src/main/java/io/swagger/v3/parser/core/models/ParseOptions.java
index 65bb3e6b..7b478ef9 100644
--- a/modules/swagger-parser-core/src/main/java/io/swagger/v3/parser/core/models/ParseOptions.java
+++ b/modules/swagger-parser-core/src/main/java/io/swagger/v3/parser/core/models/ParseOptions.java
@@ -12,7 +12,8 @@ public class ParseOptions {
     private boolean validateExternalRefs = false;
     private boolean validateInternalRefs = true;
     private boolean legacyYamlDeserialization = false;
-
+    private boolean resolveRequestBody = false;
+    
     public boolean isResolve() {
         return resolve;
     }
@@ -36,6 +37,19 @@ public class ParseOptions {
     public void setResolveFully(boolean resolveFully) {
         this.resolveFully = resolveFully;
     }
+    
+    public boolean isResolveRequestBody() {
+        return resolveRequestBody;
+    }
+
+    /**
+     * If set to true, will help resolving the requestBody as inline, provided
+     * resolve is also set to true. Default is false because of the existing
+     * behaviour.
+     */
+    public void setResolveRequestBody(boolean resolveRequestBody) {
+        this.resolveRequestBody = resolveRequestBody;
+    }
 
     public boolean isFlatten() { return flatten; }
 
diff --git a/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/ResolverCache.java b/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/ResolverCache.java
index a1e7ffff..f143ae85 100644
--- a/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/ResolverCache.java
+++ b/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/ResolverCache.java
@@ -68,12 +68,12 @@ public class ResolverCache {
     private Map<String, String> externalFileCache = new HashMap<>();
     private List<String> referencedModelKeys = new ArrayList<>();
     private Set<String> resolveValidationMessages;
-
     private final ParseOptions parseOptions;
 
 
     /*
-    a map that stores original external references, and their associated renamed references
+     * a map that stores original external references, and their associated renamed
+     * references
      */
     private Map<String, String> renameCache = new HashMap<>();
 
@@ -394,4 +394,8 @@ public class ResolverCache {
     public Map<String, String> getRenameCache() {
         return Collections.unmodifiableMap(renameCache);
     }
+
+    public ParseOptions getParseOptions() {
+        return parseOptions;
+    }
 }
diff --git a/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/processors/OperationProcessor.java b/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/processors/OperationProcessor.java
index cc6cf566..d24a3b1b 100644
--- a/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/processors/OperationProcessor.java
+++ b/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/processors/OperationProcessor.java
@@ -31,7 +31,6 @@ public class OperationProcessor {
         this.responseProcessor = new ResponseProcessor(cache,openAPI);
         this.requestBodyProcessor = new RequestBodyProcessor(cache,openAPI);
         this.externalRefProcessor = new ExternalRefProcessor(cache, openAPI);
-
         this.cache = cache;
     }
 
@@ -40,18 +39,30 @@ public class OperationProcessor {
         if(processedOperationParameters != null) {
             operation.setParameters(processedOperationParameters);
         }
-        final RequestBody requestBody = operation.getRequestBody();
-        if(requestBody != null) {
+
+        RequestBody requestBody = operation.getRequestBody();
+        if (requestBody != null) {
+            // This part allows paser to put requestBody inline without the resolveFully
+            // option set to true
+            if (requestBody.get$ref() != null && cache != null && cache.getParseOptions() != null && cache.getParseOptions().isResolveRequestBody()) {
+                requestBodyProcessor.processRequestBody(requestBody);
+                RefFormat refFormat = computeRefFormat(requestBody.get$ref());
+                RequestBody resolvedRequestBody = cache.loadRef(requestBody.get$ref(), refFormat, RequestBody.class);
+
+                if (resolvedRequestBody != null) {
+                    requestBody = resolvedRequestBody;
+                    operation.setRequestBody(resolvedRequestBody);
+                }
+            }
             requestBodyProcessor.processRequestBody(requestBody);
         }
 
-
         final Map<String, ApiResponse> responses = operation.getResponses();
         if (responses != null) {
             for (String responseCode : responses.keySet()) {
                 ApiResponse response = responses.get(responseCode);
                 if(response != null) {
-                    //This part allows parser to put response schema inline without the resolveFully option set to true
+                    //This part allows parser to put response inline without the resolveFully option set to true
                     if (response.get$ref() != null) {
 
                         responseProcessor.processResponse(response);


Test patch:
diff --git a/modules/swagger-parser-v3/src/test/java/io/swagger/v3/parser/test/OpenAPIResolverTest.java b/modules/swagger-parser-v3/src/test/java/io/swagger/v3/parser/test/OpenAPIResolverTest.java
index ead7e79d..15344888 100644
--- a/modules/swagger-parser-v3/src/test/java/io/swagger/v3/parser/test/OpenAPIResolverTest.java
+++ b/modules/swagger-parser-v3/src/test/java/io/swagger/v3/parser/test/OpenAPIResolverTest.java
@@ -595,6 +595,30 @@ public class OpenAPIResolverTest {
         assertTrue(colouringPropertySchema == colouringsSchema);
 
     }
+    
+    @Test
+    public void testIssue1706() {
+        String path = "/issue-1706/SimpleRequestResponseRef.json";
+
+        ParseOptions options = new ParseOptions();
+        options.setResolve(true);
+        // Added this parseOption to make requestBody inline in the operation resolve processing flow.
+        options.setResolveRequestBody(true);
+
+        OpenAPI openAPI = new OpenAPIV3Parser().readLocation(path, null, options).getOpenAPI();
+        
+        // RequestBody should be inline
+        assertTrue(openAPI.getPaths().get("/resource").getPost().getRequestBody().get$ref() == null);
+        assertTrue(openAPI.getPaths().get("/resource").getPost().getRequestBody().getContent() != null);
+        assertTrue(openAPI.getPaths().get("/resource").getPost().getRequestBody().getContent().get("application/json").getSchema() instanceof ObjectSchema);
+        
+        // Responses are already by default made inline in case referenced.
+        assertTrue(openAPI.getPaths().get("/resource").getPost().getResponses().get("200").get$ref() == null);
+        assertTrue(openAPI.getPaths().get("/resource").getPost().getResponses().get("200").getContent() != null);
+        assertTrue(openAPI.getPaths().get("/resource").getPost().getResponses().get("200").getContent().get("application/json").getSchema() instanceof ObjectSchema);        
+    }
+    
+    
 
     @Test
     public void selfReferenceTest(@Injectable final List<AuthorizationValue> auths) {
diff --git a/modules/swagger-parser-v3/src/test/resources/issue-1706/SimpleRequestResponseRef.json b/modules/swagger-parser-v3/src/test/resources/issue-1706/SimpleRequestResponseRef.json
new file mode 100644
index 00000000..ac874e75
--- /dev/null
+++ b/modules/swagger-parser-v3/src/test/resources/issue-1706/SimpleRequestResponseRef.json
@@ -0,0 +1,89 @@
+{
+    "openapi": "3.0.0",
+    "info": {
+        "version": "1.0",
+        "title": "Resource service",
+        "description": "Resource service"
+    },
+    "servers": [
+        {
+            "url": "http://localhost:8088/"
+        }
+    ],
+    "paths": {
+        "/resource": {
+            "post": {
+                "summary": "postResource",
+                "description": "postResource",
+                "operationId": "post-resource",
+                "parameters": [],
+                "requestBody": {
+                    "$ref": "#/components/requestBodies/ResourceBodyPost"
+                },
+                "responses": {
+                    "200": {
+                        "$ref": "#/components/responses/ResourceSuccessResponse"
+                    }
+                }
+            }
+        }
+    },
+    "components": {
+        "requestBodies": {
+            "ResourceBodyPost": {
+                "content": {
+                    "application/json": {
+                        "schema": {
+                            "type": "object",
+                            "required": [
+                                "rqname"
+                            ],
+                            "properties": {
+                                "rqname": {
+                                    "type": "string"
+                                },
+                                "rqnumber": {
+                                    "type": "integer",
+                                    "format": "int32"
+                                },
+                                "rqflag": {
+                                    "type": "boolean"
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        "responses": {
+            "ResourceSuccessResponse": {
+                "description": "a Element to be returned",
+                "content": {
+                    "application/json": {
+                        "schema": {
+                            "type": "object",
+                            "required": [
+                                "rname"
+                            ],
+                            "properties": {
+                                "rname": {
+                                    "type": "string"
+                                },
+                                "rnumber": {
+                                    "type": "integer",
+                                    "format": "int32"
+                                },
+                                "rflag": {
+                                    "type": "boolean"
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        "schemas": {
+            
+        }
+    }
+}
\ No newline at end of file