我正在使用Jersey为服务器组件创建REST Web服务。
我要在列表中序列化的带有JAXB注释的对象如下所示:
@XmlRootElement(name = "distribution") @XmlType(name = "tDistribution", propOrder = { "id", "name" }) public class XMLDistribution { private String id; private String name; // no-args constructor, getters, setters, etc }
我有一个REST资源来检索一个看起来像这样的发行版:
@Path("/distribution/{id: [1-9][0-9]*}") public class RESTDistribution { @GET @Produces("application/json") public XMLDistribution retrieve(@PathParam("id") String id) { return retrieveDistribution(Long.parseLong(id)); } // business logic (retrieveDistribution(long)) }
我还有一个REST资源来检索所有发行版的列表,如下所示:
@Path("/distributions") public class RESTDistributions { @GET @Produces("application/json") public List<XMLDistribution> retrieveAll() { return retrieveDistributions(); } // business logic (retrieveDistributions()) }
我使用ContextResolver自定义JAXB序列化,当前配置如下:
@Provider @Produces("application/json") public class JAXBJSONContextResolver implements ContextResolver<JAXBContext> { private JAXBContext context; public JAXBJSONContextResolver() throws Exception { JSONConfiguration.MappedBuilder b = JSONConfiguration.mapped(); b.nonStrings("id"); b.rootUnwrapping(true); b.arrays("distribution"); context = new JSONJAXBContext(b.build(), XMLDistribution.class); } @Override public JAXBContext getContext(Class<?> objectType) { return context; } }
REST资源和上下文解析器都可以使用。这是第一个输出的示例:
// path: /distribution/1 { "id": 1, "name": "Example Distribution" }
这正是我想要的。这是列表的输出示例:
// path: /distributions { "distribution": [{ "id": 1, "name": "Sample Distribution 1" }, { "id": 2, "name": "Sample Distribution 2" }] }
这不是我想要的。
我不明白为什么那里有一个封闭distribution标签。我想使用.rootUnwrapping(true)上下文解析器将其删除,但显然,这仅删除了另一个封闭标签。这是带有.rootUnwrapping(false)以下内容的输出:
distribution
.rootUnwrapping(true)
.rootUnwrapping(false)
// path: /distribution/1 { "distribution": { "id": 1, "name": "Example Distribution" } } // not ok // path: /distributions { "xMLDistributions": { "distribution": [{ "id": 1, "name": "Sample Distribution 1" }, { "id": 2, "name": "Sample Distribution 2" }] } }
我还必须配置.arrays("distribution")为始终获取JSON数组,即使只有一个元素也是如此。
.arrays("distribution")
理想情况下,我希望将其作为输出:
// path: /distribution/1 { "id": 1, "name": "Example Distribution" } // currently works // path: /distributions [{ "id": 1, "name": "Sample Distribution 1" }, { "id": 2, "name": "Sample Distribution 2" }]
我试图返回一个List<XMLDistribution>,XMLDistributionList(一个围绕列表的包装器),一个XMLDistribution[],但是我找不到一种方法来获取所需格式的简单JSON分布数组。
List<XMLDistribution>
XMLDistributionList
XMLDistribution[]
我还尝试了由JSONConfiguration.natural(),JSONConfiguration.mappedJettison()等返回的其他符号,但没有得到与我需要的东西相似的东西。
JSONConfiguration.natural()
JSONConfiguration.mappedJettison()
有谁知道是否可以配置JAXB来做到这一点?
我找到了一个解决方案:用性能更好的JSON序列化程序(例如Jackson)替换JAXB JSON序列化程序。简单的方法是使用已经为您完成的jackson- jaxrs。该类是JacksonJsonProvider。您所要做的就是编辑项目的web.xml,以便Jersey(或另一个JAX- RS实现)对其进行扫描。这是您需要添加的内容:
<init-param> <param-name>com.sun.jersey.config.property.packages</param-name> <param-value>your.project.packages;org.codehaus.jackson.jaxrs</param-value> </init-param>
这就是全部。Jackson将用于JSON序列化,并且可以按您期望的方式使用列表和数组。
更长的方法是编写您自己的自定义MessageBodyWriter,注册该内容以生成“ application / json”。这是一个例子:
@提供者 @Produces(“ application / json”) 公共类JsonMessageBodyWriter实现MessageBodyWriter { @Override public long getSize(Object obj,Class type,Type genericType, Annotation []批注,MediaType mediaType){ 返回-1; } @Override public boolean isWriteable(Class type,Type genericType, 注释注释[],MediaType mediaType){ 返回true; } @Override public void writeTo(Object target,Class type,Type genericType, Annotation []批注,MediaType mediaType, MultivaluedMap httpHeaders,OutputStream outputStream) 引发IOException { 新的ObjectMapper()。writeValue(outputStream,target); } }
与上面的现成解决方案一样,您需要确保web.xml包括该包。
无论哪种方式:瞧!您会看到格式正确的JSON。
您可以从此处下载Jackson:http : //jackson.codehaus.org/