【问题标题】:JAX-RS - JSON without root nodeJAX-RS - 没有根节点的 JSON
【发布时间】:2011-06-17 19:33:07
【问题描述】:

我有一个安静的网络服务,响应是:

{
    "cities": [{
        "id": "1",
        "name": "City 01",
        "state": "A1"
    }, {
        "id": "2",
        "name": "City 02",
        "state": "A1"
    }]
}

但我想要这个:

{
    [{
        "id": "1",
        "name": "City 01",
        "state": "A1"
    }, {
        "id": "2",
        "name": "City 02",
        "state": "A1"
    }]
}

如何配置 JAX-RS 以仅使用 JAX-RS 功能而不是实现特定功能来生成没有根节点的 JSON?我的代码需要跨任何应用服务器移植。

【问题讨论】:

  • 你的模型(城市)类 JAXB 是如何注解的?这将控制 XML 和 JSON 的串行/反序列化。
  • 我的班级如下:@XmlRootElement(name = "cities") public class CityDTO implements Serializable { }

标签: java json jax-rs


【解决方案1】:

Glassfish v3 也有同样的问题。我发现这种行为取决于 JAX-RS 实现,切换到 Codehaus 的 Jackson JAX-RS 实现为我解决了这个问题。

如果您也在使用 Glassfish,那么您可以通过将 org.codehaus.jackson.jaxrs 添加到您的战争以及 WEB-INF/web.xml 配置中来解决问题,如下所示:

<!-- REST -->

<servlet>
  <servlet-name>RESTful Services</servlet-name>
  <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
  <init-param>
    <param-name>com.sun.jersey.config.property.resourceConfigClass</param-name>
    <param-value>com.sun.jersey.api.core.PackagesResourceConfig</param-value>
  </init-param>
  <init-param>
    <param-name>com.sun.jersey.config.property.packages</param-name>
    <param-value>you.service.packages;org.codehaus.jackson.jaxrs</param-value>
    <!-- NOTE: The last element above, org.codehaus.jackson.jaxrs, replaces the default
       JAX-RS processor with the Codehaus Jackson JAX-RS implementation. The default
       JAX-RS processor returns top-level arrays encapsulated as child elements of a
       single JSON object, whereas the Jackson JAX-RS implementation return an array.
    -->
  </init-param>
  <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
  <servlet-name>RESTful Services</servlet-name>
  <url-pattern>/your/rest/path/*</url-pattern>
</servlet-mapping>

或者,您可以简单地拦截客户端中的响应:

function consumesCity(json) {
   ...
}

替换

... consumesCity(json) ...

function preprocess(json) {
    return json.city;
}

... consumesCity(preprocess(json)) ...

【讨论】:

  • 谢谢你,金。但我仍然会寻找便携式解决方案。
  • 我的印象是这种特定行为是特定于供应商的,即集合返回类型的顶级 JSON 对象是数组,还是具有包含集合成员的字段的单个对象。看到 Glassfish 的参考实现返回后一种风格的集合,我有点沮丧。我认为返回 JSON 数组更直观。如果您找到更好的解决方案,请发布更新。
  • 我同意金的观点。虽然结构确实不同——主要是由于历史原因,特别是因为有通过 XML API 处理 JSON 的库,这有时会强制使用包装器——但实际上并没有更标准的方式,除非你想使用自定义MessageBodyWriter/Reader 实现。
【解决方案2】:

好问题。我有类似的要求。我必须有权访问生成的原始响应并进行一些操作。我通过注册一个共振过滤器然后适应一个自定义的响应者来实现这一点。有关详细信息,请参阅下面的链接。

http://www.mentby.com/paul-sandoz/access-to-raw-xml-in-jersey.html

在您的响应过滤器中,您可以从生成的 json 中剪掉类名,或者更好的是,在响应中返回 String 并使用自定义 json 序列化机制,如 Google-gson。

让我知道这个解决方案是否有效。

【讨论】:

    【解决方案3】:

    上面 Kim Burgaard 的回答也适用于 Jersey Spring WS。我在使用 Glassfish 3.0 时遇到了同样的问题,并通过添加如下所示的参数解决了它。

    示例 web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app version="2.4"
             xmlns="http://java.sun.com/xml/ns/j2ee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:applicationContext.xml</param-value>
        </context-param>
        <listener>
            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        </listener>
        <listener>
            <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
        </listener>
        <servlet>
            <servlet-name>Jersey Spring Web Application</servlet-name>
            <servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
            <init-param>
                <param-name>com.sun.jersey.config.property.packages</param-name>
                <param-value>org.codehaus.jackson.jaxrs</param-value>
    <!--             NOTE: The last element above, org.codehaus.jackson.jaxrs, replaces the default
                   JAX-RS processor with the Codehaus Jackson JAX-RS implementation. The default
                   JAX-RS processor returns top-level arrays encapsulated as child elements of a
                   single JSON object, whereas the Jackson JAX-RS implementation return an array.-->
            </init-param>
        </servlet>
        <servlet-mapping>
            <servlet-name>Jersey Spring Web Application</servlet-name>
            <url-pattern>/services/*</url-pattern>
        </servlet-mapping>
    </web-app>
    

    示例 applicationContext.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
           xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
           xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
           xsi:schemaLocation="
                http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
                http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
                http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
                http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd
                http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
        <!--  Scan for both Jersey Rest Annotations and persistence classes  -->
        <context:component-scan base-package="your.service.packages"/>
    </beans>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-06
      • 1970-01-01
      • 2012-11-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多