如何使用Jersey REST序列化Java基元

在我的应用程序中,我使用Jersey REST来序列化复杂对象。 这很好用。 但是有一些方法只返回一个int或boolean。

泽西岛无法处理原始类型(据我所知),可能是因为它们没有注释,而泽西没有默认注释。 我通过创建像RestBoolean或RestInteger这样的复杂类型来解决这个问题,它只包含一个int或boolean值并具有相应的注释。

有没有比编写这些容器对象更简单的方法?

看看Genson。它帮助了我很多类似的问题。使用Genson你可以使用generics,如int,boolean,list等……这是一个简单的例子。

@GET @Produces(MediaType.APPLICATION_JSON) public Response getMagicList() { List objList = new ArrayList<>(); stringList.add("Random String"); stringList.add(121); //int stringList.add(1.22); //double stringList.add(false); //bolean return Response.status(Status.OK).entity(objList).build(); } 

这将生成一个有效的JSON女巫,可以像这样非常简单地检索:

  Client client = Client.create(); WebResource webResource = client.resource("...path to resource..."); List objList = webResource.accept(MediaType.APPLICATION_JSON).get(ArrayList.class); for (Object obj : objList) { System.out.println(obj.getClass()); } 

您将看到Genson也将帮助您在客户端解码JSON并为每个输出正确的类。

你在写服务还是客户? 在服务端,你只需编写一个MessageBodyWriter来将数据流序列化为类型的Java对象。 在我的用例中,我正在编写的服务输出到JSON或XML,而在XML的情况下,我只是在我的类的顶部抛出一个JAXB注释,我就完成了。

您是否看过泽西用户指南?

3.6。 添加对新表示的支持

实际上,最好的办法是编写一个自定义的ContextResolver Provider,如下所示,使用JSON的自然构建。

  @Provider public class YourContextResolver implements ContextResolver { private JAXBContext context; private Class[] types = { YourSpecialBean.class }; public YourContextResolver() throws Exception { this.context = new JSONJAXBContext( JSONConfiguration.natural().build(), types); } public JAXBContext getContext(Class objectType) { for (int i = 0; i < this.types.length; i++) if (this.types[i].equals(objectType)) return context; return null; } } 

这里唯一需要注意的是Class []中的YourSpecialBean.class。 这定义了此提供程序将自然解析的类类型数组。

告诉Jersey生成适当的JSON文档(自然json)。 我为rest app和JAXBContext解析器使用相同的类,发现它是最干净的封装。

更好的程序员可以通过识别@Annotation标签来实现帮助程序来迭代.class文件并自动列出适当的类。 我不知道如何在自己的源代码中运行它。

这两个链接有助于研究这个额外的java行话。 我不知道为什么没有Jersey参数可以让所有人都能开箱即用。

WEB-INF / web.xml(片段):

  RESTServlet com.sun.jersey.spi.container.servlet.ServletContainer  javax.ws.rs.Application com.myapp.rest.RESTApplication    RESTServlet /servlet/rest/*  

com.myapp.rest.RESTApplication.java

 package com.myapp.rest; import java.util.*; import javax.ws.rs.core.Application; import javax.ws.rs.ext.ContextResolver; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import com.sun.jersey.api.json.JSONConfiguration; import com.sun.jersey.api.json.JSONJAXBContext; public class RESTApplication extends Application implements ContextResolver { private JAXBContext context; private Class[] types; public RESTApplication() throws JAXBException { // list JAXB bean types to be used for REST serialization types = new Class[] { com.myapp.rest.MyBean1.class, com.myapp.rest.MyBean2.class, }; context = new JSONJAXBContext(JSONConfiguration.natural().build(), types); } @Override public Set> getClasses() { // list JAXB resource/provider/resolver classes Set> classes = new HashSet>(); //for(Class type : types) // classes.add(type); classes.add(MyBeansResource.class); classes.add(this.getClass()); // used as a ContextResolver class return classes; } @Override public JAXBContext getContext(Class objectType) { // this is called each time when rest path was called by remote client for (Class type : types) { if (type==objectType) return context; } return null; } } 

类MyBean1,MyBean2是普通的java对象,MyBeansResource类是具有@Path rest函数的类。 他们期待标准的jaxp @Annotations在这里和那里没有什么特别之处。 在这个java术语JSON文件之后

  • 零或单元素列表数组总是写为json数组([]字段)
  • 原始整数和布尔字段写为json原语(不带引号)

我使用以下环境

  • Sun Java JDK1.6.x
  • Apache Tomcat 6.x
  • 泽西岛v1.14图书馆(jersey-archive-1.14.zip)
  • webapps / myapp / WEB-INF / lib文件夹有asm-3.3.1.jar,jackson-core-asl.jar,jersey-client.jar,jersey-core.jar,jersey-json.jar,jersey-server.jar ,jersey-servlet.jar库
  • 如果使用infomas-asl发现工具,请添加可选的annotation-detector.jar

jersey-archive.zip有较旧的asm-3.1.jar文件,可能工作正常,但chapter_deps.html链接到较新的文件。 请参阅顶部的链接列表。

编辑我发现了一个优秀的(快速,轻量级只有15KB)注释发现工具。 请参阅这篇文章,了解我如何在运行时自动发现类型,并且每次添加新的java(jaxb)bean时都不再需要编辑RESTApplication。

https://github.com/rmuller/infomas-asl/issues/7

我今天遇到了同样的问题,直到找到一个非常合适的解决方案才放弃。 我无法从1.1.5更新泽西图书馆,它是一个传统系统。 我的rest服务返回一个列表,他们应该遵循这些规则。

  1. 空列表呈现为[](几乎不可能)
  2. 一个元素列表呈现为[](困难但仅映射配置)
  3. 许多元素列表呈现为[](简单)

从容易到不可能开始。

3)今天没有什么正常的JSON映射

2)注册JAXBContextResolver,如下所示

 @Provider public class JAXBContextResolver implements ContextResolver { private final JAXBContext context; private final Set> types; private Class[] ctypes = { Pojo.class }; //your pojo class public JAXBContextResolver() throws Exception { this.types = new HashSet>(Arrays.asList(ctypes)); this.context = new JSONJAXBContext(JSONConfiguration.mapped() .rootUnwrapping(true) .arrays("propertyName") //that should rendered as JSONArray even if the List only contain one element but doesn't handle the empty Collection case .build() , ctypes); } @Override public JAXBContext getContext(Class objectType) { return (types.contains(objectType)) ? context : null; } } 

1)以下方法仅适用于Collections $ EmptyList类。 您是否可以找到一种方法,使其对所有集合都是空的。 可能代码处理EmptyList所以。

 @Provider @Produces(value={MediaType.APPLICATION_JSON}) public class EmptyListWriter implements MessageBodyWriter { private static final String EMPTY_JSON_ARRAY = "[]"; @Override public long getSize(AbstractList list, Class clazz, Type type, Annotation[] annotations, MediaType mediaType) { return EMPTY_JSON_ARRAY.length(); } @Override public boolean isWriteable(Class clazz, Type type, Annotation[] annotations, MediaType mediaType) { return clazz.getName().equals("java.util.Collections$EmptyList"); } @Override public void writeTo(AbstractList list, Class clazz, Type type, Annotation[] annotations, MediaType mediaType, MultivaluedMap headers, OutputStream outputStream) throws IOException, WebApplicationException { if (list.isEmpty()) outputStream.write(EMPTY_JSON_ARRAY.getBytes()); } } 

我刚刚发现用Jersey返回一个原始类型是有问题的。 我已决定返回String。 也许这不干净,但我认为它太脏了。 Java客户端大多数时间由服务器的同一作者编写,可以包装这样的字符串返回值并将其转换回int。 用其他语言编写的客户端必须以任何方式了解返回类型。

定义RestInteger,RestBoolean可能是另一种选择,但它更麻烦,我觉得它的吸引力太小了。

或许我在这里错过了一些重要的东西?