Pretty print option for Jackson converter and view

Jackson serialization supports pretty printing. Usually it's enabled
by invoking ObjectMapper.configure(..), which is not convenient for
apps with XML configuration. The Jackson HttpMessageConverter and View
now both have a prettyPrint property.

A second more serious issue is documented here:
https://github.com/FasterXML/jackson-databind/issues/12

The workaround discussed at the above link has been implemented.

Issue: SPR-7201
This commit is contained in:
Rossen Stoyanchev
2012-05-09 16:29:22 -04:00
parent 6a162d488a
commit db289495e5
9 changed files with 510 additions and 180 deletions

View File

@@ -25,7 +25,9 @@ import javax.servlet.http.HttpServletResponse;
import com.fasterxml.jackson.core.JsonEncoding;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
@@ -61,6 +63,8 @@ public class MappingJackson2JsonView extends AbstractView {
private boolean prefixJson = false;
private Boolean prettyPrint;
private Set<String> modelKeys;
private boolean extractValueFromSingleKeyModel = false;
@@ -89,6 +93,13 @@ public class MappingJackson2JsonView extends AbstractView {
public void setObjectMapper(ObjectMapper objectMapper) {
Assert.notNull(objectMapper, "'objectMapper' must not be null");
this.objectMapper = objectMapper;
configurePrettyPrint();
}
private void configurePrettyPrint() {
if (this.prettyPrint != null) {
this.objectMapper.configure(SerializationFeature.INDENT_OUTPUT, this.prettyPrint);
}
}
/**
@@ -112,6 +123,21 @@ public class MappingJackson2JsonView extends AbstractView {
this.prefixJson = prefixJson;
}
/**
* Whether to use the {@link DefaultPrettyPrinter} when writing JSON.
* This is a shortcut for setting up an {@code ObjectMapper} as follows:
* <pre>
* ObjectMapper mapper = new ObjectMapper();
* mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
* converter.setObjectMapper(mapper);
* </pre>
* <p>The default value is {@code false}.
*/
public void setPrettyPrint(boolean prettyPrint) {
this.prettyPrint = prettyPrint;
configurePrettyPrint();
}
/**
* Set the attribute in the model that should be rendered by this view.
* When set, all other model attributes will be ignored.
@@ -192,6 +218,13 @@ public class MappingJackson2JsonView extends AbstractView {
Object value = filterModel(model);
JsonGenerator generator =
this.objectMapper.getJsonFactory().createJsonGenerator(response.getOutputStream(), this.encoding);
// A workaround for JsonGenerators not applying serialization features
// https://github.com/FasterXML/jackson-databind/issues/12
if (this.objectMapper.isEnabled(SerializationFeature.INDENT_OUTPUT)) {
generator.useDefaultPrettyPrinter();
}
if (this.prefixJson) {
generator.writeRaw("{} && ");
}

View File

@@ -20,20 +20,23 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.codehaus.jackson.JsonEncoding;
import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;
import org.codehaus.jackson.map.SerializerFactory;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.BindingResult;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.view.AbstractView;
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
/**
* Spring MVC {@link View} that renders JSON content by serializing the model for the current request
* using <a href="http://jackson.codehaus.org/">Jackson's</a> {@link ObjectMapper}.
@@ -62,12 +65,14 @@ public class MappingJacksonJsonView extends AbstractView {
private boolean prefixJson = false;
private Boolean prettyPrint;
private Set<String> modelKeys;
private boolean extractValueFromSingleKeyModel = false;
private boolean disableCaching = true;
/**
* Construct a new {@code JacksonJsonView}, setting the content type to {@code application/json}.
@@ -90,6 +95,13 @@ public class MappingJacksonJsonView extends AbstractView {
public void setObjectMapper(ObjectMapper objectMapper) {
Assert.notNull(objectMapper, "'objectMapper' must not be null");
this.objectMapper = objectMapper;
configurePrettyPrint();
}
private void configurePrettyPrint() {
if (this.prettyPrint != null) {
this.objectMapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, this.prettyPrint);
}
}
/**
@@ -113,6 +125,21 @@ public class MappingJacksonJsonView extends AbstractView {
this.prefixJson = prefixJson;
}
/**
* Whether to use the {@link DefaultPrettyPrinter} when writing JSON.
* This is a shortcut for setting up an {@code ObjectMapper} as follows:
* <pre>
* ObjectMapper mapper = new ObjectMapper();
* mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true);
* converter.setObjectMapper(mapper);
* </pre>
* <p>The default value is {@code false}.
*/
public void setPrettyPrint(boolean prettyPrint) {
this.prettyPrint = prettyPrint;
configurePrettyPrint();
}
/**
* Set the attribute in the model that should be rendered by this view.
* When set, all other model attributes will be ignored.
@@ -120,7 +147,7 @@ public class MappingJacksonJsonView extends AbstractView {
public void setModelKey(String modelKey) {
this.modelKeys = Collections.singleton(modelKey);
}
/**
* Set the attributes in the model that should be rendered by this view.
* When set, all other model attributes will be ignored.
@@ -193,6 +220,13 @@ public class MappingJacksonJsonView extends AbstractView {
Object value = filterModel(model);
JsonGenerator generator =
this.objectMapper.getJsonFactory().createJsonGenerator(response.getOutputStream(), this.encoding);
// A workaround for JsonGenerators not applying serialization features
// https://github.com/FasterXML/jackson-databind/issues/12
if (this.objectMapper.getSerializationConfig().isEnabled(SerializationConfig.Feature.INDENT_OUTPUT)) {
generator.useDefaultPrettyPrinter();
}
if (this.prefixJson) {
generator.writeRaw("{} && ");
}