2011-01-29 5 views
6

Mam relaksującego usługę internetową, a odpowiedź brzmi:JAX-RS - JSON bez węzła głównego

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

Ale chcę to:

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

Jak mogę skonfigurować JAX-RS do produkuje JSON bez węzła głównego przy użyciu tylko funkcji JAX-RS, a nie funkcji specyficznej dla implementacji? Mój kod musi być przenośny w każdym appserver.

+0

jaki jest model klasy (Miasto) JAXB adnotacji? to właśnie kontroluje seryjne/deserialization do/z XML i JSON. –

+0

Moja klasa poniżej: @XmlRootElement (name = "cities") Publiczna klasa CityDTO implementuje Serializable { } –

Odpowiedz

4

Miałem ten sam problem z Glassfish v3. Zauważyłem, że to zachowanie zależy od implementacji JAX-RS i przejścia do implementacji Codehausa Jacksona JAX-RS rozwiązało problem dla mnie.

Jeśli używasz GlassFish jak dobrze, to można rozwiązać ten problem przez dodanie org.codehaus.jackson.jaxrs do wojny, jak również do konfiguracji WEB-INF/web.xml następująco:

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

Alternatywnie, może być w stanie po prostu przechwycić odpowiedź w kliencie:

function consumesCity(json) { 
    ... 
} 

Wymień

... consumesCity(json) ... 

z

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

... consumesCity(preprocess(json)) ... 
+1

Dziękuję, Kim. Ale nadal będę szukał przenośnego rozwiązania. –

+3

Mam wrażenie, że to konkretne zachowanie jest specyficzne dla dostawcy, tj. Czy obiekt JSON najwyższego poziomu dla typu zwracanego kolekcji będzie tablicą lub pojedynczym obiektem z polem zawierającym elementy kolekcji. Byłem trochę przerażony, widząc, że implementacja referencyjna Glassfish zwraca ten drugi styl do kolekcji. Myślę, że zwracanie tablicy JSON jest znacznie bardziej intuicyjne. Opublikuj aktualizację, jeśli znajdziesz lepsze rozwiązanie. –

+1

Zgadzam się z Kim.Chociaż struktury rzeczywiście różnią się - głównie z przyczyn historycznych, a konkretnie dlatego, że istnieją biblioteki obsługujące JSON za pośrednictwem interfejsów API XML, które czasami wymuszają korzystanie z wrapperów - nie ma bardziej standardowego sposobu, chyba że chcesz użyć niestandardowego Implementacje MessageBodyWriter/Reader. – StaxMan

1

Dobre pytanie. Mam podobny wymóg. Musiałem mieć dostęp do wygenerowanej nieprzetworzonej odpowiedzi i wykonać jakąś manipulację. Osiągnąłem to poprzez zarejestrowanie filtra resonse, a następnie zaadaptowanie niestandardowego reponsewritera. Zobacz link poniżej, aby uzyskać więcej informacji.

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

w filtrze odpowiedzi, można clip się nazwę klasy z wygenerowanym json, albo jeszcze lepiej, powrót String w odpowiedzi i użyć niestandardowego json mechanizm serializacji jak Google-gson.

Daj mi znać, jeśli to rozwiązanie działa.

0

Odpowiedź od Kim Burgaard powyżej również dotyczy Jersey Spring WS. Miałem ten sam problem używając Glassfish 3.0 i rozwiązałem go, dodając parametr pokazany poniżej.

Przykład 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> 

Przykład 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>