Repository: swagger-api/swagger-parser
Pull request #961 (2018-12-07 07:03:23)

Fixed Issue_948
Pull Request for #948 


Patch:
diff --git a/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/OpenAPIV3Parser.java b/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/OpenAPIV3Parser.java
index 58e9201f..07bdde3d 100644
--- a/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/OpenAPIV3Parser.java
+++ b/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/OpenAPIV3Parser.java
@@ -180,7 +180,9 @@ public class OpenAPIV3Parser implements SwaggerParserExtension {
                     if (options.isResolveFully()) {
                         result.setOpenAPI(new OpenAPIResolver(result.getOpenAPI(), auth, null).resolve());
                         new ResolverFully(options.isResolveCombinators()).resolveFully(result.getOpenAPI());
-                    } else if (options.isFlatten()) {
+
+                    }
+                    if (options.isFlatten()) {
                         new InlineModelResolver().flatten(result.getOpenAPI());
                     }
                 }else{
diff --git a/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/processors/ParameterProcessor.java b/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/processors/ParameterProcessor.java
index fde98ab3..b2d60b75 100644
--- a/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/processors/ParameterProcessor.java
+++ b/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/processors/ParameterProcessor.java
@@ -83,6 +83,11 @@ public class ParameterProcessor {
             if (parameter.get$ref() != null) {
                 RefFormat refFormat = computeRefFormat(parameter.get$ref());
                 final Parameter resolvedParameter = cache.loadRef(parameter.get$ref(), refFormat, Parameter.class);
+                if (parameter.get$ref().startsWith("#") && parameter.get$ref().indexOf("#/components/parameters") <= -1) {
+                    //TODO: Not possible to add warning during resolve doesn't accept result as an input. Hence commented below line.
+                    //result.warning(location, "The parameter should use Reference Object to link to parameters that are defined at the OpenAPI Object's components/parameters.");
+                    continue;
+                }
 
                 if(resolvedParameter == null) {
                     // can't resolve it!
@@ -92,7 +97,7 @@ public class ParameterProcessor {
                 // if the parameter exists, replace it
                 boolean matched = false;
                 for(Parameter param : processedPathLevelParameters) {
-                    if(param.getName().equals(resolvedParameter.getName())) {
+                    if(param != null && param.getName() != null && param.getName().equals(resolvedParameter.getName())) {
                         // ref param wins
                         matched = true;
                         break;
diff --git a/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/util/ResolverFully.java b/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/util/ResolverFully.java
index 43d74962..95438b30 100644
--- a/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/util/ResolverFully.java
+++ b/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/util/ResolverFully.java
@@ -314,7 +314,7 @@ public class ResolverFully {
                     Schema innerProperty = obj.getProperties().get(propertyName);
                     // reference check
                     if(schema != innerProperty) {
-                        if(resolvedProperties.get(propertyName) == null || resolvedProperties.get(propertyName) != innerProperty) {
+                        if(resolvedProperties.get(propertyName) == null && resolvedProperties.get(propertyName) != innerProperty) {
                             LOGGER.debug("avoiding infinite loop");
                             Schema resolved = resolveSchema(innerProperty);
                             updated.put(propertyName, resolved);
@@ -354,7 +354,7 @@ public class ResolverFully {
                         if (resolved.getProperties() != null) {
                             for (String key : properties.keySet()) {
                                 Schema prop = (Schema) resolved.getProperties().get(key);
-                                if(resolvedProperties.get(key) == null || resolvedProperties.get(key) != prop) {
+                                if(resolvedProperties.get(key) == null && resolvedProperties.get(key) != prop) {
                                     LOGGER.debug("avoiding infinite loop");
                                     Schema resolvedProp = resolveSchema(prop);
                                     model.addProperties(key,resolvedProp );
@@ -402,7 +402,7 @@ public class ResolverFully {
                             if (resolved.getProperties() != null) {
                                 for (String key : properties.keySet()) {
                                     Schema prop = (Schema) resolved.getProperties().get(key);
-                                    if(resolvedProperties.get(key) == null || resolvedProperties.get(key) != prop) {
+                                    if(resolvedProperties.get(key) == null && resolvedProperties.get(key) != prop) {
                                         LOGGER.debug("avoiding infinite loop");
                                         Schema resolvedProp = resolveSchema(prop);
                                         model.addProperties(key,resolvedProp );
@@ -451,7 +451,7 @@ public class ResolverFully {
                             if (resolved.getProperties() != null) {
                                 for (String key : properties.keySet()) {
                                     Schema prop = (Schema) resolved.getProperties().get(key);
-                                    if(resolvedProperties.get(key) == null || resolvedProperties.get(key) != prop) {
+                                    if(resolvedProperties.get(key) == null && resolvedProperties.get(key) != prop) {
                                         LOGGER.debug("avoiding infinite loop");
                                         Schema resolvedProp = resolveSchema(prop);
                                         model.addProperties(key,resolvedProp );
@@ -507,7 +507,7 @@ public class ResolverFully {
             Map<String, Schema> properties = model.getProperties();
             for (String propertyName : properties.keySet()) {
                 Schema property = (Schema) model.getProperties().get(propertyName);
-                if(resolvedProperties.get(propertyName) == null || resolvedProperties.get(propertyName) != property) {
+                if(resolvedProperties.get(propertyName) == null && resolvedProperties.get(propertyName) != property) {
                     LOGGER.debug("avoiding infinite loop");
                     Schema resolved = resolveSchema(property);
                     updated.put(propertyName, resolved);


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 e9473152..e5558ed5 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
@@ -1166,16 +1166,6 @@ public class OpenAPIResolverTest {
         }
     }
 
-    @Test
-    public void propertyNameMixup() {
-        ParseOptions parseOptions = new ParseOptions();
-        parseOptions.setResolveFully(true);
-        OpenAPI openAPI = new OpenAPIV3Parser().read("simple.yaml", null, parseOptions);
-        assertEquals(((StringSchema)openAPI.getComponents().getSchemas().get("Manufacturer").getProperties().get("name")).getExample(), "ACME Corporation");
-        Schema schema = openAPI.getPaths().get("/inventory").getGet().getResponses().get("200").getContent().get("application/json").getSchema();
-        assertEquals(((ObjectSchema) ((ArraySchema) schema).getItems().getProperties().get("manufacturer")).getProperties().get("name").getExample(), "ACME Corporation");
-    }
-
     public String replacePort(String url){
         String pathFile = url.replace("${dynamicPort}", String.valueOf(this.serverPort));
         return pathFile;
diff --git a/modules/swagger-parser-v3/src/test/java/io/swagger/v3/parser/test/OpenAPIV3ParserTest.java b/modules/swagger-parser-v3/src/test/java/io/swagger/v3/parser/test/OpenAPIV3ParserTest.java
index 8a1c31cc..f073579c 100644
--- a/modules/swagger-parser-v3/src/test/java/io/swagger/v3/parser/test/OpenAPIV3ParserTest.java
+++ b/modules/swagger-parser-v3/src/test/java/io/swagger/v3/parser/test/OpenAPIV3ParserTest.java
@@ -30,6 +30,7 @@ import io.swagger.v3.oas.models.parameters.QueryParameter;
 import io.swagger.v3.oas.models.parameters.RequestBody;
 import io.swagger.v3.oas.models.responses.ApiResponse;
 import io.swagger.v3.oas.models.security.SecurityScheme;
+import io.swagger.v3.parser.OpenAPIResolver;
 import io.swagger.v3.parser.OpenAPIV3Parser;
 import io.swagger.v3.parser.core.models.AuthorizationValue;
 import io.swagger.v3.parser.core.models.ParseOptions;
@@ -1608,6 +1609,16 @@ public class OpenAPIV3ParserTest {
 
     }
 
+    @Test
+    public void testIssue948() {
+        ParseOptions options = new ParseOptions();
+        options.setResolve(true);
+        SwaggerParseResult result = new OpenAPIV3Parser().readLocation("Issue_948.json", null, options);
+        new OpenAPIResolver(result.getOpenAPI()).resolve();
+        assertNotNull(result.getOpenAPI());
+
+    }
+
     public void shouldParseParameters() {
         ParseOptions parseOptions = new ParseOptions();
         parseOptions.setResolveFully(true);
diff --git a/modules/swagger-parser-v3/src/test/resources/Issue_948.json b/modules/swagger-parser-v3/src/test/resources/Issue_948.json
new file mode 100644
index 00000000..983c4394
--- /dev/null
+++ b/modules/swagger-parser-v3/src/test/resources/Issue_948.json
@@ -0,0 +1,109 @@
+{
+  "openapi":"3.0.0",
+  "info":{
+    "title":"Test",
+    "description":"Test API",
+    "version":"1.0"
+  },
+  "servers":[
+    {
+      "url":"http://localhost:8888/api"
+    }
+  ],
+  "paths":{
+    "/devices":{
+      "get":{
+        "tags":[
+          "devices"
+        ],
+        "summary":"List all Devices",
+        "operationId":"getDevices",
+        "parameters":[
+          {
+            "$ref":"#/components/headers/Content-Type"
+          },
+          {
+            "$ref":"#/components/parameters/idFrom"
+          },
+          {
+            "name":"category",
+            "in":"query",
+            "description":"A request parameter that matches against the device category.",
+            "schema":{
+              "$ref":"#/components/schemas/deviceCategory"
+            }
+          },
+          {
+            "name":"manufacturer",
+            "in":"query",
+            "description":"A request parameter that performs LIKE matching against the device manufacturer.",
+            "schema":{
+              "maxLength":200,
+              "minLength":1,
+              "type":"string",
+              "example":"Sony"
+            }
+          }
+        ],
+        "responses":{
+          "200":{
+            "description":"An array of devices that match the request parameters requested.",
+            "content":{
+              "application/json":{
+                "schema":{
+                  "type":"object",
+                  "properties":{
+                    "device":{
+                      "$ref":"#/components/schemas/device"
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  },
+  "components":{
+    "schemas":{
+      "deviceCategory":{
+        "type":"string",
+        "description":"The list of avialable viewer device categories.",
+        "example":"TV",
+        "enum":[
+          "TV",
+          "Phone",
+          "Tablet",
+          "Laptop",
+          "Monitor",
+          "Other"
+        ]
+      },
+      "device":{
+        "type":"string",
+        "description":"Captures the possible states for an analysis."
+      }
+    },
+    "parameters":{
+      "idFrom":{
+        "name":"idFrom",
+        "in":"query",
+        "description":"The lower-bound of a request parameter filtering based on unique object identifier.",
+        "schema":{
+          "type":"integer"
+        }
+      }
+    },
+    "headers":{
+      "Content-Type":{
+        "required":true,
+        "schema":{
+          "type":"string",
+          "example":"application/json;charset=UTF-8",
+          "default":"application/json;charset=UTF-8"
+        }
+      }
+    }
+  }
+}
diff --git a/modules/swagger-parser-v3/src/test/resources/simple.yaml b/modules/swagger-parser-v3/src/test/resources/simple.yaml
deleted file mode 100644
index d3940253..00000000
--- a/modules/swagger-parser-v3/src/test/resources/simple.yaml
+++ /dev/null
@@ -1,115 +0,0 @@
-openapi: 3.0.0
-info:
-  description: This is a simple API
-  version: "1.0.0"
-  title: Simple Inventory API
-  contact:
-    email: you@your-company.com
-  license:
-    name: Apache 2.0
-    url: 'http://www.apache.org/licenses/LICENSE-2.0.html'
-tags:
-- name: admins
-  description: Secured Admin-only calls
-- name: developers
-  description: Operations available to regular developers
-paths:
-  /inventory:
-    get:
-      tags:
-      - developers
-      summary: searches inventory
-      operationId: searchInventory
-      description: |
-        By passing in the appropriate options, you can search for
-        available inventory in the system
-      parameters:
-      - in: query
-        name: searchString
-        description: pass an optional search string for looking up inventory
-        required: false
-        schema:
-          type: string
-      - in: query
-        name: skip
-        description: number of records to skip for pagination
-        schema:
-          type: integer
-          format: int32
-          minimum: 0
-      - in: query
-        name: limit
-        description: maximum number of records to return
-        schema:
-          type: integer
-          format: int32
-          minimum: 0
-          maximum: 50
-      responses:
-        '200':
-          description: search results matching criteria
-          content:
-            application/json:
-              schema:
-                type: array
-                items:
-                  $ref: '#/components/schemas/InventoryItem'
-        '400':
-          description: bad input parameter
-    post:
-      tags:
-      - admins
-      summary: adds an inventory item
-      operationId: addInventory
-      description: Adds an item to the system
-      responses:
-        '201':
-          description: item created
-        '400':
-          description: 'invalid input, object invalid'
-        '409':
-          description: an existing item already exists
-      requestBody:
-        content:
-          application/json:
-            schema:
-              $ref: '#/components/schemas/InventoryItem'
-        description: Inventory item to add
-components:
-  schemas:
-    InventoryItem:
-      type: object
-      required:
-      - id
-      - name
-      - manufacturer
-      - releaseDate
-      properties:
-        id:
-          type: string
-          format: uuid
-          example: d290f1ee-6c54-4b01-90e6-d701748f0851
-        name:
-          type: string
-          example: Widget Adapter
-        releaseDate:
-          type: string
-          format: date-time
-          example: '2016-08-29T09:12:33.001Z'
-        manufacturer:
-          $ref: '#/components/schemas/Manufacturer'
-    Manufacturer:
-      required:
-      - name
-      properties:
-        name:
-          type: string
-          example: ACME Corporation
-        homePage:
-          type: string
-          format: url
-          example: 'https://www.acme-corp.com'
-        phone:
-          type: string
-          example: 408-867-5309
-      type: object
\ No newline at end of file