通过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>() {});