首页 文章

Jersey如何从Collections中提取泛型类型以调用javax.ws.rs.ext.MessageBodyWriter#writeTo()?

提问于
浏览
2

在使用JAX-RS规范的Rest服务中,我可以定义一个通用服务

@GET
@Path("something")
@Produces( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public List<MyPojo> getMyPojoList() {
    ...
}

在 Jersey 发生了一些神奇的事情,因为在调用时

javax.ws.rs.ext.MessageBodyWriter#writeTo(T t,
        Class<?> type,
        Type genericType,
        Annotation annotations[], 
        MediaType mediaType, 
        MultivaluedMap<String, Object> httpHeaders,
        OutputStream entityStream) throws IOException, WebApplicationException;

在分析 genericType 时,很容易看出他的 Value 是 class MyPojo .

我一直在尝试阅读泽西源代码,以了解他们如何在调用 javax.ws.rs.ext.MessageBodyWriterjavax.ws.rs.ext.MessageBodyWriter 之前提取Collection Generic类型,但是一旦到达读取 GenericEntity 类,我就迷路了 .

任何人都可以帮助我了解他们在那里使用哪种魔法?提前致谢!!!

2 回答

  • 1

    一些通用信息通过编译器保留到运行时 . 看一下有关Java反射的文档 . 在这种情况下,它们可能使用getGenericReturnType,尽管有许多方法与参数类型甚至类的通用参数有关 .

    这里最明显的缺点是只能保留编译时的信息 - 特别是你无法可靠地检查List以确定它是 List<Integer> 还是 List<String> .

  • 0

    您需要使用JAX-RS框架的神奇类来保留您正在寻找的信息 . 我花了很长时间才真正开始研究我的项目,但这就是我解决问题的方法:

    首先,在Resource类中,传递泛型集合(注意我使用Response Objects):

    public Response findAll() {
      Collection<MyType> entities = service.findAll(); // whatever code you need to load it.
      GenericEntity<Collection<MyType>> list = new GenericEntity<Collection<MyType>>(entities) {}; // This line is key!
      return Response.ok.entity(list).build();
    }
    

    然后,您可以创建一个正常的MessageBodyWriter实现,并在方法中执行类型检查,该方法负责检查您的实现是否合适 .

    public class MyTypeMessageBodyWriter implements MessageBodyWriter<MyType> {
        public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
            if (Collection.class.isAssignableFrom(type) && genericType instanceof ParameterizedType) {
                ParameterizedType parameterizedType = (ParameterizedType) genericType;
                Type[] actualTypeArgs = parameterizedType.getActualTypeArguments();
                return (actualTypeArgs.length == 1 && actualTypeArgs[0].equals(MyType.class));
            } else {
                return false;
            }
        }
    }
    

    您可以增强 isWriteable 方法以执行更多检查,例如仔细检查 MediaType 是否正确,以及是否需要存在某些注释等,具体取决于您的要求 .

    但要总结一下:

    • 将您的集合包装在 GenericEntity<> 包装器中以保留通用类型信息

    • 在MessageBodyWriter中执行适当的强制转换以确定类型 .

相关问题