Jax-rs json pretty output
Asked Answered
S

7

16

in Java when i use the

@Produces("application/json")

annotation the output is not formated into human readable form. How do i achive that?

Stannary answered 10/5, 2012 at 10:34 Comment(4)
what json-serializer are you using?Tauten
Just using the netbeans standard. Created with the wizard "new RESTful Webservices from Entity Classes" I am new to it, but I think it is jackson?Stannary
so the question is where can i change the output format in netbeans. i found some information googling. but it is just about ObjectMapper. Netbeans hides all that. Which class do i have to extend or Method to override? And how do I make it work then?Stannary
Which server r u using and why do you want to use pretty print?Misapprehend
B
24

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();
}
Bum answered 21/8, 2014 at 8:35 Comment(1)
@JacksonFeatures is only available on a method, not a class.Dieball
R
17

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.

Racemic answered 18/9, 2015 at 10:16 Comment(1)
This is the best solution by far, I wish I could upvote twice. Do not forget to use register(PrettyFilter.class) in your ResourceConfig.Russi
M
16

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.

Misapprehend answered 10/5, 2012 at 13:8 Comment(2)
How does Jersey know to use this context resolver, rather than the JAXRS provider that is builtin to Jackson?Loo
with the annotation @ProviderMisapprehend
U
3

If you are using Spring, then you can globally set the property

spring.jackson.serialization.INDENT_OUTPUT=true

More info at https://docs.spring.io/spring-boot/docs/current/reference/html/howto-properties-and-configuration.html

Unlovely answered 28/2, 2017 at 23:10 Comment(0)
C
2

Building on helpful DaTroop's answer, here is another version which allows choosing between optimized json and formatted json based on the absence or presence of a "pretty" parameter :

package test;


import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;

import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;

@Provider
@Produces(MediaType.APPLICATION_JSON)
public class JacksonContextResolver implements ContextResolver<ObjectMapper> {

    private ObjectMapper prettyPrintObjectMapper;
    private UriInfo uriInfoContext;

    public JacksonContextResolver(@Context UriInfo uriInfoContext) throws Exception {
        this.uriInfoContext = uriInfoContext;

        this.prettyPrintObjectMapper = new ObjectMapper();
        this.prettyPrintObjectMapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true);
    }

    @Override
    public ObjectMapper getContext(Class<?> objectType) {

        try {
            MultivaluedMap<String, String> queryParameters = uriInfoContext.getQueryParameters();
            if(queryParameters.containsKey("pretty")) {
                return prettyPrintObjectMapper;
            }

        } catch(Exception e) {
            // protect from invalid access to uriInfoContext.getQueryParameters()
        }

        return null; // use default mapper
    }
}
Cimex answered 23/4, 2015 at 14:11 Comment(1)
While this is a good solution - it only works the first time a resource is called. After that, the provider has been registered and you are stuck with pretty print (or not). For real flexibility, choose a Filter solution.Russi
M
1

If you are using the jersey-media-json-binding dependency, which uses Yasson (the official RI of JSR-367) and JAVAX-JSON, you can introduce pretty printing as follows:

import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
import javax.json.bind.JsonbConfig;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;

@Provider
public class RandomConfig implements ContextResolver<Jsonb> {
    private final Jsonb jsonb = JsonbBuilder.create(new JsonbConfig().withFormatting(true));

    public RandomConfig() { }

    @Override
    public Jsonb getContext(Class<?> objectType) {
        return jsonb;
    }
}
Miraculous answered 30/8, 2019 at 8:26 Comment(1)
This question was asked many years ago, and this is currently the best out-of-the-box way to do it. I'd add that you can condition the prettiness on a URL query parameter by accepting a @Context UriInfo uriInfo in the constructor and returning a different Jsonb instance depending on the uriInfo properties.Valediction
C
0

Alternative for Jersey 1.x:

org.codehaus.jackson.map.ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationConfig.Feature.INDENT_OUTPUT);
Cymbiform answered 25/6, 2021 at 23:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.