15

我有一个通用 JAX-RS 资源类,并且我定义了一个通用findAll方法

public abstract class GenericDataResource<T extends GenericModel> {

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

和用户类:

public class User extends GenericModel {
    ...
}

这是示例子类定义:

@Path("users")
public class UserResource extends GenericDataResource<User> {

    public UserResource() {
        super(User.class);
    }
}

我得到以下异常:

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

如果我将 T 替换为已定义的类,例如User

GenericEntity<List<User>>(list)

然后它工作正常。

关于如何使它与通用 T 一起工作的任何想法?

4

4 回答 4

12

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

new GenericEntity<List<T>>(list) {}

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

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

调用者将发送一个令牌,如

new GenericEntity<List<User>>() {}

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

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

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

于 2013-03-14T11:57:10.357 回答
10

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

List<MyObject> list = response.readEntity(new GenericType<List<MyObject>>(){}));
于 2015-02-05T09:35:09.510 回答
2

响应对象被返回给客户端以响应发送到服务器的请求。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 的实体(返回的有效负载)并分配给响应的实例变量。之后,status 还会分配状态并返回 Response.ResponseBuilder 实例。构建器在调用 build() 方法时连接它们。

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

最后,build 方法构造了完整的(带有属性的)响应。

现在是GenericEntity对象的问题。它表示一个泛型类型 T 的响应实体。

例如,

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

obj是上面给出的 List 类型。实体方法接受通用的Object类型。如果需要特定类型,您必须将其作为 GenericEntity 类型的参数传递,在运行时通过该参数将其转换为特定类型的对象。

实际使用

希望我的 Jersey 框架将 Array 类型的 JSON 作为 Response 对象的一部分响应回客户端,该 JSON 是我的 Java 模型中的 List 对象。

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


Web服务端的资源

public Response findAllFruits(@QueryParam("frtID") String frtID ) {

         List<String> lst = new ArrayList<String>();
         lst.add("Banana");
         lst.add("Apple");

         GenericEntity<List<String>> obj = new GenericEntity<List<String>>(lst) {};


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

    } 

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


如何读取响应实体

List<CustomType> myObj= response.readEntity(new GenericType<List<CustomType>>() {});
于 2017-04-03T13:28:07.457 回答
1

为了解决这个问题,我们创建了一个方法来返回 aGenericEntity然后从我的泛型类中调用它,如下所示:

@XmlRootElement
public abstract class AbstractRest<T extends IEntity> {

    private Long id;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }
}


public abstract class SmartWebServiceNEW<R extends AbstractRest<T>> {

    @GET
    @Produces({MediaType.APPLICATION_XML})
    public Response findAll() {
        List<T> lista = getDelegate().findAll();
        if (lista == null || lista.isEmpty()) {
            return Response.status(Response.Status.NO_CONTENT).build();
        }
        List<R> retorno = new ArrayList<R>();
        for (T it : lista) {
            retorno.add(toRest(it));
        }
        GenericEntity entity = listToGenericEntity(retorno);
        return Response.ok(entity).build();
    }

    protected abstract GenericEntity listToGenericEntity(List<R> restList);   
}

@Path("/something")
@RequestScoped
public class MyEntityResource extends SmartWebServiceNEW<MyEntityExtendingAbstractRest> {

 @Override
    protected GenericEntity listToGenericEntity(List<MyEntityExtendingAbstractRest> restList) {
        return new GenericEntity<List<MyEntityExtendingAbstractRest>>(restList) {
        };
    }

}
于 2013-07-01T18:30:18.323 回答