From 798bf6a205d1c5fe287bc0f938de32cade72a203 Mon Sep 17 00:00:00 2001 From: Ivan Ushankin Date: Tue, 22 Sep 2015 15:36:43 +0300 Subject: [PATCH] Fixed #1417: Bug in scanning The Specification Extensions --- .../java/io/swagger/util/BaseReaderUtils.java | 54 ++++++++ .../java/io/swagger/BaseReaderUtilsTest.java | 115 ++++++++++++++++++ .../main/java/io/swagger/jaxrs/Reader.java | 39 +----- .../main/java/io/swagger/servlet/Reader.java | 38 +----- 4 files changed, 177 insertions(+), 69 deletions(-) create mode 100644 modules/swagger-core/src/main/java/io/swagger/util/BaseReaderUtils.java create mode 100644 modules/swagger-core/src/test/java/io/swagger/BaseReaderUtilsTest.java diff --git a/modules/swagger-core/src/main/java/io/swagger/util/BaseReaderUtils.java b/modules/swagger-core/src/main/java/io/swagger/util/BaseReaderUtils.java new file mode 100644 index 0000000000..e76edef37b --- /dev/null +++ b/modules/swagger-core/src/main/java/io/swagger/util/BaseReaderUtils.java @@ -0,0 +1,54 @@ +package io.swagger.util; + +import io.swagger.annotations.Extension; +import io.swagger.annotations.ExtensionProperty; + +import org.apache.commons.lang3.StringUtils; + +import java.util.HashMap; +import java.util.Map; + +/** + * The BaseReaderUtils class is utility class which helps read annotations to the Swagger. + */ +public final class BaseReaderUtils { + + private BaseReaderUtils() { + + } + + /** + * Collects extensions. + * + * @param extensions is an array of extensions + * @return the map with extensions + */ + public static Map parseExtensions(Extension[] extensions) { + final Map map = new HashMap(); + for (Extension extension : extensions) { + final String name = extension.name(); + final String key = name.length() > 0 ? StringUtils.prependIfMissing(name, "x-") : name; + + for (ExtensionProperty property : extension.properties()) { + final String propertyName = property.name(); + final String propertyValue = property.value(); + if (StringUtils.isNotBlank(propertyName) && StringUtils.isNotBlank(propertyValue)) { + if (key.isEmpty()) { + map.put(StringUtils.prependIfMissing(propertyName, "x-"), propertyValue); + } else { + Object value = map.get(key); + if (value == null || !(value instanceof Map)) { + value = new HashMap(); + map.put(key, value); + } + @SuppressWarnings("unchecked") + final Map mapValue = (Map) value; + mapValue.put(propertyName, propertyValue); + } + } + } + } + + return map; + } +} diff --git a/modules/swagger-core/src/test/java/io/swagger/BaseReaderUtilsTest.java b/modules/swagger-core/src/test/java/io/swagger/BaseReaderUtilsTest.java new file mode 100644 index 0000000000..0936077a9d --- /dev/null +++ b/modules/swagger-core/src/test/java/io/swagger/BaseReaderUtilsTest.java @@ -0,0 +1,115 @@ +package io.swagger; + +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.Extension; +import io.swagger.annotations.ExtensionProperty; +import io.swagger.util.BaseReaderUtils; + +import com.google.common.collect.ImmutableMap; +import org.testng.Assert; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import java.lang.reflect.Method; +import java.util.Collections; +import java.util.Map; + +public class BaseReaderUtilsTest { + + @DataProvider + private Object[][] expectedData() { + return new Object[][]{ + {"methodOne", Collections.emptyMap()}, + {"methodTwo", Collections.emptyMap()}, + {"methodThree", ImmutableMap.of( + "x-test1", "value1", + "x-test2", "value2", + "x-test", ImmutableMap.of("test1", "value1", "test2", "value2"))}, + {"methodFour", ImmutableMap.of( + "x-test", ImmutableMap.of("test1", "value1", "test2", "value2"), + "x-test1", "value1", + "x-test2", "value2")}, + {"methodFive", ImmutableMap.of( + "x-test1", ImmutableMap.of("test1", "value1", "test2", "value2"), + "x-test2", "value2")}, + {"methodSix", ImmutableMap.of("x-test1", "value1", "x-test2", "value2")} + }; + } + + @Test(dataProvider = "expectedData") + public void extensionsTest(String methodName, Map expected) throws NoSuchMethodException { + final Method method = getClass().getDeclaredMethod(methodName); + final Extension[] extensions = method.getAnnotation(ApiOperation.class).extensions(); + final Map map = BaseReaderUtils.parseExtensions(extensions); + + Assert.assertEquals(map, expected); + } + + @ApiOperation(value = "method") + private void methodOne() { + + } + + @ApiOperation(value = "method", extensions = { + @Extension(name = "test", properties = { + @ExtensionProperty(name = "test1", value = "") + })}) + private void methodTwo() { + + } + + @ApiOperation(value = "method", extensions = { + @Extension(properties = { + @ExtensionProperty(name = "test1", value = "value1"), + @ExtensionProperty(name = "test2", value = "value2") + }), + @Extension(name = "test", properties = { + @ExtensionProperty(name = "test1", value = "value1"), + @ExtensionProperty(name = "test2", value = "value2") + })}) + private void methodThree() { + + } + + @ApiOperation(value = "method", extensions = { + @Extension(name = "test", properties = { + @ExtensionProperty(name = "test1", value = "value1"), + @ExtensionProperty(name = "test2", value = "value2") + }), + @Extension(properties = { + @ExtensionProperty(name = "test1", value = "value1"), + @ExtensionProperty(name = "test2", value = "value2") + }) + }) + private void methodFour() { + + } + + @ApiOperation(value = "method", extensions = { + @Extension(properties = { + @ExtensionProperty(name = "test1", value = "value1"), + @ExtensionProperty(name = "test2", value = "value2") + }), + @Extension(name = "test1", properties = { + @ExtensionProperty(name = "test1", value = "value1"), + @ExtensionProperty(name = "test2", value = "value2") + }) + }) + private void methodFive() { + + } + + @ApiOperation(value = "method", extensions = { + @Extension(name = "test1", properties = { + @ExtensionProperty(name = "test1", value = "value1"), + @ExtensionProperty(name = "test2", value = "value2") + }), + @Extension(properties = { + @ExtensionProperty(name = "test1", value = "value1"), + @ExtensionProperty(name = "test2", value = "value2") + }) + }) + private void methodSix() { + + } +} diff --git a/modules/swagger-jaxrs/src/main/java/io/swagger/jaxrs/Reader.java b/modules/swagger-jaxrs/src/main/java/io/swagger/jaxrs/Reader.java index 937ec0a529..8efdb822e4 100644 --- a/modules/swagger-jaxrs/src/main/java/io/swagger/jaxrs/Reader.java +++ b/modules/swagger-jaxrs/src/main/java/io/swagger/jaxrs/Reader.java @@ -59,6 +59,7 @@ import io.swagger.models.properties.MapProperty; import io.swagger.models.properties.Property; import io.swagger.models.properties.RefProperty; +import io.swagger.util.BaseReaderUtils; import io.swagger.util.ParameterProcessor; import io.swagger.util.PathUtils; import io.swagger.util.ReflectionUtils; @@ -264,7 +265,7 @@ private Swagger read(Class cls, String parentPath, String parentMethod, boole String httpMethod = extractOperationMethod(apiOperation, method, SwaggerExtensions.chain()); Operation operation = null; - if(apiOperation != null || config.isScanAllResources() || httpMethod != null || methodPath != null) { + if(apiOperation != null || config.isScanAllResources() || httpMethod != null || methodPath != null) { operation = parseMethod(cls, method, globalParameters); } if (operation == null) { @@ -332,7 +333,7 @@ private Swagger read(Class cls, String parentPath, String parentMethod, boole } if (operation != null) { - addExtensionProperties(apiOperation.extensions(), operation.getVendorExtensions()); + operation.getVendorExtensions().putAll(BaseReaderUtils.parseExtensions(apiOperation.extensions())); } } if (operation != null) { @@ -458,7 +459,7 @@ protected void readSwaggerConfig(Class cls, SwaggerDefinition config) { tagConfig.externalDocs().url())); } - addExtensionProperties(tagConfig.extensions(), tag.getVendorExtensions()); + tag.getVendorExtensions().putAll(BaseReaderUtils.parseExtensions(tagConfig.extensions())); swagger.addTag(tag); } @@ -525,37 +526,7 @@ protected void readInfoConfig(SwaggerDefinition config) { } } - addExtensionProperties(infoConfig.extensions(), info.getVendorExtensions()); - } - - private void addExtensionProperties(Extension[] extensions, Map map) { - for (Extension extension : extensions) { - String name = extension.name(); - if (name.length() > 0) { - - if (!name.startsWith("x-")) { - name = "x-" + name; - } - - if (!map.containsKey(name)) { - map.put(name, new HashMap()); - } - - map = (Map) map.get(name); - } - - for (ExtensionProperty property : extension.properties()) { - if (!property.name().isEmpty() && !property.value().isEmpty()) { - - String propertyName = property.name(); - if (name.isEmpty() && !propertyName.startsWith("x-")) { - propertyName = "x-" + propertyName; - } - - map.put(propertyName, property.value()); - } - } - } + info.getVendorExtensions().putAll(BaseReaderUtils.parseExtensions(infoConfig.extensions())); } protected Class getSubResource(Method method) { diff --git a/modules/swagger-servlet/src/main/java/io/swagger/servlet/Reader.java b/modules/swagger-servlet/src/main/java/io/swagger/servlet/Reader.java index e2bf8dbf7d..e4d4b8d3e2 100644 --- a/modules/swagger-servlet/src/main/java/io/swagger/servlet/Reader.java +++ b/modules/swagger-servlet/src/main/java/io/swagger/servlet/Reader.java @@ -1,7 +1,5 @@ package io.swagger.servlet; -import io.swagger.annotations.Extension; -import io.swagger.annotations.ExtensionProperty; import io.swagger.annotations.Info; import io.swagger.annotations.SwaggerDefinition; import io.swagger.models.Contact; @@ -16,6 +14,7 @@ import io.swagger.models.parameters.Parameter; import io.swagger.servlet.extensions.ReaderExtension; import io.swagger.servlet.extensions.ReaderExtensions; +import io.swagger.util.BaseReaderUtils; import io.swagger.util.PathUtils; import io.swagger.util.ReflectionUtils; @@ -166,7 +165,7 @@ private void readSwaggerConfig(SwaggerDefinition config) { tagConfig.externalDocs().url())); } - addExtensionProperties(tagConfig.extensions(), tag.getVendorExtensions()); + tag.getVendorExtensions().putAll(BaseReaderUtils.parseExtensions(tagConfig.extensions())); swagger.addTag(tag); } @@ -233,37 +232,6 @@ private void readInfoConfig(SwaggerDefinition config) { } } - addExtensionProperties(infoConfig.extensions(), info.getVendorExtensions()); - } - - @SuppressWarnings("unchecked") - private void addExtensionProperties(Extension[] extensions, Map map) { - for (Extension extension : extensions) { - String name = extension.name(); - if (name.length() > 0) { - - if (!name.startsWith("x-")) { - name = "x-" + name; - } - - if (!map.containsKey(name)) { - map.put(name, new HashMap()); - } - - map = (Map) map.get(name); - } - - for (ExtensionProperty property : extension.properties()) { - if (!property.name().isEmpty() && !property.value().isEmpty()) { - - String propertyName = property.name(); - if (name.isEmpty() && !propertyName.startsWith("x-")) { - propertyName = "x-" + propertyName; - } - - map.put(propertyName, property.value()); - } - } - } + info.getVendorExtensions().putAll(BaseReaderUtils.parseExtensions(infoConfig.extensions())); } }