通过GenericEntity <List >在RESTful Response对象中使用Java-generics模板类型

我有一个通用的JAX-RS资源类,我已经定义了一个通用的findAll方法

 public abstract class GenericDataResource { @GET @Produces(MediaType.APPLICATION_JSON) public Response findAll() { Query query = em.createNamedQuery(modelClass.getSimpleName()+".findAll"); List list = query.getResultList(); return Response.ok(new GenericEntity<List>(list) {}).build(); } } 

和用户类:

 public class User extends GenericModel { ... } 

这里是示例子类定义:

 @Path("users") public class UserResource extends GenericDataResource { public UserResource() { super(User.class); } } 

我得到以下exception:

 com.sun.jersey.api.MessageException: A message body writer for Java class java.util.Vector, and Java type java.util.List, and MIME media type application/json was not found exception. 

如果我用定义的类替换T,比如User就像这样:

GenericEntity<List>(list)

然后它工作正常。

有关如何使其与通用T一起使用的任何想法?

编译源代码后,由该行创建的(匿名)类:

 new GenericEntity>(list) {} 

使用类型变量来引用其父变量。 由于类型变量在运行时没有值,因此不能使用这样的generics。 您被迫从调用站点传递所谓的类型令牌 。 这是一个需要从findAll()调用者传递令牌的示例,但您可以在构造函数中需要一个令牌并将其保存在实例变量中:

 public abstract class GenericDataResource { public Response findAll(GenericEntity> token) { Query query = em.createNamedQuery(modelClass.getSimpleName() + ".findAll"); List list = query.getResultList(); return Response.ok(token).build(); } } 

来电者会发送一个令牌

 new GenericEntity>() {} 

如果你只使用非参数化的子类, findAll()可以利用reflection来构建令牌(未经测试,希望你明白):

 @GET @Produces(MediaType.APPLICATION_JSON) public Response findAll() { Query query = em.createNamedQuery(modelClass.getSimpleName()+".findAll"); List list = query.getResultList(); return Response.ok(new GenericEntity(list, getType())).build(); } 

您必须实现getType()以返回所需的类型。 它将是ParameterizedType的子类,能够表示类型List>

除了答案之外,还要在客户端上读取Response对象:

 List list = response.readEntity(new GenericType>(){})); 

为了解决它,一个方法返回一个GenericEntity ,然后从我的generics类中调用它,如下所示:

 @XmlRootElement public abstract class AbstractRest { private Long id; public Long getId() { return id; } public void setId(Long id) { this.id = id; } } public abstract class SmartWebServiceNEW> { @GET @Produces({MediaType.APPLICATION_XML}) public Response findAll() { List lista = getDelegate().findAll(); if (lista == null || lista.isEmpty()) { return Response.status(Response.Status.NO_CONTENT).build(); } List retorno = new ArrayList(); for (T it : lista) { retorno.add(toRest(it)); } GenericEntity entity = listToGenericEntity(retorno); return Response.ok(entity).build(); } protected abstract GenericEntity listToGenericEntity(List restList); } @Path("/something") @RequestScoped public class MyEntityResource extends SmartWebServiceNEW { @Override protected GenericEntity listToGenericEntity(List restList) { return new GenericEntity>(restList) { }; } } 

响应于发送到服务器的请求, 响应对象返回给客户端。 Response类具有Response.ResponseBuilder内部类,该内部类将每个属性集收集到其Response.ResponseBuilder类型的字段中。 Response.ResponseBuilder应用Builder设计模式来构造响应对象。

build()方法负责连接在构建过程中形成的Response.ResponseBuilder对象链。 例如

 Response.status(200); 

status方法在分配STATUS后返回Response.ResponseBuilder

  Response.status(200).entity( AnyObj ); 

实体对象分配Response.ResponseBuilder类型的实体(返回的有效负载),并分配给Response的实例变量。 之后,status还会分配状态并返回Response.ResponseBuilder实例。 构建器在build()方法调用时连接它们。

 Response.status(200).entity( obj ).build(); 

最后,构建方法构造完成(具有所列出的属性)Response。

现在出现了GenericEntity对象的问题。 它表示generics类型T的响应实体。

例如,

GenericEntity> obj = new GenericEntity>(lst){}; Response.status(200).entity(obj).build();

obj是上面给出的List的类型。 entity方法接受通用的Object类型。 如果出现特定类型的需要,你必须将它作为GenericEntity类型的参数传递,在运行时它将被转换为特定类型的对象。

实际使用

希望我的Jersey Framework能够将我的Java模型中的List对象的JSON作为Response对象的一部分回复给客户端。

因此,新的GenericEntity> —将对象/有效负载转换为List类型new GenericEntity —运行时类型变为String


Web服务端的资源

 public Response findAllFruits(@QueryParam("frtID") String frtID ) { List lst = new ArrayList(); lst.add("Banana"); lst.add("Apple"); GenericEntity> obj = new GenericEntity>(lst) {}; return Response.status(200).entity( obj ).build(); } 

输出响应发送回客户端。 [“香蕉”,“苹果”]


如何阅读响应实体

 List myObj= response.readEntity(new GenericType>() {});