Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When using Spring MVC for REST, how do you enable Jackson to pretty-print rendered JSON?

While developing REST services using Spring MVC, I would like render JSON 'pretty printed' in development but normal (reduced whitespace) in production.

like image 289
Les Hazlewood Avatar asked Jun 30 '11 22:06

Les Hazlewood


People also ask

How do I enable pretty print JSON?

If you only need to pretty print a JSON string, you can use Object instead of creating an application POJO. The code to do so is this. Object object = objectMapper. readValue(jsonString, Object.

Does spring REST use Jackson?

Spring Framework and Spring Boot provide builtin support for Jackson based XML serialization/deserialization. As soon as you include the jackson-dataformat-xml dependency to your project, it is automatically used instead of JAXB2.

Can we make REST API using Spring MVC?

The REST API support was introduced in Spring from version 3.0 onwards; since then, it has steadily evolved to the present day. We can create REST resources in the following ways: Using controllers which are used to handle HTTP requests such as GET, POST, PUT, and so forth.

Does spring boot have Jackson ObjectMapper?

Overview. When using JSON format, Spring Boot will use an ObjectMapper instance to serialize responses and deserialize requests. In this tutorial, we'll take a look at the most common ways to configure the serialization and deserialization options. To learn more about Jackson, be sure to check out our Jackson tutorial.


2 Answers

I had an answer when I posted this question, but I thought I'd post it anyway in case there are better alternative solutions. Here was my experience:

First thing's first. The MappingJacksonHttpMessageConverter expects you to inject a Jackson ObjectMapper instance and perform Jackson configuration on that instance (and not through a Spring class).

I thought it would be as easy as doing this:

Create an ObjectMapperFactoryBean implementation that allows me to customize the ObjectMapper instance that can be injected into the MappingJacksonHttpMessageConverter. For example:

<bean id="jacksonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">     <property name="objectMapper">         <bean class="com.foo.my.ObjectMapperFactoryBean">             <property name="prettyPrint" value="${json.prettyPrint}"/>         </bean>     </property> </bean> 

And then, in my ObjectMapperFactoryBean implementation, I could do this (as has been documented as a solution elsewhere on SO):

ObjectMapper mapper = new ObjectMapper(); mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, isPrettyPrint()); return mapper; 

But it didn't work. And trying to figure out why is a nightmare. It is a major test of patience to figure Jackson out. Looking at its source code only confuses you further as it uses outdated and obtuse forms of configuration (integer bitmasks for turning on/off features? Are you kidding me?)

I essentially had to re-write Spring's MappingJacksonHttpMessageConverter from scratch, and override its writeInternal implementation to be the following:

@Override protected void writeInternal(Object o, HttpOutputMessage outputMessage)         throws IOException, HttpMessageNotWritableException {      JsonEncoding encoding = getEncoding(outputMessage.getHeaders().getContentType());     JsonGenerator jsonGenerator =             getObjectMapper().getJsonFactory().createJsonGenerator(outputMessage.getBody(), encoding);     try {         if (this.prefixJson) {             jsonGenerator.writeRaw("{} && ");         }         if (isPrettyPrint()) {             jsonGenerator.useDefaultPrettyPrinter();         }         getObjectMapper().writeValue(jsonGenerator, o);     }     catch (JsonGenerationException ex) {         throw new HttpMessageNotWritableException("Could not write JSON: " + ex.getMessage(), ex);     } } 

The only thing I added to the existing implementation is the following block:

if (isPrettyPrint()) {     jsonGenerator.useDefaultPrettyPrinter(); } 

isPrettyPrint() is just a JavaBeans compatible getter w/ matching setter that I added to my MappingJacksonHttpMessageConverter subclass.

Only after jumping through these hoops was I able to turn on or off pretty printing based on my ${json.prettyPrint} value (that is set as a property depending on how the app is deployed).

I hope this helps someone out in the future!

like image 23
Les Hazlewood Avatar answered Sep 19 '22 21:09

Les Hazlewood


If you are using Spring Boot 1.2 or later the simple solution is to add

spring.jackson.serialization.INDENT_OUTPUT=true 

to the application.properties file. This assumes that you are using Jackson for serialization.

If you are using an earlier version of Spring Boot then you can add

http.mappers.json-pretty-print=true 

This solution still works with Spring Boot 1.2 but it is deprecated and will eventually be removed entirely. You will get a deprecation warning in the log at startup time.

(tested using spring-boot-starter-web)

like image 59
user4061342 Avatar answered Sep 23 '22 21:09

user4061342