【问题标题】:How can I customize serialization of a list of JAXB objects to JSON?如何自定义将 JAXB 对象列表序列化为 JSON?
【发布时间】:2011-01-13 01:20:18
【问题描述】:

我正在使用 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&lt;XMLDistribution&gt;、一个XMLDistributionList(一个列表的包装)、一个XMLDistribution[],但我找不到以我所需格式获取一个简单的JSON分布数组的方法。

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

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

【问题讨论】:

    标签: json jaxb serialization jersey jax-rs


    【解决方案1】:

    我找到了一个解决方案:将 JAXB JSON 序列化器替换为像 Jackson 这样表现更好的 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”。这是一个例子:

    @Provider @Produces("应用程序/json") 公共类 JsonMessageBodyWriter 实现 MessageBodyWriter { @Override public long getSize(Object obj, Class type, Type genericType, Annotation[] 注释,MediaType mediaType) { 返回-1; } @Override 公共布尔isWriteable(类类型,类型genericType, 注释 annotations[], MediaType mediaType) { 返回真; } @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/

    【讨论】:

    • maven 依赖“jersey-json”包含正确的jackson json 转换器。 com.sun.jerseyjersey-json1.13
    • 好答案!但是,我发现默认的 JSON 转换器不会被修复很奇怪。我敢打赌是因为:没用
    • 如果您的阵列在切换到 Jackson 后仍在包装,请查看 stackoverflow.com/questions/11027713/…
    • 我使用 guice 而不是 web.xml 来配置;这篇博文帮助了我:flamingpenguin.co.uk/blog/2012/08/17/…
    • +1 ... 我只想指出,init-param 解决方案在我的本地开发期间在 Jetty 中有效,但在部署到 Websphere 时无效。但是,您的第二个解决方案效果很好。
    【解决方案2】:

    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>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-11
      • 1970-01-01
      • 2021-04-16
      • 1970-01-01
      相关资源
      最近更新 更多