Formatted XML output in CXF?

I know about the ability to enable formatting when using Marshaller. But I use Apache CXF (JAX-RS) and return a response like return Response.ok(entity).build(); .

I did not find any way to format the output. How can i do this?

+6
source share
2 answers

First, the way to get formatted XML output is to set the correct property on the marshaller (usually JAXB when working with CXF, which is good since JAXB does a commendable job). That is, somewhere you will have something like this:

 marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 

The problem is that you do not necessarily want the entire output format to be formatted; this adds quite a bit to the overhead. Fortunately, you are already creating an explicit Response , so we can simply use more features of this:

 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(); 

Another method is mentioned in this JIRA issue (itself is closed, but for you it is not much):

The workaround is to register a custom output handler that can check which user request is used to request an optional indent:

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

JAXBElementProvider and JSONProvider are controlled by the JAXB marshaller, so by default they check the Marshaller.JAXB_FORMATTED_OUTPUT property on the current message.

This leads to the following code:

 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); } } 

The CXF website discusses registration of interceptors .

+10
source

You can implement MessageBodyWriter . This is a JAX-RS engine that allows you to override the way an object is mapped to 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; } } 

Additional Information

Below is a link to a complete example where MessageBodyWriter used as part of the JAX-RS service.

+1
source

Source: https://habr.com/ru/post/913196/


All Articles