使用Java-泛型模板类型>

使用Java-泛型模板类型>

问题描述:

我有一个通用的JAX-RS资源类和我已经定义了一个通用的findAll方法使用Java-泛型模板类型>

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工作?

+0

超类型令牌的整点是捕获,否则将被删除的一般信息。试图让令牌本身具有通用性就是......适得其反。 – Perception 2013-03-14 11:47:58

+0

我需要“T扩展GenericModel”,因为有一些函数需要在抽象类中访问,例如T.getId() – Emin 2013-03-14 11:52:29

一旦源代码被编译,由线产生的(匿名)类:

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>>

+0

THanks Raffaele。我有一个类“公共类UserResource扩展GenericDataResource ”。这个想法是扩展泛型类而不覆盖其功能,如果标准的行为是预期的。我认为在你的解决方案中,每个扩展抽象类的类都应该重写findAll方法?任何可能跳过重写? – Emin 2013-03-14 12:02:23

+0

无需重写。调用'findAll()'的代码必须传递一个标记,但该方法本身没有修改就可以工作。顺便说一句,如果你绝对确信**你只会通过像'UserResource'这样的非参数化子类来使用'GenericDataResource ',那么你可以通过反射获得该标记(为'findAll()'恢复0-arity' ) – Raffaele 2013-03-14 12:09:32

+0

实际上没有明确调用findAll的方法。它通过注释调用。我编辑了问题以显示JAX-RS注释。 – Emin 2013-03-14 12:22:32

为了解决它的子类中的做了一个方法返回一个GenericEntity,然后从我的泛型类调用它,有些东西象下面这样:

@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) { 
     }; 
    } 

} 

除了答案,阅读Response对象后面的客户端上:

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

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

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

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

实体对象后

Response.status(200); 

状态的方法返回Response.ResponseBuilder分配 类型Response.ResponseBuilder的实体(有效载荷返回)和被分配给的响应的实例varible。之后,状态还会分配状态并返回Response.ResponseBuilder实例。构建器在build()方法调用时连接它们。

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

最后,构建方法构建完整(有属性阐述)响应。

现在问题GenericEntity对象。它代表了一种通用类型T.

对于实例的响应实体,

GenericEntity> OBJ =新GenericEntity>(LST){}; Response.status(200).entity(obj).build();

obj是List的类型,如上所述。实体方法接受对象通用类型。如果出现特定类型的需要,则必须将其作为GenericEntity类型的参数传递,在运行时将它转换为特定类型的对象。

实际运用

通缉我的球衣框架来这是List对象在我的Java模型回客户端作为响应对象的一部分数组类型的响应JSON。

因此, 新GenericEntity> ---连铸对象/有效载荷列出 类型新GenericEntity ---运行时类型变得字符串


资源上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>>() {});