如何将 JAXB 对象列表的序列化自定义为 JSON? [英] How can I customize serialization of a list of JAXB objects to JSON?

查看:65
本文介绍了如何将 JAXB 对象列表的序列化自定义为 JSON?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 Jersey 为服务器组件创建 REST Web 服务.

我想在列表中序列化的 JAXB 注释对象如下所示:

@XmlRootElement(name = "distribution")@XmlType(name = "tDistribution", propOrder = {身份证",姓名"})公共类 XMLDistribution {私人字符串ID;私人字符串名称;//无参数构造函数、getter、setter 等}

我有一个 REST 资源来检索一个如下所示的分布:

@Path("/distribution/{id: [1-9][0-9]*}")公共类 RESTDistribution {@得到@Produces("应用程序/json")公共 XMLDistribution 检索(@PathParam(id")字符串 id){返回retrieveDistribution(Long.parseLong(id));}//业务逻辑(retrieveDistribution(long))}

我还有一个 REST 资源来检索所有发行版的列表,如下所示:

@Path("/distributions")公共类 RESTDistributions {@得到@Produces("应用程序/json")公共列表检索所有(){返回retrieveDistributions();}//业务逻辑(retrieveDistributions())}

我使用了一个ContextResolver来自定义JAXB序列化,目前是这样配置的:

@Provider@Produces("应用程序/json")公共类 JAXBJSONContextResolver 实现了 ContextResolver{私有 JAXBContext 上下文;公共 JAXBJSONContextResolver() 抛出异常 {JSONConfiguration.MappedBuilder b = JSONConfiguration.mapped();b.nonStrings("id");b.rootUnwrapping(true);b.arrays("分布");context = new JSONJAXBContext(b.build(), XMLDistribution.class);}@覆盖public JAXBContext getContext(Class objectType) {返回上下文;}}

REST 资源和上下文解析器都可以工作.这是第一个输出的示例:

//路径:/distribution/1{身份证":1,"name": "示例分布"}

这正是我想要的.这是列表的输出示例:

//路径:/distributions{分配": [{身份证":1,"name": "样本分布 1"}, {身份证":2,"name": "样本分布 2"}]}

这不是我想要的.

我不明白为什么那里有一个封闭的 distribution 标签.我想在上下文解析器中使用 .rootUnwrapping(true) 删除它,但显​​然这只会删除另一个封闭标签.这是带有 .rootUnwrapping(false) 的输出:

//路径:/distribution/1{分配": {身份证":1,"name": "示例分布"}}//不好//路径:/分布{xMLDistributions":{分配": [{身份证":1,"name": "样本分布 1"}, {身份证":2,"name": "样本分布 2"}]}}

我还必须配置 .arrays("distribution") 以始终获得一个 JSON 数组,即使只有一个元素.

理想情况下,我希望将其作为输出:

//路径:/distribution/1{身份证":1,"name": "示例分布"}//目前有效//路径:/分布[{身份证":1,"name": "样本分布 1"}, {身份证":2,"name": "样本分布 2"}]

我试图返回一个 List、一个 XMLDistributionList(一个列表的包装器)、一个 XMLDistribution[],但我找不到以我所需格式获取简单 JSON 分布数组的方法.

我还尝试了 JSONConfiguration.natural()JSONConfiguration.mappedJettison() 等返回的其他符号,但没有得到与我需要的类似的任何东西.

有谁知道是否可以配置 JAXB 来执行此操作?

解决方案

我找到了一个解决方案:将 JAXB JSON 序列化器替换为性能更好的 JSON 序列化器,例如 Jackson.简单的方法是使用 jackson-jaxrs,它已经为您完成了.该类是 JacksonJsonProvider.您所要做的就是编辑项目的 web.xml,以便 Jersey(或其他 JAX-RS 实现)扫描它.以下是您需要添加的内容:

<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("应用程序/json")公共类 JsonMessageBodyWriter 实现 MessageBodyWriter {@覆盖public long getSize(Object obj, Class type, Type genericType,Annotation[] annotations, MediaType mediaType) {返回-1;}@覆盖public boolean isWriteable(Class type, Type genericType,注释 annotations[], MediaType mediaType) {返回真;}@覆盖public void writeTo(Object target, Class type, Type genericType,Annotation[] 注释,MediaType mediaType,MultivaluedMap httpHeaders, OutputStream outputStream)抛出 IOException {new ObjectMapper().writeValue(outputStream, target);}}

您需要确保您的 web.xml 包含该包,就像上面的现成解决方案一样.

不管怎样:瞧!您会看到格式正确的 JSON.

您可以从这里下载 Jackson:http://jackson.codehaus.org/

I'm using Jersey to create a REST web service for a server component.

The JAXB-annotated object I want to serialize in a list looks like this:

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

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

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

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

// 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 distribution tag 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):

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

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.

I also tried the other notations returned by JSONConfiguration.natural(), JSONConfiguration.mappedJettison(), etc, and couldn't get anything resembling what I need.

Does anyone know if it is possible to configure JAXB to do this?

解决方案

I found a solution: replace the JAXB JSON serializer with a better behaved JSON serializer like Jackson. The easy way is to use jackson-jaxrs, which has already done it for you. The class is JacksonJsonProvider. 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:

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

And that's all there is to it. Jackson will be used for JSON serialization, and it works the way you expect for lists and arrays.

The longer way is to write your own custom MessageBodyWriter registered to produce "application/json". Here's an example:

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

Either way: voila! You'll see properly formed JSON.

You can download Jackson from here: http://jackson.codehaus.org/

这篇关于如何将 JAXB 对象列表的序列化自定义为 JSON?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆