Reputation: 513
I need to return to client list of few results and total count of results. I have to do it on several places with different entities so I would like to have a generic class with these two attributes:
@XmlRootElement
public class QueryResult<T> implements Serializable {
private int count;
private List<T> result;
public QueryResult() {
}
public void setCount(int count) {
this.count = count;
}
public void setResult(List<T> result) {
this.result = result;
}
public int getCount() {
return count;
}
public List<T> getResult() {
return result;
}
}
And the service:
@GET
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public QueryResult<TestEntity> findAll(
QueryResult<TestEntity> findAll = facade.findAllWithCount();
return findAll;
}
Entity is not important:
@XmlRootElement
public class TestEntity implements Serializable {
...
}
But this causes: javax.xml.bind.JAXBException: class test.TestEntity nor any of its super class is known to this context.
Returning of just collection is easy but I don't know how to return my own generic type. I tried to use GenericType
but without success - I think it's ment for collections.
Upvotes: 5
Views: 6636
Reputation: 6153
I had exactly the same issue. The problem occurs because of Java's type erasure.
My first approach was to generate a result class for each entity type:
public class Entity1Result extends QueryResult<Entity1> { ... }
public class Entity2Result extends QueryResult<Entity2> { ... }
I returned the generic QueryResult<>
in my serivces only for built-in types like QueryResult<String>
, or QueryResult<Integer>
But this was cumbersome, because I had a lot of entities. So my other approach was to use only JSON and I changed my result class to be non-generic and use an Object
result field:
public class QueryResult {
private Object result;
}
It works fine, Jersey is able to serialize everything I give it into JSON (Note: I don't know if it is important, but the QueryResult
and all my entities still have @Xml...
annotations. This works also for lists with own entity types.
If you have problems with collections, you can also see this question
Upvotes: 1
Reputation: 3624
After battling with this myself I discovered the answer is fairly simple. In your service, return a built response of a GenericEntity (http://docs.oracle.com/javaee/6/api/javax/ws/rs/core/GenericEntity.html) typed accordingly. For example:
@GET
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public Response findAll(){
return Response.ok(new GenericEntity<TestEntity>(facade.findAllWithCount()){}).build();
}
See this post as to why you cannot simply return GenericEntity: Jersey GenericEntity Not Working
A more complex solution could be to return the GenericEntity directly and create your own XmlAdapter (http://jaxb.java.net/nonav/2.2.4/docs/api/javax/xml/bind/annotation/adapters/XmlAdapter.html) to handle marshalling/unmarshalling. I've not tried this, though, so it's just a theory.
Upvotes: 6
Reputation: 513
I solved it using @XmlSeeAlso
annotation:
@XmlSeeAlso(TestEntity.class)
@XmlRootElement
public class QueryResult<T> implements Serializable {
...
}
Another possibility is to use @XmlElementRefs
.
Upvotes: 1