From 240a821769528b2c73c26bf5022aff0c3827946a Mon Sep 17 00:00:00 2001 From: Peter Taylor Date: Wed, 8 May 2024 15:47:55 +0100 Subject: [PATCH] OpenAPIDeserializer add seam for converting JsonNode to Object + use LocalDate --- .../v3/parser/util/OpenAPIDeserializer.java | 37 ++++++++----------- .../test/OpenAPIV31ParserSchemaTest.java | 23 +++++++----- 2 files changed, 28 insertions(+), 32 deletions(-) diff --git a/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/util/OpenAPIDeserializer.java b/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/util/OpenAPIDeserializer.java index bf10fcd792..167f7ccccd 100644 --- a/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/util/OpenAPIDeserializer.java +++ b/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/util/OpenAPIDeserializer.java @@ -67,7 +67,9 @@ import java.net.URISyntaxException; import java.net.URL; import java.text.ParseException; +import java.time.LocalDate; import java.time.OffsetDateTime; +import java.time.ZoneOffset; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -260,9 +262,6 @@ public class OpenAPIDeserializer { private static final String COOKIE_PARAMETER = "cookie"; private static final String PATH_PARAMETER = "path"; private static final String HEADER_PARAMETER = "header"; - private static final Pattern RFC3339_DATE_TIME_PATTERN = Pattern.compile("^(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):" + - "(\\d{2}):(\\d{2})(\\.\\d+)?((Z)|([+-]\\d{2}:\\d{2}))$"); - private static final Pattern RFC3339_DATE_PATTERN = Pattern.compile("^(\\d{4})-(\\d{2})-(\\d{2})$"); private static final String REFERENCE_SEPARATOR = "#/"; private static final int MAX_EXTENSION_ENTRIES = 20; @@ -297,7 +296,7 @@ public SwaggerParseResult deserialize(JsonNode rootNode, String path, ParseOptio public SwaggerParseResult deserialize(JsonNode rootNode, String path, ParseOptions options, boolean isOaiAuthor) { basePath = path; this.rootNode = rootNode; - rootMap = new ObjectMapper().convertValue(rootNode, Map.class); + rootMap = convertValue(rootNode, Map.class); SwaggerParseResult result = new SwaggerParseResult(); try { ParseResult rootParse = new ParseResult(); @@ -319,6 +318,13 @@ public SwaggerParseResult deserialize(JsonNode rootNode, String path, ParseOptio return result; } + protected T convertValue(JsonNode fromValue, Class toValueType) { + if(Object.class.equals(toValueType)) { + return Json.mapper().convertValue(fromValue, toValueType); + } + return new ObjectMapper().convertValue(fromValue, toValueType); + } + public OpenAPI parseRoot(JsonNode node, ParseResult result, String path) { String location = ""; OpenAPI openAPI = new OpenAPI(); @@ -517,7 +523,7 @@ private Map tryDirectExtensions(ObjectNode node) { Set keys = getKeys(node); for (String key : keys) { if (key.startsWith("x-")) { - extensions.put(key, Json.mapper().convertValue(node.get(key), Object.class)); + extensions.put(key, convertValue(node.get(key), Object.class)); } } @@ -3201,23 +3207,10 @@ private OffsetDateTime toDateTime(String dateString) { * Returns null if this string can't be parsed as Date. */ private Date toDate(String dateString) { - Matcher matcher = RFC3339_DATE_PATTERN.matcher(dateString); - Date date = null; - if (matcher.matches()) { - String year = matcher.group(1); - String month = matcher.group(2); - String day = matcher.group(3); - - try { - date = - new Calendar.Builder() - .setDate(Integer.parseInt(year), Integer.parseInt(month) - 1, - Integer.parseInt(day)) - .build() - .getTime(); - } catch (Exception ignore) { - } + try { + date = new Date(LocalDate.parse(dateString).atStartOfDay(ZoneOffset.UTC).toInstant().toEpochMilli()); + } catch (Exception ignore) { } return date; @@ -4251,7 +4244,7 @@ public Schema getJsonSchema(JsonNode jsonNode, String location, ParseResult resu for (String key : schemaKeys) { validateReservedKeywords(specKeys, key, location, result); if (!specKeys.get("SCHEMA_KEYS").contains(key) && !key.startsWith("x-")) { - extensions.put(key, Json.mapper().convertValue(node.get(key), Object.class)); + extensions.put(key, convertValue(node.get(key), Object.class)); schema.setExtensions(extensions); } } diff --git a/modules/swagger-parser-v3/src/test/java/io/swagger/v3/parser/test/OpenAPIV31ParserSchemaTest.java b/modules/swagger-parser-v3/src/test/java/io/swagger/v3/parser/test/OpenAPIV31ParserSchemaTest.java index 0768c1aaf2..38e78c64fc 100644 --- a/modules/swagger-parser-v3/src/test/java/io/swagger/v3/parser/test/OpenAPIV31ParserSchemaTest.java +++ b/modules/swagger-parser-v3/src/test/java/io/swagger/v3/parser/test/OpenAPIV31ParserSchemaTest.java @@ -1,5 +1,6 @@ package io.swagger.v3.parser.test; +import com.fasterxml.jackson.core.util.DefaultIndenter; import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; import com.fasterxml.jackson.databind.MapperFeature; import com.fasterxml.jackson.databind.ObjectMapper; @@ -25,13 +26,15 @@ import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; import static com.github.tomakehurst.wiremock.client.WireMock.get; import static com.github.tomakehurst.wiremock.client.WireMock.urlPathMatching; -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.assertTrue; public class OpenAPIV31ParserSchemaTest { protected int serverPort = getDynamicPort(); protected WireMockServer wireMockServer; + private static SwaggerParseResult readLocation(String pathname, ParseOptions p) { + return new OpenAPIV3Parser().readLocation(new File(pathname).getAbsoluteFile().toURI().toString(), null, p); + } + private static int getDynamicPort() { return new Random().ints(10000, 20000).findFirst().getAsInt(); } @@ -167,7 +170,7 @@ private void tearDownWireMockServer() { public void test$idUrlExternal() throws Exception { ParseOptions p = new ParseOptions(); p.setResolve(true); - SwaggerParseResult swaggerParseResult = new OpenAPIV3Parser().readLocation(new File("src/test/resources/3.1.0/dereference/schema/$id-uri-external/root.json").getAbsolutePath(), null, p); + SwaggerParseResult swaggerParseResult = readLocation("src/test/resources/3.1.0/dereference/schema/$id-uri-external/root.json", p); compare("$id-uri-external", swaggerParseResult); } @@ -175,7 +178,7 @@ private void tearDownWireMockServer() { public void test$idUrlEnclosing() throws Exception { ParseOptions p = new ParseOptions(); p.setResolve(true); - SwaggerParseResult swaggerParseResult = new OpenAPIV3Parser().readLocation(new File("src/test/resources/3.1.0/dereference/schema/$id-uri-enclosing/root.json").getAbsolutePath(), null, p); + SwaggerParseResult swaggerParseResult = readLocation("src/test/resources/3.1.0/dereference/schema/$id-uri-enclosing/root.json", p); compare("$id-uri-enclosing", swaggerParseResult); } @@ -183,14 +186,14 @@ private void tearDownWireMockServer() { public void test$idUrlDirect() throws Exception { ParseOptions p = new ParseOptions(); p.setResolve(true); - SwaggerParseResult swaggerParseResult = new OpenAPIV3Parser().readLocation(new File("src/test/resources/3.1.0/dereference/schema/$id-uri-direct/root.json").getAbsolutePath(), null, p); + SwaggerParseResult swaggerParseResult = readLocation("src/test/resources/3.1.0/dereference/schema/$id-uri-direct/root.json", p); compare("$id-uri-direct", swaggerParseResult); } @Test public void test$idUrlUnresolvable() throws Exception { ParseOptions p = new ParseOptions(); p.setResolve(true); - SwaggerParseResult swaggerParseResult = new OpenAPIV3Parser().readLocation(new File("src/test/resources/3.1.0/dereference/schema/$id-unresolvable/root.json").getAbsolutePath(), null, p); + SwaggerParseResult swaggerParseResult = readLocation("src/test/resources/3.1.0/dereference/schema/$id-unresolvable/root.json", p); compare("$id-unresolvable", swaggerParseResult); } @@ -198,7 +201,7 @@ private void tearDownWireMockServer() { public void testAnchorExt() throws Exception { ParseOptions p = new ParseOptions(); p.setResolve(true); - SwaggerParseResult swaggerParseResult = new OpenAPIV3Parser().readLocation(new File("src/test/resources/3.1.0/dereference/schema/$anchor-external/root.json").getAbsolutePath(), null, p); + SwaggerParseResult swaggerParseResult = readLocation("src/test/resources/3.1.0/dereference/schema/$anchor-external/root.json", p); compare("$anchor-external", swaggerParseResult); } @@ -206,7 +209,7 @@ public void testAnchorExt() throws Exception { public void testAnchorInt() throws Exception { ParseOptions p = new ParseOptions(); p.setResolve(true); - SwaggerParseResult swaggerParseResult = new OpenAPIV3Parser().readLocation(new File("src/test/resources/3.1.0/dereference/schema/$anchor-internal/root.json").getAbsolutePath(), null, p); + SwaggerParseResult swaggerParseResult = readLocation("src/test/resources/3.1.0/dereference/schema/$anchor-internal/root.json", p); compare("$anchor-internal", swaggerParseResult); } @@ -214,7 +217,7 @@ public void testAnchorInt() throws Exception { public void testAnchorUnresolve() throws Exception { ParseOptions p = new ParseOptions(); p.setResolve(true); - SwaggerParseResult swaggerParseResult = new OpenAPIV3Parser().readLocation(new File("src/test/resources/3.1.0/dereference/schema/$anchor-not-found/root.json").getAbsolutePath(), null, p); + SwaggerParseResult swaggerParseResult = readLocation("src/test/resources/3.1.0/dereference/schema/$anchor-not-found/root.json", p); compare("$anchor-not-found", swaggerParseResult); } @@ -223,7 +226,7 @@ public void compare(String dir, SwaggerParseResult result) throws Exception { ObjectMapper mapper = Json31.mapper().copy(); mapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true); mapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true); - String actual = mapper.writer(new DefaultPrettyPrinter()).writeValueAsString(result.getOpenAPI()); + String actual = mapper.writer(new DefaultPrettyPrinter().withObjectIndenter(new DefaultIndenter().withLinefeed("\n"))).writeValueAsString(result.getOpenAPI()); org.testng.Assert.assertEquals(actual, FileUtils.readFileToString(new File("src/test/resources/3.1.0/dereference/schema/" + dir + "/dereferenced.json"))); }