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

问题描述 投票:55回答:2

我正在使用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)的输出:

// 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数组,即使只有一个元素也是如此。

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

// 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数组的方法。

[我还尝试了JSONConfiguration.natural()JSONConfiguration.mappedJettison()等返回的其他符号,但无法获得与我需要的东西相似的东西。

有人知道是否可以配置JAXB来做到这一点吗?

json jaxb serialization jersey jax-rs
2个回答
102
投票

我找到了一个解决方案:用性能更好的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 {@Overridepublic long getSize(Object obj,Class type,Type genericType,Annotation []批注,MediaType mediaType){返回-1;}@Overridepublic boolean isWriteable(Class type,Type genericType,注释注释[],MediaType mediaType){返回true;}@Overridepublic 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/


13
投票

Jonhatan的回答很好,对我来说非常有用。

只是升级:

如果您使用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>
© www.soinside.com 2019 - 2024. All rights reserved.