Jax-rs json pretty output

This is how you can properly do conditional pretty/non-pretty json output based on presence of "pretty" in query string.

Create a PrettyFilter that implements ContainerResponseFilter, that will be executed on every request:

@Provider
public class PrettyFilter implements ContainerResponseFilter {

    @Override
    public void filter(ContainerRequestContext reqCtx, ContainerResponseContext respCtx) throws IOException {

        UriInfo uriInfo = reqCtx.getUriInfo();
        //log.info("prettyFilter: "+uriInfo.getPath());

        MultivaluedMap<String, String> queryParameters = uriInfo.getQueryParameters();
        if(queryParameters.containsKey("pretty")) {
            ObjectWriterInjector.set(new IndentingModifier(true));
        }

    }

    public static class IndentingModifier extends ObjectWriterModifier {

        private final boolean indent;

        public IndentingModifier(boolean indent) {
            this.indent = indent;
        }


        @Override
        public ObjectWriter modify(EndpointConfigBase<?> endpointConfigBase, MultivaluedMap<String, Object> multivaluedMap, Object o, ObjectWriter objectWriter, JsonGenerator jsonGenerator) throws IOException {
            if(indent) jsonGenerator.useDefaultPrettyPrinter();
            return objectWriter;
        }
    }
}

And pretty much that's it!

You will need to ensure that this class gets used by Jersey by either automated package scanning or registered manually.

Spent few hours trying to achieve that and found that no-one has published a ready-to-use solution before.


Create this class anywhere in your project. It will be loaded on deployment. Notice the .configure(SerializationConfig.Feature.INDENT_OUTPUT, true); which configures the mapper to format the output.

For Jackson 2.0 and later, replace the two .configure() lines with these: .configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, false) .configure(SerializationFeature.INDENT_OUTPUT, true);

And change your imports accordingly.

package com.secret;

import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;
import org.codehaus.jackson.map.DeserializationConfig;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;

/**
 *
 * @author secret
 */
@Provider
@Produces(MediaType.APPLICATION_JSON)
public class JacksonContextResolver implements ContextResolver<ObjectMapper> {
    private ObjectMapper objectMapper;

    public JacksonContextResolver() throws Exception {
        this.objectMapper = new ObjectMapper();
    this.objectMapper
        .configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false)
        .configure(SerializationConfig.Feature.INDENT_OUTPUT, true);
    }

    @Override
    public ObjectMapper getContext(Class<?> objectType) {
        return objectMapper;
    }
}

Bear in mind that formatting has a negative effect on performance.


Just for the record, if you want to enable the pretty output only for some resources you can use the @JacksonFeatures annotation on a resource method.

Here is example:

@Produces(MediaType.APPLICATION_JSON)
@JacksonFeatures(serializationEnable =  { SerializationFeature.INDENT_OUTPUT })
public Bean resource() {
    return new Bean();
}