Repository: swagger-api/swagger-parser
Pull request #1271 (2019-12-09 22:04:23)

enable STRICT_DUPLICATE_DETECTION in Jackson parser


Patch:
diff --git a/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/ObjectMapperFactory.java b/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/ObjectMapperFactory.java
index 371df3b8..b6e4282d 100644
--- a/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/ObjectMapperFactory.java
+++ b/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/ObjectMapperFactory.java
@@ -2,6 +2,8 @@ package io.swagger.v3.parser;
 
 import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonFactoryBuilder;
+import com.fasterxml.jackson.core.StreamReadFeature;
 import com.fasterxml.jackson.databind.DeserializationFeature;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.SerializationFeature;
@@ -25,7 +27,7 @@ public class ObjectMapperFactory {
     }
 
     private static ObjectMapper create(JsonFactory jsonFactory, boolean includePathDeserializer, boolean includeResponseDeserializer) {
-        ObjectMapper mapper = jsonFactory == null ? new ObjectMapper() : new ObjectMapper(jsonFactory);
+        ObjectMapper mapper = jsonFactory == null ? new ObjectMapper(createJsonFactory()) : new ObjectMapper(jsonFactory);
 
         mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
         mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
@@ -34,4 +36,10 @@ public class ObjectMapperFactory {
 
         return mapper;
     }
+
+    private static JsonFactory createJsonFactory() {
+        return new JsonFactoryBuilder()
+          .enable(StreamReadFeature.STRICT_DUPLICATE_DETECTION)
+          .build();
+    }
 }
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 2bc681f4..86e93afa 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
@@ -1,5 +1,6 @@
 package io.swagger.v3.parser;
 
+import com.fasterxml.jackson.core.JsonParseException;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import io.swagger.v3.oas.models.OpenAPI;
@@ -162,6 +163,17 @@ public class OpenAPIV3Parser implements SwaggerParserExtension {
                     "Certificate Authority."));
             return output;
         }
+        catch (JsonParseException e) {
+            LOGGER.warn("Exception while parsing:", e);
+            SwaggerParseResult output = new SwaggerParseResult();
+            String message = e.getOriginalMessage();
+            if ((message != null) && (message.startsWith("Duplicate field"))) {
+                output.setMessages(Arrays.asList(message + " in `" + location + "`"));
+            } else {
+                output.setMessages(Arrays.asList("unable to parse `" + location + "`"));
+            }
+            return output;
+        }
         catch (Exception e) {
             LOGGER.warn("Exception while reading:", e);
             SwaggerParseResult output = new SwaggerParseResult();


Test patch:
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 cd32c5e7..d19c9deb 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
@@ -2246,4 +2246,19 @@ public class OpenAPIV3ParserTest {
         assertEquals(result.getMessages().get(0).contains("attribute components.schemas.Pet. writeOnly and readOnly are both present"), true);
 
     }
+
+    @Test
+    public void testDuplicateHttpStatusCodes() {
+        final String location = "src/test/resources/duplicateHttpStatusCodes.json";
+
+        final ParseOptions options = new ParseOptions();
+        options.setResolve(true);
+
+        final OpenAPIV3Parser parser = new OpenAPIV3Parser();
+        final SwaggerParseResult result = parser.readLocation(location, null, options);
+        assertNull(result.getOpenAPI());
+        List<String> messages = result.getMessages();
+        assertEquals(1, messages.size());
+        assertEquals(messages.get(0), "Duplicate field '200' in `src/test/resources/duplicateHttpStatusCodes.json`");
+    }
 }
diff --git a/modules/swagger-parser-v3/src/test/resources/duplicateHttpStatusCodes.json b/modules/swagger-parser-v3/src/test/resources/duplicateHttpStatusCodes.json
new file mode 100644
index 00000000..9da5d4b0
--- /dev/null
+++ b/modules/swagger-parser-v3/src/test/resources/duplicateHttpStatusCodes.json
@@ -0,0 +1,35 @@
+{
+  "openapi": "3.0.1",
+  "servers": [
+    {
+      "description": "An absolute path",
+      "url": "https://api.absolute.org/v2"
+    }
+  ],
+  "info": {
+    "description": "This is a sample server",
+    "version": "1.0.0",
+    "title": "title",
+    "license": {
+      "name": "Apache-2.0",
+      "url": "http://www.apache.org/licenses/LICENSE-2.0.html"
+    }
+  },
+  "paths": {
+    "/whatever": {
+      "get": {
+        "summary": "Some operation",
+        "description": "Some operation",
+        "operationId": "doWhatever",
+        "responses": {
+          "200": {
+            "description": "OK"
+          },
+          "200": {
+            "description": "duplicate HTTP status code"
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file