2012-04-14 20 views
6

Wiem o możliwości włączenia formatowania przy użyciu programu Marshaller. Ale używam Apache CXF (JAX-RS) i zwracam odpowiedź jak return Response.ok(entity).build();.Sformatowane wyjście XML w CXF?

Nie znalazłem żadnej opcji, jak sformatować dane wyjściowe. Jak mogę to zrobić?

Odpowiedz

10

Po pierwsze, sposobem na sformatowanie danych wyjściowych XML jest ustawienie właściwej właściwości na urządzeniu Marshaller (zwykle JAXB podczas pracy z CXF, co jest w porządku, ponieważ JAXB wykonuje dobrą pracę). Oznacza to, że gdzieś idziesz mieć coś w ten sposób:

marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 

Problemem jest to, że nie koniecznie chcą mieć wszystko wyjście sformatowane; dodaje trochę do kosztów ogólnych. Na szczęście, jesteś już wytwarzania wyraźny Response, więc możemy po prostu użyć więcej cech, które:

Marshaller marshaller = JAXBContext.newInstance(entity.getClass()).createMarshaller(); 
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 
StringWriter sw = new StringWriter(); 
marshaller.marshal(entity, sw); 

return Response.ok(sw.toString(), MediaType.APPLICATION_XML_TYPE).build(); 

Inną metodą jest wymieniona w this JIRA issue (sama zamknięta, ale to nie jest tak wiele kwestii do ty):

Rozwiązaniem jest zarejestrowanie klasę obsługi wyjściowy, który może sprawdzić, co niestandardowe zapytania służy do żądania dodatkowego wcięcia:

http://svn.apache.org/repos/asf/cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/FormatResponseHandler.java

JAXBElementProvider i JSONProvider są obsługiwane przez program JAXB Marshaller, dlatego domyślnie sprawdzają właściwość Marshaller.JAXB_FORMATTED_OUTPUT w bieżącej wiadomości.

Prowadzi to do kodu tak:

public class FormattedJAXBInterceptor extends AbstractPhaseInterceptor<Message> { 
    public FormattedJAXBInterceptor() { 
     super(Phase.PRE_STREAM); 
    } 

    public void handleMessage(Message message) { 
     message.put(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); 
    } 

    public void handleFault(Message messageParam) { 
     message.put(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); 
    } 
} 

CXF witryny discusses registration of interceptors.

+0

Napisałem powyżej, że wiedziałem o tej opcji. Chciałem tego uniknąć, ponieważ przekazanie jednostki do 'Response.ok (entity)' powoduje automatyczne ustawienie. Czy mówisz, że ten ręczny fragment kodu jest jedynym sposobem wymuszenia formatowania i nie ma sposobu, aby przekazać to do ResponseBuilder? – user219882

+0

Możesz spróbować zarejestrować komponent bean "MessageBodyWriter ", który koduje powyższą lukę. Następnie możesz po prostu zwrócić 'Cokolwiek', tak jak w przypadku standardowej serializacji. Nigdy nie byłem zbyt zainteresowany robieniem tego dla generowania XML (zbyt blisko domyślnego silnika serializacji), ale może w tym przypadku zadziałać.Możliwym wadą jest to, że * wszystkie * zwrócone wartości tego typu będą serializowane w ten sposób (chyba że dodasz pewne kluczowanie do niestandardowej adnotacji, przypuszczam) ... –

+0

Zobacz także http: //cxf.547215.n5.nabble. com/Formatting-binding-output-Json-amp-Xml-td565786.html, ale nie wiem, jak istotne jest to dla CXF 2.5 ... –

1

Można wdrożyć MessageBodyWriter. Jest to mechanizm JAX-RS, który pozwala przesłonić sposób, w jaki obiekt jest kierowany do formatu XML.

package org.example; 

import java.io.*; 
import java.lang.annotation.Annotation; 
import java.lang.reflect.*; 

import javax.ws.rs.*; 
import javax.ws.rs.core.*; 
import javax.ws.rs.ext.*; 
import javax.xml.bind.*; 

@Provider 
@Produces(MediaType.APPLICATION_XML) 
public class FormattingWriter implements MessageBodyWriter<Object>{ 

    @Context 
    protected Providers providers; 

    public boolean isWriteable(Class<?> type, Type genericType, 
     Annotation[] annotations, MediaType mediaType) { 
     return true; 
    } 

    public void writeTo(Object object, Class<?> type, Type genericType, 
     Annotation[] annotations, MediaType mediaType, 
     MultivaluedMap<String, Object> httpHeaders, 
     OutputStream entityStream) throws IOException, 
     WebApplicationException { 
     try { 
      ContextResolver<JAXBContext> resolver 
       = providers.getContextResolver(JAXBContext.class, mediaType); 
      JAXBContext jaxbContext; 
      if(null == resolver || null == (jaxbContext = resolver.getContext(type))) { 
       jaxbContext = JAXBContext.newInstance(type); 
      } 
      Marshaller m = jaxbContext.createMarshaller(); 
      m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 
      m.marshal(object, entityStream); 
     } catch(JAXBException jaxbException) { 
      throw new WebApplicationException(jaxbException); 
     } 
    } 

    public long getSize(Object t, Class<?> type, Type genericType, 
     Annotation[] annotations, MediaType mediaType) { 
     return -1; 
    } 

} 

Aby uzyskać więcej informacji

Poniżej znajduje się link do kompletnego przykład gdzie MessageBodyWriter jest używany jako część usługi JAX-RS.

+0

To [nie zadziała] (http://cxf.apache.org/docs/jax-rs-basics.html#JAX-RSBasics-Registeringcustomproviders) jak napisano z CXF, z subtelnych powodów. Musisz ręcznie zarejestrować dostawców z komponentem bean serwera. Jest to przydatne, jeśli chcesz mieć różne strategie serializacji dla różnych części aplikacji webapp, co okazuje się być * bardzo * dobrą rzeczą! (Miałem aplikację, która chciała serializować POJO do XML na kilka różnych sposobów - czasami zwykły, czasem z dodatkowymi elementami opakowania - i była w stanie podzielić strategię serializacji według głównego zasobu, dzięki czemu działała.) –

Powiązane problemy