I know about the possibility how to turn on the formatting when using Marshaller. But I'm using Apache CXF (JAX-RS) and returning a response like return Response.ok(entity).build();
.
I haven't found any option how to format the output. How can I do it?
First off, the way to get formatted output of XML is to set the right property on the marshaller (typically JAXB when working with CXF, which is OK since JAXB does a creditable job). That is, somewhere you're going to have something doing this:
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
The issue is that you don't necessarily want to have all output formatted; it adds quite a bit to the overhead. Luckily, you're already producing an explicit Response
, so we can just use more features of that:
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 closed, but that's not so much of an issue for you):
The workaround is to register a custom output handler which can check whatever custom query is used to request the optional indentation:
http://svn.apache.org/repos/asf/cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/FormatResponseHandler.java
JAXBElementProvider and JSONProvider are driven by the JAXB Marshaller so by default they check a Marshaller.JAXB_FORMATTED_OUTPUT property on the current message.
This leads to code like this:
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 message) {
message.put(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
}
}
The CXF site discusses registration of interceptors.
You could implement a MessageBodyWriter
. This is a JAX-RS mechanism that allows you to override how an object is marshalled 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;
}
}
For More Information
Below is a link to a complete example where a MessageBodyWriter
is used as part of a JAX-RS service.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With