简体   繁体   English

如何将 JAXB 对象列表的序列化自定义为 JSON?

[英]How can I customize serialization of a list of JAXB objects to JSON?

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. REST 资源和上下文解析器都可以工作。 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.我不明白为什么那里有一个封闭的distribution标签。 I wanted to remove it with .rootUnwrapping(true) in the context resolver, but apparently that only removes another enclosing tag.我想在上下文解析器中使用.rootUnwrapping(true)删除它,但显​​然这只会删除另一个封闭标签。 This is the output with .rootUnwrapping(false) :这是.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.我试图返回一个List<XMLDistribution> 、一个XMLDistributionList (一个列表的包装器)、一个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 来做到这一点?

I found a solution: replace the JAXB JSON serializer with a better behaved JSON serializer like Jackson.我找到了一个解决方案:将 JAXB JSON 序列化器替换为性能更好的 JSON 序列化器,例如 Jackson。 The easy way is to use jackson-jaxrs, which has already done it for you.简单的方法是使用 jackson-jaxrs,它已经为您完成了。 The class is JacksonJsonProvider.该类是 JacksonJsonProvider。 All you have to do is edit your project's web.xml so that Jersey (or another JAX-RS implementation) scans for it.您所要做的就是编辑项目的 web.xml,以便 Jersey(或其他 JAX-RS 实现)扫描它。 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. Jackson 将用于 JSON 序列化,它以您期望的列表和数组方式工作。

The longer way is to write your own custom MessageBodyWriter registered to produce "application/json".更长的方法是编写自己的自定义 MessageBodyWriter 注册以生成“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.您需要确保您的 web.xml 包含该包,就像上面的现成解决方案一样。

Either way: voila!无论哪种方式:瞧! You'll see properly formed JSON.您将看到格式正确的 JSON。

You can download Jackson from here: http://jackson.codehaus.org/你可以从这里下载杰克逊: http : //jackson.codehaus.org/

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 Jackson (eg version 2.1) the class is com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider, therefore the web.xml is:如果您使用 Jackson 的 2.x 版(例如 2.1 版),则该类为 com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider,因此 web.xml 为:

<init-param>
  <param-name>com.sun.jersey.config.property.packages</param-name>
  <param-value>your.project.packages;com.fasterxml.jackson.jaxrs.json</param-value>
</init-param>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM