diff --git a/modules/swagger-core/src/main/java/io/swagger/util/ReflectionUtils.java b/modules/swagger-core/src/main/java/io/swagger/util/ReflectionUtils.java index 08c19acf0a..5c8d0c1b77 100644 --- a/modules/swagger-core/src/main/java/io/swagger/util/ReflectionUtils.java +++ b/modules/swagger-core/src/main/java/io/swagger/util/ReflectionUtils.java @@ -64,20 +64,19 @@ public static boolean isOverriddenMethod(Method methodToFind, Class cls) { public static Method getOverriddenMethod(Method method) { Class declaringClass = method.getDeclaringClass(); Class superClass = declaringClass.getSuperclass(); + Method result = null; if (superClass != null && !(superClass.equals(Object.class))) { - Method result = findMethod(method, superClass); - if (result == null) { - for (Class anInterface : declaringClass.getInterfaces()) { - result = findMethod(method, anInterface); - if (result != null) { - return result; - } + result = findMethod(method, superClass); + } + if (result == null) { + for (Class anInterface : declaringClass.getInterfaces()) { + result = findMethod(method, anInterface); + if (result != null) { + return result; } - } else { - return result; } } - return null; + return result; } /** @@ -182,6 +181,25 @@ public static A getAnnotation(Method method, Class ann return annotation; } + public static A getAnnotation(Class cls, Class annotationClass) { + A annotation = cls.getAnnotation(annotationClass); + if (annotation == null) { + Class superClass = cls.getSuperclass(); + if (superClass != null && !(superClass.equals(Object.class))) { + annotation = getAnnotation(superClass, annotationClass); + } + } + if (annotation == null) { + for (Class anInterface : cls.getInterfaces()) { + annotation = getAnnotation(anInterface, annotationClass); + if (annotation != null) { + return annotation; + } + } + } + return annotation; + } + /** * Checks if the type is void. * diff --git a/modules/swagger-core/src/test/java/io/swagger/ReflectionUtilsTest.java b/modules/swagger-core/src/test/java/io/swagger/ReflectionUtilsTest.java index 1fe0bcb5ea..5ac1d7b5da 100644 --- a/modules/swagger-core/src/test/java/io/swagger/ReflectionUtilsTest.java +++ b/modules/swagger-core/src/test/java/io/swagger/ReflectionUtilsTest.java @@ -13,6 +13,8 @@ import java.lang.reflect.Type; import java.util.Arrays; +import javax.ws.rs.Path; + public class ReflectionUtilsTest { @Test @@ -105,4 +107,11 @@ public void isVoidTest() { Assert.assertTrue(ReflectionUtils.isVoid(Void.TYPE)); Assert.assertFalse(ReflectionUtils.isVoid(String.class)); } + + @Test + public void testDerivedAnnotation() { + final Path annotation = ReflectionUtils.getAnnotation(Child.class, javax.ws.rs.Path.class); + Assert.assertNotNull(annotation); + Assert.assertEquals(annotation.value(), "parentInterfacePath"); + } } diff --git a/modules/swagger-core/src/test/java/io/swagger/reflection/IParent.java b/modules/swagger-core/src/test/java/io/swagger/reflection/IParent.java index e818a970c6..e438528afd 100644 --- a/modules/swagger-core/src/test/java/io/swagger/reflection/IParent.java +++ b/modules/swagger-core/src/test/java/io/swagger/reflection/IParent.java @@ -1,5 +1,8 @@ package io.swagger.reflection; +import javax.ws.rs.Path; + +@Path("parentInterfacePath") public interface IParent { public String parametrizedMethod2(T arg); 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..1c622d7b57 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 @@ -244,7 +244,7 @@ private Swagger read(Class cls, String parentPath, String parentMethod, boole globalParameters.addAll(ReaderUtils.collectFieldParameters(cls, swagger)); // parse the method - final javax.ws.rs.Path apiPath = cls.getAnnotation(javax.ws.rs.Path.class); + final javax.ws.rs.Path apiPath = ReflectionUtils.getAnnotation(cls, javax.ws.rs.Path.class); Method methods[] = cls.getMethods(); for (Method method : methods) { if (ReflectionUtils.isOverriddenMethod(method, cls)) { diff --git a/modules/swagger-jaxrs/src/test/java/io/swagger/ReaderTest.java b/modules/swagger-jaxrs/src/test/java/io/swagger/ReaderTest.java index 04685cf8e6..8d935f5d5b 100644 --- a/modules/swagger-jaxrs/src/test/java/io/swagger/ReaderTest.java +++ b/modules/swagger-jaxrs/src/test/java/io/swagger/ReaderTest.java @@ -9,6 +9,7 @@ import io.swagger.models.parameters.Parameter; import io.swagger.models.parameters.PathParameter; import io.swagger.models.parameters.QueryParameter; +import io.swagger.resources.AnnotatedInterfaceImpl; import io.swagger.resources.ApiConsumesProducesResource; import io.swagger.resources.BookResource; import io.swagger.resources.BothConsumesProducesResource; @@ -20,6 +21,7 @@ import io.swagger.resources.ResourceWithKnownInjections; import io.swagger.resources.RsConsumesProducesResource; import io.swagger.resources.SimpleMethods; + import org.testng.annotations.Test; import javax.ws.rs.DELETE; @@ -161,6 +163,13 @@ public void scanOverriddenMethod() { assertNotNull(methodFromInterface); } + @Test(description = "scan annotation from interface, issue#1427") + public void scanInterfaceTest() { + final Swagger swagger = new Reader(new Swagger()).read(AnnotatedInterfaceImpl.class); + assertNotNull(swagger); + assertNotNull(swagger.getPath("/v1/users/{id}").getGet()); + } + @Test(description = "scan implicit params") public void scanImplicitParam() { Swagger swagger = getSwagger(ResourceWithImplicitParams.class); diff --git a/modules/swagger-jaxrs/src/test/java/io/swagger/resources/AnnotatedInterface.java b/modules/swagger-jaxrs/src/test/java/io/swagger/resources/AnnotatedInterface.java new file mode 100644 index 0000000000..fd6372a807 --- /dev/null +++ b/modules/swagger-jaxrs/src/test/java/io/swagger/resources/AnnotatedInterface.java @@ -0,0 +1,18 @@ +package io.swagger.resources; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +@Path("/v1/users") +public interface AnnotatedInterface { + + @GET + @Path("/{id}") + String findById(@PathParam("id") String id); +} diff --git a/modules/swagger-jaxrs/src/test/java/io/swagger/resources/AnnotatedInterfaceImpl.java b/modules/swagger-jaxrs/src/test/java/io/swagger/resources/AnnotatedInterfaceImpl.java new file mode 100644 index 0000000000..766199213b --- /dev/null +++ b/modules/swagger-jaxrs/src/test/java/io/swagger/resources/AnnotatedInterfaceImpl.java @@ -0,0 +1,14 @@ +package io.swagger.resources; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; + +@Api(value = "/v1/users", tags = "annotatedInterface") +public class AnnotatedInterfaceImpl implements AnnotatedInterface { + + @Override + @ApiOperation(value = "Load by userId") + public String findById(String id) { + return ""; + } +}