swagger-api / swagger-parser

Swagger Spec to Java POJOs
http://swagger.io
Apache License 2.0
780 stars 526 forks source link

External Refs with same name are ignored #2055

Open anthochristen opened 7 months ago

anthochristen commented 7 months ago

When external referenced components have the same name but different definitions, only the first is considered, the rest seem to be ignored. This seems to be because of the way the JSON pointers are used to derive the component name in Refutils.

RefUtils.java

   if (definitionPath != null) { //the name will come from the last element of the definition path

"the name will come from the last element of the definition path" - I couldn't find any documentation as to why this is done, nor did I see any mention of this in this spec. This could likely cause issues as the definitions with same names are allow if the it is provided in-line.

P.S: Originally identified by @crankydillo.

openapi.json

{
    "openapi": "3.0.3",
    "info": {
        "version": "1.0.0",
        "title": "OpenAPI Service",
        "description": "Sample OpenAPI generated swagger contract"
    },
    "paths": {
        "/a-path": {
            "post": {
                "operationId": "ignoredRefPost",
                "parameters": [
                    { "$ref": "./external_ref_1.json#/limit" }
                ],
                "requestBody": { "$ref": "external_ref_1.json#/a-request" },
                "responses": {
                    "200": {
                        "$ref": "external_ref_1.json#/a-response"
                    },
                    "default": {
                        "$ref": "#/components/responses/default-string"
                    }
                }
            },
            "put": {
                "operationId": "ignoredRefPut",
                "parameters": [
                    { "$ref": "./external_ref_2.json#/limit" }
                ],
                "requestBody": { "$ref": "external_ref_2.json#/a-request" },
                "responses": {
                    "200": {
                        "$ref": "external_ref_2.json#/a-response"
                    },
                    "default": {
                        "$ref": "#/components/responses/default-string"
                    }
                }
            }
        }
    },
    "components": {
        "responses": {
            "default-string": {
                "description": "some string",
                "content": {
                    "text/plain": {
                        "schema": {
                            "type": "string"
                        }
                    }
                }
            }
        }
    }
}

external_ref1.json

{
  "limit": {
    "name": "limit",
    "description": "There can be only 1!",
    "in": "query",
    "schema": {
      "type": "integer",
      "maximum": 1,
      "minimum": 0
    }
  },
 "a-request": {
   "required": true,
   "description": "a string req",
   "content": {
     "text/plain": {
       "schema": {
         "type": "string"
       }
     }
   }
},
  "a-response": {
    "description": "some string response",
    "content": {
      "text/plain": {
        "schema": {
          "type": "string"
        }
      }
    }
  }
}

external_ref_2.json

{
  "limit": {
    "name": "limit",
    "description": "There can be only 2!",
    "in": "query",
    "schema": {
      "type": "integer",
      "maximum": 2,
      "minimum": 0
    }
  },
  "a-response": {
    "description": "some string response",
    "content": {
      "appilication/json": {
        "schema": {
          "schema": {
            "$ref": "#/an-object"
            }
        }
      }
    }
  },
  "an-object": {
    "type": "object",
    "properties": {
      "a-prop": {
        "type": "string"
      }
    }
  },
  "a-request": {
    "required": true,
    "description": "a JSON req",
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/an-object"
        }
      }
    }
  }
}

Main.java

ParseOptions options = new ParseOptions();
options.setResolve(true);
OpenAPI openAPI = new OpenAPIV3Parser().read("openapi.json", null, options);
System.out.println("Parameters: " + openAPI.getComponents().getParameters().keySet());
System.out.println("Responses: " + openAPI.getComponents().getResponses().keySet());
System.out.println("Requests: " + openAPI.getComponents().getRequestBodies().keySet());
kota65535 commented 7 months ago

Same here. Is this an expected behavior?