diff --git a/modules/swagger-jaxrs/src/main/java/io/swagger/jaxrs/ParameterProcessor.java b/modules/swagger-jaxrs/src/main/java/io/swagger/jaxrs/ParameterProcessor.java index 331c83e38c..26f82f599d 100644 --- a/modules/swagger-jaxrs/src/main/java/io/swagger/jaxrs/ParameterProcessor.java +++ b/modules/swagger-jaxrs/src/main/java/io/swagger/jaxrs/ParameterProcessor.java @@ -1,7 +1,5 @@ package io.swagger.jaxrs; -import com.fasterxml.jackson.databind.JavaType; -import com.fasterxml.jackson.databind.type.TypeFactory; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiParam; import io.swagger.converter.ModelConverters; @@ -41,7 +39,6 @@ public static Parameter applyAnnotations(Swagger swagger, Parameter parameter, T return null; } final String defaultValue = helper.getDefaultValue(); - final JavaType javaType = TypeFactory.defaultInstance().constructType(type); if (parameter instanceof AbstractSerializableParameter) { final AbstractSerializableParameter p = (AbstractSerializableParameter) parameter; @@ -112,14 +109,14 @@ public static Parameter applyAnnotations(Swagger swagger, Parameter parameter, T bp.setAccess(param.getAccess()); } - final Property property = ModelConverters.getInstance().readAsProperty(javaType); + final Property property = ModelConverters.getInstance().readAsProperty(type); if (property != null) { final Map args = new EnumMap(PropertyBuilder.PropertyId.class); if (StringUtils.isNotEmpty(defaultValue)) { args.put(PropertyBuilder.PropertyId.DEFAULT, defaultValue); } bp.setSchema(PropertyBuilder.toModel(PropertyBuilder.merge(property, args))); - for (Map.Entry entry : ModelConverters.getInstance().readAll(javaType).entrySet()) { + for (Map.Entry entry : ModelConverters.getInstance().readAll(type).entrySet()) { swagger.addDefinition(entry.getKey(), entry.getValue()); } } 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 94bf08982d..88ad11d40c 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 @@ -260,7 +260,7 @@ protected Swagger read(Class cls, String parentPath, String parentMethod, boo Operation operation = null; if(apiOperation != null || config.isScanAllResources() || httpMethod != null || methodPath != null) { - operation = parseMethod(method, globalParameters); + operation = parseMethod(cls, method, globalParameters); } if (operation == null) { continue; @@ -688,10 +688,10 @@ private Map parseResponseHeaders(ResponseHeader[] headers) { } public Operation parseMethod(Method method) { - return parseMethod(method, Collections.emptyList()); + return parseMethod(method.getDeclaringClass(), method, Collections.emptyList()); } - private Operation parseMethod(Method method, List globalParameters) { + private Operation parseMethod(Class cls, Method method, List globalParameters) { Operation operation = new Operation(); ApiOperation apiOperation = getAnnotation(method, ApiOperation.class); @@ -834,7 +834,7 @@ private Operation parseMethod(Method method, List globalParameters) { Type[] genericParameterTypes = method.getGenericParameterTypes(); Annotation[][] paramAnnotations = method.getParameterAnnotations(); for (int i = 0; i < genericParameterTypes.length; i++) { - Type type = genericParameterTypes[i]; + final Type type = TypeFactory.defaultInstance().constructType(genericParameterTypes[i], cls); List parameters = getParameters(type, Arrays.asList(paramAnnotations[i])); for (Parameter parameter : parameters) { @@ -871,7 +871,6 @@ private List getParameters(Type type, List annotations) { LOGGER.debug("trying extension " + extension); final List parameters = extension.extractParameters(annotations, type, typesToSkip, chain); - if (parameters.size() > 0) { final List processed = new ArrayList(parameters.size()); for (Parameter parameter : parameters) { diff --git a/modules/swagger-jaxrs/src/test/java/io/swagger/GenericsTest.java b/modules/swagger-jaxrs/src/test/java/io/swagger/GenericsTest.java index 3ee240a9d9..4f983db87e 100644 --- a/modules/swagger-jaxrs/src/test/java/io/swagger/GenericsTest.java +++ b/modules/swagger-jaxrs/src/test/java/io/swagger/GenericsTest.java @@ -5,6 +5,7 @@ import com.google.common.collect.Sets; import io.swagger.jaxrs.Reader; import io.swagger.models.ArrayModel; +import io.swagger.models.Model; import io.swagger.models.Operation; import io.swagger.models.RefModel; import io.swagger.models.Swagger; @@ -17,14 +18,18 @@ import io.swagger.models.properties.StringProperty; import io.swagger.models.properties.UUIDProperty; import io.swagger.resources.ResourceWithGenerics; +import io.swagger.resources.generics.UserApiRoute; + import org.testng.annotations.Test; import java.util.Arrays; import java.util.HashSet; +import java.util.Map; import java.util.Set; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotEquals; +import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; public class GenericsTest { @@ -211,4 +216,16 @@ public void checkGenericResult() { assertEquals(items.getClass().getName(), RefProperty.class.getName()); assertEquals(((RefProperty) items).getSimpleRef(), "Tag"); } + + @Test(description = "scan model with Generic Type") + public void scanModelWithGenericType() { + final Swagger swagger = new Reader(new Swagger()).read(UserApiRoute.class); + assertNotNull(swagger); + final Model userEntity = swagger.getDefinitions().get("UserEntity"); + assertNotNull(userEntity); + final Map properties = userEntity.getProperties(); + assertEquals(properties.size(), 2); + assertNotNull(properties.get("id")); + assertNotNull(properties.get("name")); + } } diff --git a/modules/swagger-jaxrs/src/test/java/io/swagger/resources/generics/AbstractEntity.java b/modules/swagger-jaxrs/src/test/java/io/swagger/resources/generics/AbstractEntity.java new file mode 100644 index 0000000000..6a7101cf00 --- /dev/null +++ b/modules/swagger-jaxrs/src/test/java/io/swagger/resources/generics/AbstractEntity.java @@ -0,0 +1,7 @@ +package io.swagger.resources.generics; + +import java.io.Serializable; + +public abstract class AbstractEntity implements Serializable { + public String id; +} diff --git a/modules/swagger-jaxrs/src/test/java/io/swagger/resources/generics/ApiCrudRoute.java b/modules/swagger-jaxrs/src/test/java/io/swagger/resources/generics/ApiCrudRoute.java new file mode 100644 index 0000000000..b856ccd426 --- /dev/null +++ b/modules/swagger-jaxrs/src/test/java/io/swagger/resources/generics/ApiCrudRoute.java @@ -0,0 +1,21 @@ +package io.swagger.resources.generics; + +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import io.swagger.models.Response; + +import java.util.List; + +import javax.ws.rs.POST; + +public abstract class ApiCrudRoute { + protected List service; + + @POST + @ApiOperation(value = "Create") + public Response doCreate( + @ApiParam(value = "Create object", required = true) T entity) throws Exception { + service.add(entity); + return new Response(); + } +} diff --git a/modules/swagger-jaxrs/src/test/java/io/swagger/resources/generics/UserApiRoute.java b/modules/swagger-jaxrs/src/test/java/io/swagger/resources/generics/UserApiRoute.java new file mode 100644 index 0000000000..81e58cefa1 --- /dev/null +++ b/modules/swagger-jaxrs/src/test/java/io/swagger/resources/generics/UserApiRoute.java @@ -0,0 +1,14 @@ +package io.swagger.resources.generics; + +import io.swagger.annotations.Api; + +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +@Path("/api/users") +@Api(value = "/users") +@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) +public class UserApiRoute extends ApiCrudRoute { + +} diff --git a/modules/swagger-jaxrs/src/test/java/io/swagger/resources/generics/UserEntity.java b/modules/swagger-jaxrs/src/test/java/io/swagger/resources/generics/UserEntity.java new file mode 100644 index 0000000000..bf905bba52 --- /dev/null +++ b/modules/swagger-jaxrs/src/test/java/io/swagger/resources/generics/UserEntity.java @@ -0,0 +1,14 @@ +package io.swagger.resources.generics; + +import io.swagger.annotations.ApiModel; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement +@ApiModel(value = "UserEntity") +@XmlAccessorType(XmlAccessType.FIELD) +public class UserEntity extends AbstractEntity { + public String name; +}