如何将 JAXB 对象列表的序列化自定义为 JSON?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2199453/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I customize serialization of a list of JAXB objects to JSON?
提问by Alpha Hydrae
I'm using Jersey to create a REST web service for a server component.
我正在使用 Jersey 为服务器组件创建 REST Web 服务。
The JAXB-annotated object I want to serialize in a list looks like this:
我想在列表中序列化的 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
}
I have a REST resource to retrieve one distribution which looks like this:
我有一个 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))
}
I also have a REST resource to retrieve a list of all distributions, which looks like this:
我还有一个 REST 资源来检索所有发行版的列表,如下所示:
@Path("/distributions")
public class RESTDistributions {
@GET
@Produces("application/json")
public List<XMLDistribution> retrieveAll() {
return retrieveDistributions();
}
// business logic (retrieveDistributions())
}
I use a ContextResolver to customize JAXB serialization, which is currently configured like this:
我使用 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;
}
}
Both REST resources work, as well as the context resolver. This is an example of output for the first one:
REST 资源和上下文解析器都可以工作。这是第一个输出的示例:
// path: /distribution/1
{
"id": 1,
"name": "Example Distribution"
}
Which is exactly what I want. This is an example of output for the list:
这正是我想要的。这是列表的输出示例:
// path: /distributions
{
"distribution": [{
"id": 1,
"name": "Sample Distribution 1"
}, {
"id": 2,
"name": "Sample Distribution 2"
}]
}
Which is not quite what I want.
这不是我想要的。
I don't understand why there is an enclosing distributiontag there. I wanted to remove it with .rootUnwrapping(true)in the context resolver, but apparently that only removes another enclosing tag. This is the output with .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"
}]
}
}
I also had to configure .arrays("distribution")to always get a JSON array, even with only one element.
我还必须配置.arrays("distribution")为始终获取 JSON 数组,即使只有一个元素。
Ideally, I'd like to have this as an output:
理想情况下,我希望将其作为输出:
// path: /distribution/1
{
"id": 1,
"name": "Example Distribution"
} // currently works
// path: /distributions
[{
"id": 1,
"name": "Sample Distribution 1"
}, {
"id": 2,
"name": "Sample Distribution 2"
}]
I tried to return a List<XMLDistribution>, a XMLDistributionList(wrapper around a list), a XMLDistribution[], but I couldn't find a way to get a simple JSON array of distributions in my required format.
我试图返回 a List<XMLDistribution>, a XMLDistributionList(环绕列表的包装器), a XMLDistribution[],但我找不到一种方法以我所需的格式获取简单的 JSON 分布数组。
I also tried the other notations returned by JSONConfiguration.natural(), JSONConfiguration.mappedJettison(), etc, and couldn't get anything resembling what I need.
我也试图通过返回的其他符号JSONConfiguration.natural(),JSONConfiguration.mappedJettison()等,并不能得到任何类似我需要什么。
Does anyone know if it is possible to configure JAXB to do this?
有谁知道是否可以配置 JAXB 来做到这一点?
回答by Jonathan
I found a solution: replace the JAXB JSON serializer with a better behaved JSON serializer like Hymanson. The easy way is to use Hymanson-jaxrs, which has already done it for you. The class is HymansonJsonProvider. All you have to do is edit your project's web.xml so that Jersey (or another JAX-RS implementation) scans for it. Here's what you need to add:
我找到了一个解决方案:将 JAXB JSON 序列化器替换为性能更好的 JSON 序列化器,例如 Hymanson。简单的方法是使用 Hymanson-jaxrs,它已经为您完成了。该类是 HymansonJsonProvider。您所要做的就是编辑项目的 web.xml,以便 Jersey(或其他 JAX-RS 实现)扫描它。以下是您需要添加的内容:
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>your.project.packages;org.codehaus.Hymanson.jaxrs</param-value>
</init-param>
And that's all there is to it. Hymanson will be used for JSON serialization, and it works the way you expect for lists and arrays.
这就是全部。Hymanson 将用于 JSON 序列化,它以您期望的列表和数组的方式工作。
The longer way is to write your own custom MessageBodyWriter registered to produce "application/json". Here's an example:
更长的方法是编写自己的自定义 MessageBodyWriter 注册以生成“application/json”。下面是一个例子:
@Provider
@Produces("application/json")
public class JsonMessageBodyWriter implements MessageBodyWriter {
@Override
public long getSize(Object obj, Class type, Type genericType,
Annotation[] annotations, MediaType mediaType) {
return -1;
}
@Override
public boolean isWriteable(Class type, Type genericType,
Annotation annotations[], MediaType mediaType) {
return true;
}
@Override
public void writeTo(Object target, Class type, Type genericType,
Annotation[] annotations, MediaType mediaType,
MultivaluedMap httpHeaders, OutputStream outputStream)
throws IOException {
new ObjectMapper().writeValue(outputStream, target);
}
}
You'll need to make sure your web.xml includes the package, as for the ready-made solution above.
您需要确保您的 web.xml 包含该包,就像上面的现成解决方案一样。
Either way: voila! You'll see properly formed JSON.
无论哪种方式:瞧!您将看到格式正确的 JSON。
You can download Hymanson from here: http://Hymanson.codehaus.org/
你可以从这里下载Hyman逊:http: //Hymanson.codehaus.org/
回答by Gabriele
The answer of Jonhatan is great and it has been very useful for me.
Jonhatan 的回答很棒,对我非常有用。
Just an upgrade:
只是升级:
if you use the version 2.x of Hymanson (e.g. version 2.1) the class is com.fasterxml.Hymanson.jaxrs.json.HymansonJaxbJsonProvider, therefore the web.xml is:
如果您使用 Hymanson 的 2.x 版(例如 2.1 版),则该类为 com.fasterxml.Hymanson.jaxrs.json.HymansonJaxbJsonProvider,因此 web.xml 为:
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>your.project.packages;com.fasterxml.Hymanson.jaxrs.json</param-value>
</init-param>

