Closed jfhall closed 11 years ago
This should be fixed in 1.2.2-SNAPSHOT, can you try again?
please re-open if 1.2.2-SNAPSHOT doesn't resolve this for you.
Looks like it's still an issue. Per here:
https://groups.google.com/forum/#!topic/swagger-swaggersocket/eO2d6qD9K9g
This model:
public class DateTimeParam extends AbstractParam<DateTime> {
public DateTimeParam(String param) {
super(param);
}
protected DateTime parse(String param) {
return DateConverter.convertToDateTime(param);
}
public Date getValueAsDate() {
return getValue() == null ? null : getValue().toDate();
}
public static Date getValueAsDate(DateTimeParam dateTimeParam) {
return dateTimeParam == null ? null : dateTimeParam.getValueAsDate();
}
}
Used like this:
public List<ResultFeedback> historical(@QueryParam("ownerId") Long ownerId,
@ApiParam(value = "YYYY-MM-DD") @QueryParam("fromDate") DateTimeParam fromDate) {
public Response findEvents(
@PathParam("ownerId") Long ownerId,
@PathParam("registrationType") RegistrationTypeParam registrationType,
@ApiParam(required = false) @QueryParam("status") AnimalExt.EnrollmentStatusCombination esc,
@ApiParam(required = false) @QueryParam("unenrollmentDate") DateTimeParam unenrollmentDate,
@ApiParam(required = false) @QueryParam("fromDate") DateTimeParam fromDate,
@HeaderParam("If-Modified-Since") String modified) {
Is giving this stack trace:
1)
2013-03-18 13:55:41,489 ERROR com.wordnik.swagger.jaxrs.HelpApi : Unable to load model documentation for no.tine.api.jersey.DateTimeParam
java.lang.ClassCastException: sun.reflect.generics.reflectiveObjects.TypeVariableImpl cannot be cast to java.lang.Class
at com.wordnik.swagger.core.ApiPropertiesReader$.getDataType(SpecReader.scala:91)
at com.wordnik.swagger.jsonschema.ApiModelParser.parsePropertyAnnotations(SwaggerJsonSchemaProvider.scala:154)
at com.wordnik.swagger.jsonschema.ApiModelParser.com$wordnik$swagger$jsonschema$ApiModelParser$$parseMethod(SwaggerJsonSchemaProvider.scala:98)
at com.wordnik.swagger.jsonschema.ApiModelParser$$anonfun$parseRecursive$1.apply(SwaggerJsonSchemaProvider.scala:81)
at com.wordnik.swagger.jsonschema.ApiModelParser$$anonfun$parseRecursive$1.apply(SwaggerJsonSchemaProvider.scala:79)
class def
public class DateTimeParam extends AbstractParam<DateTime> {
And
2)
2013-03-18 13:55:41,500 ERROR com.wordnik.swagger.jaxrs.HelpApi : Unable to load model documentation for no.tine.api.jersey.RegistrationParam
java.lang.ClassCastException: sun.reflect.generics.reflectiveObjects.TypeVariableImpl cannot be cast to java.lang.Class
at com.wordnik.swagger.core.ApiPropertiesReader$.getDataType(SpecReader.scala:84)
at com.wordnik.swagger.core.ApiPropertiesReader$.getDataType(SpecReader.scala:70)
at com.wordnik.swagger.jsonschema.ApiModelParser.parsePropertyAnnotations(SwaggerJsonSchemaProvider.scala:154)
at com.wordnik.swagger.jsonschema.ApiModelParser.com$wordnik$swagger$jsonschema$ApiModelParser$$parseMethod(SwaggerJsonSchemaProvider.scala:98)
at com.wordnik.swagger.jsonschema.ApiModelParser$$anonfun$parseRecursive$1.apply(SwaggerJsonSchemaProvider.scala:81)
at com.wordnik.swagger.jsonschema.ApiModelParser$$anonfun$parseRecursive$1.apply(SwaggerJsonSchemaProvider.scala:79)
Any news on this issue?
I'm unable to reproduce this with 1.2.2-SNAPSHOT, if someone can help with a test case we can figure it out.
Ok, I have tried to reproduce and create a testcase be removing everything in my app except for the related classes. However, when doing this, I am no longer able to reproduce the error. So something else in my app must be influencing this. I'm suspecting frameworks that modify or somehow change the behaviour of my code - Spring aop proxies, spring security, ehcache proxies, jpa/cglib. For now I'm suppressing the errors in my log, as the doc/listing seems to work ok
I am having the same class cast exception issue but in a different class.
15:27:32.212 [http-bio-8080-exec-3] DEBUG o.s.web.servlet.DispatcherServlet - Could not complete request
java.lang.ClassCastException: sun.reflect.generics.reflectiveObjects.TypeVariableImpl cannot be cast to java.lang.Class
at com.wordnik.swagger.core.ApiPropertiesReader$.getDataType(ApiPropertiesReader.scala:97) ~[swagger-core_2.9.1-1.2.2.jar:1.2.2]
at com.wordnik.swagger.core.ApiPropertiesReader$.getDataType(ApiPropertiesReader.scala:83) ~[swagger-core_2.9.1-1.2.2.jar:1.2.2]
This is specifically referencing the line below in the ApiPropertiesReader class.
} else if (!returnType.getClass.isAssignableFrom(classOf[ParameterizedTypeImpl]) && returnType.asInstanceOf[Class[_]].isArray) {
This is an issue because generics are necessary for us, it would be great if this could be resolved quickly or if you could possibly offer some workaround as we are big fans of Swagger and would love to use it.
If you can move to 1.2.3-SNAPSHOT the issues should be resolved. Can you please try?
I still received the same exception
16:56:37.600 [http-bio-8080-exec-3] DEBUG o.s.web.servlet.DispatcherServlet - Could not complete request
java.lang.ClassCastException: sun.reflect.generics.reflectiveObjects.TypeVariableImpl cannot be cast to java.lang.Class
at com.wordnik.swagger.core.ApiPropertiesReader$.getDataType(ApiPropertiesReader.scala:97) ~[swagger-core_2.9.1-1.2.3-SNAPSHOT.jar:1.2.3-SNAPSHOT]
at com.wordnik.swagger.core.ApiPropertiesReader$.getDataType(ApiPropertiesReader.scala:83) ~[swagger-core_2.9.1-1.2.3-SNAPSHOT.jar:1.2.3-SNAPSHOT]
OK rats. Can you share what your model looks like?
It's pretty basic but here's what it looks like
@JsonSerialize @JsonInclude(Include.NON_EMPTY) public class PageDTO< T > implements Serializable { private static final long serialVersionUID = 1L;
private List< T > content; private Long total;
public PageDTO() { content = new ArrayList< T >(); }
public PageDTO(T element) { content = new ArrayList< T >(); total = Long.valueOf(0); if(element != null) { content.add(element); total = Long.valueOf(1); } }
public PageDTO(List< T > content, Long total) { this.content = content; this.total = total; }
public List< T > getContent() { return content; }
public Long getTotal() { return total; }
public void setTotal(Long total) { this.total = total; }
public void setContent(List< T > content) { this.content = content; }
}
Sorry for the lack of code tags, I'm still new to the site and I couldn't get the < T > to display when I was using them.
Thanks. Are you using Play or JAX-RS? And is this model a parameter in a POST method? Or the return value of a GET?
We're actually using Spring MVC and this is part of a return value of a GET.
+1
I didn't write the Spring MVC integration but happy to help with it. If you can boil this down into a small sample project, I'll help sort it out.
Hey there, here is a WAR of a small sample project recreating the issue being seen with the DTO object above.
http://xosis.net/swagger/swagger4springweb-example-1.0.0-BUILD-SNAPSHOT.war
Here is the source code for the sample project:
http://xosis.net/swagger/swagger4spring-web-example.zip
Here is the source to the Spring MVC integration being referred to:
https://github.com/wkennedy/swagger4spring-web
I noticed this error happening when parsing the return type, but that seemed to be resolved in version 1.2.2. However, this issue appears to happen when I try parsing the model above using ApiModelParser. I updated to 1.2.3-SNAPSHOT and still noticed this issue happening. Here is the code from swagger4spring-web where the error occurs (ApiParserImpl.java line 162)
private void createDocumentationSchemas(Documentation documentation) {
Reflections reflections = new Reflections(new ConfigurationBuilder()
.filterInputsBy(new FilterBuilder().include(FilterBuilder.prefix(baseModelPackage)))
.setUrls(ClasspathHelper.forPackage(baseModelPackage))
.setScanners(new SubTypesScanner(false), new ResourcesScanner()));
Set<Class<? extends Object>> allModelClasses = reflections.getSubTypesOf(Object.class);
for (Class<? extends Object> clazz : allModelClasses) {
ApiModelParser parser;
String schemaName;
if (clazz.isArray()) {
parser = new ApiModelParser(clazz.getComponentType());
schemaName = clazz.getComponentType().getSimpleName();
} else {
parser = new ApiModelParser(clazz);
schemaName = clazz.getSimpleName();
}
documentation.addModel(schemaName, parser.parse().toDocumentationSchema());
}
}
Let me know if I can help, thanks!
got it! Thanks for the sample. I've updated your pom to force swagger-core_2.9.1-1.2.3-SNAPSHOT.jar, added tomcat6 plugin (remove as you see fit) and access sonatype snapshots. I DID find an issue in ApiPropertiesReader as you mentioned, and added a simple fix. It's uploading to sonatype right now.
The pom is below, but there is one other issue you're going to hit. As is, the model schema for /api/v1/persons/ looks like this:
{
"total": "long",
"content": [
"T"
]
}
Which I'm certain you don't really want content
to be type T
. This current has to be done by manually mapping the class to a concrete representation in your application bootstrap, if you want to have a proper concrete class. To do this, please take a look at this test class:
I'd update your sample but I'm out of time right now. Give it a whirl and post back. You're almost there!
Tony
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.knappsack</groupId>
<artifactId>swagger4springweb-example</artifactId>
<name>swagger4spring-web-example</name>
<packaging>war</packaging>
<version>1.0.0-BUILD-SNAPSHOT</version>
<properties>
<java-version>1.6</java-version>
<org.springframework-version>3.1.4.RELEASE</org.springframework-version>
<org.aspectj-version>1.6.10</org.aspectj-version>
<org.slf4j-version>1.6.6</org.slf4j-version>
<swagger-version>1.2.3-SNAPSHOT</swagger-version>
</properties>
<repositories>
<repository>
<id>sonatype snapshots</id>
<name>sonatype snapshots</name>
<layout>default</layout>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.knappsack</groupId>
<artifactId>swagger4spring-web</artifactId>
<version>0.1.6</version>
<exclusions>
<exclusion>
<artifactId>slf4j-log4j12</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
<exclusion>
<artifactId>junit</artifactId>
<groupId>junit</groupId>
</exclusion>
<exclusion>
<artifactId>slf4j-api</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<!-- swagger -->
<dependency>
<groupId>com.wordnik</groupId>
<artifactId>swagger-core_2.9.1</artifactId>
<version>${swagger-version}</version>
<scope>compile</scope>
</dependency>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${org.springframework-version}</version>
<exclusions>
<!-- Exclude Commons Logging in favor of SLF4j -->
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<!-- AspectJ -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${org.aspectj-version}</version>
</dependency>
<!-- Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${org.slf4j-version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${org.slf4j-version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${org.slf4j-version}</version>
<scope>runtime</scope>
<exclusions>
<exclusion>
<artifactId>log4j</artifactId>
<groupId>log4j</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.15</version>
<exclusions>
<exclusion>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
</exclusion>
<exclusion>
<groupId>javax.jms</groupId>
<artifactId>jms</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jdmk</groupId>
<artifactId>jmxtools</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jmx</groupId>
<artifactId>jmxri</artifactId>
</exclusion>
</exclusions>
<scope>runtime</scope>
</dependency>
<!-- @Inject -->
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
<!-- Servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- Test -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.5.1</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
<compilerArgument>-Xlint:all</compilerArgument>
<showWarnings>true</showWarnings>
<showDeprecation>true</showDeprecation>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat6-maven-plugin</artifactId>
<version>2.1</version>
<configuration>
<port>8002</port>
<path>/</path>
</configuration>
<executions>
<execution>
<id>run-tomcat</id>
<phase>pre-integration-test</phase>
<configuration>
<fork>true</fork>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Awesome, Tony! I've confirmed your fix does work. I'll update swagger4spring-web with version 1.2.3 as soon as it is released.
Thank you so much!!
released 1.2.3
Lines 90-99 of SpecReader.scala don't handle TypeVariableImpl appropriately, and the method attempts to cast a TypeVariableImpl to a class on line 91 causing a ClassCastException.
Using swagger4spring produces the following stack trace