MappingJackson2JsonView/MessageConverter calls non-deprecated Jackson 2.1+ createGenerator API
Also removing workaround for https://github.com/FasterXML/jackson-databind/issues/12 (fixed in 2.1+) Issue: SPR-11262
This commit is contained in:
parent
a6a86b8025
commit
777085bbfc
|
@ -39,7 +39,7 @@ import org.springframework.util.MimeType;
|
||||||
/**
|
/**
|
||||||
* A Jackson 2 based {@link MessageConverter} implementation.
|
* A Jackson 2 based {@link MessageConverter} implementation.
|
||||||
*
|
*
|
||||||
* <p>Tested against Jackson 2.2 and 2.3; compatible with Jackson 2.0 and higher.
|
* <p>Compatible with Jackson 2.1 and higher.
|
||||||
*
|
*
|
||||||
* @author Rossen Stoyanchev
|
* @author Rossen Stoyanchev
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
|
@ -183,18 +183,7 @@ public class MappingJackson2MessageConverter extends AbstractMessageConverter {
|
||||||
if (byte[].class.equals(getSerializedPayloadClass())) {
|
if (byte[].class.equals(getSerializedPayloadClass())) {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
|
ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
|
||||||
JsonEncoding encoding = getJsonEncoding(getMimeType(headers));
|
JsonEncoding encoding = getJsonEncoding(getMimeType(headers));
|
||||||
|
JsonGenerator generator = this.objectMapper.getFactory().createGenerator(out, encoding);
|
||||||
// The following has been deprecated as late as Jackson 2.2 (April 2013);
|
|
||||||
// preserved for the time being, for Jackson 2.0/2.1 compatibility.
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
JsonGenerator generator = this.objectMapper.getJsonFactory().createJsonGenerator(out, 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();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.objectMapper.writeValue(generator, payload);
|
this.objectMapper.writeValue(generator, payload);
|
||||||
payload = out.toByteArray();
|
payload = out.toByteArray();
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,7 @@ import org.springframework.util.ClassUtils;
|
||||||
* <p>By default, this converter supports {@code application/json}. This can be overridden by setting the
|
* <p>By default, this converter supports {@code application/json}. This can be overridden by setting the
|
||||||
* {@link #setSupportedMediaTypes supportedMediaTypes} property.
|
* {@link #setSupportedMediaTypes supportedMediaTypes} property.
|
||||||
*
|
*
|
||||||
* <p>Tested against Jackson 2.2 and 2.3; compatible with Jackson 2.0 and higher.
|
* <p>Compatible with Jackson 2.1 and higher.
|
||||||
*
|
*
|
||||||
* @author Arjen Poutsma
|
* @author Arjen Poutsma
|
||||||
* @author Keith Donald
|
* @author Keith Donald
|
||||||
|
@ -233,21 +233,10 @@ public class MappingJackson2HttpMessageConverter extends AbstractHttpMessageConv
|
||||||
throws IOException, HttpMessageNotWritableException {
|
throws IOException, HttpMessageNotWritableException {
|
||||||
|
|
||||||
JsonEncoding encoding = getJsonEncoding(outputMessage.getHeaders().getContentType());
|
JsonEncoding encoding = getJsonEncoding(outputMessage.getHeaders().getContentType());
|
||||||
// The following has been deprecated as late as Jackson 2.2 (April 2013);
|
JsonGenerator generator = this.objectMapper.getFactory().createGenerator(outputMessage.getBody(), encoding);
|
||||||
// preserved for the time being, for Jackson 2.0/2.1 compatibility.
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
JsonGenerator jsonGenerator =
|
|
||||||
this.objectMapper.getJsonFactory().createJsonGenerator(outputMessage.getBody(), encoding);
|
|
||||||
|
|
||||||
// A workaround for JsonGenerators not applying serialization features
|
|
||||||
// https://github.com/FasterXML/jackson-databind/issues/12
|
|
||||||
if (this.objectMapper.isEnabled(SerializationFeature.INDENT_OUTPUT)) {
|
|
||||||
jsonGenerator.useDefaultPrettyPrinter();
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (this.jsonPrefix != null) {
|
if (this.jsonPrefix != null) {
|
||||||
jsonGenerator.writeRaw(this.jsonPrefix);
|
generator.writeRaw(this.jsonPrefix);
|
||||||
}
|
}
|
||||||
Class<?> serializationView = null;
|
Class<?> serializationView = null;
|
||||||
String jsonpFunction = null;
|
String jsonpFunction = null;
|
||||||
|
@ -258,17 +247,17 @@ public class MappingJackson2HttpMessageConverter extends AbstractHttpMessageConv
|
||||||
jsonpFunction = container.getJsonpFunction();
|
jsonpFunction = container.getJsonpFunction();
|
||||||
}
|
}
|
||||||
if (jsonpFunction != null) {
|
if (jsonpFunction != null) {
|
||||||
jsonGenerator.writeRaw(jsonpFunction + "(" );
|
generator.writeRaw(jsonpFunction + "(");
|
||||||
}
|
}
|
||||||
if (serializationView != null) {
|
if (serializationView != null) {
|
||||||
this.objectMapper.writerWithView(serializationView).writeValue(jsonGenerator, object);
|
this.objectMapper.writerWithView(serializationView).writeValue(generator, object);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.objectMapper.writeValue(jsonGenerator, object);
|
this.objectMapper.writeValue(generator, object);
|
||||||
}
|
}
|
||||||
if (jsonpFunction != null) {
|
if (jsonpFunction != null) {
|
||||||
jsonGenerator.writeRaw(");");
|
generator.writeRaw(");");
|
||||||
jsonGenerator.flush();
|
generator.flush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (JsonProcessingException ex) {
|
catch (JsonProcessingException ex) {
|
||||||
|
|
|
@ -19,7 +19,12 @@ package org.springframework.web.servlet.view.json;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.*;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
@ -45,6 +50,8 @@ import org.springframework.web.servlet.view.AbstractView;
|
||||||
* will be encoded as JSON. If the model contains only one key, you can have it extracted encoded as JSON
|
* will be encoded as JSON. If the model contains only one key, you can have it extracted encoded as JSON
|
||||||
* alone via {@link #setExtractValueFromSingleKeyModel}.
|
* alone via {@link #setExtractValueFromSingleKeyModel}.
|
||||||
*
|
*
|
||||||
|
* <p>Compatible with Jackson 2.1 and higher.
|
||||||
|
*
|
||||||
* @author Jeremy Grelle
|
* @author Jeremy Grelle
|
||||||
* @author Arjen Poutsma
|
* @author Arjen Poutsma
|
||||||
* @author Rossen Stoyanchev
|
* @author Rossen Stoyanchev
|
||||||
|
@ -60,6 +67,9 @@ public class MappingJackson2JsonView extends AbstractView {
|
||||||
*/
|
*/
|
||||||
public static final String DEFAULT_CONTENT_TYPE = "application/json";
|
public static final String DEFAULT_CONTENT_TYPE = "application/json";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default content type for JSONP: "application/javascript".
|
||||||
|
*/
|
||||||
public static final String DEFAULT_JSONP_CONTENT_TYPE = "application/javascript";
|
public static final String DEFAULT_JSONP_CONTENT_TYPE = "application/javascript";
|
||||||
|
|
||||||
|
|
||||||
|
@ -71,8 +81,6 @@ public class MappingJackson2JsonView extends AbstractView {
|
||||||
|
|
||||||
private Boolean prettyPrint;
|
private Boolean prettyPrint;
|
||||||
|
|
||||||
private final List<String> jsonpParameterNames = new ArrayList<String>(Arrays.asList("jsonp", "callback"));
|
|
||||||
|
|
||||||
private Set<String> modelKeys;
|
private Set<String> modelKeys;
|
||||||
|
|
||||||
private boolean extractValueFromSingleKeyModel = false;
|
private boolean extractValueFromSingleKeyModel = false;
|
||||||
|
@ -81,6 +89,8 @@ public class MappingJackson2JsonView extends AbstractView {
|
||||||
|
|
||||||
private boolean updateContentLength = false;
|
private boolean updateContentLength = false;
|
||||||
|
|
||||||
|
private Set<String> jsonpParameterNames = new LinkedHashSet<String>(Arrays.asList("jsonp", "callback"));
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new {@code MappingJackson2JsonView}, setting the content type to {@code application/json}.
|
* Construct a new {@code MappingJackson2JsonView}, setting the content type to {@code application/json}.
|
||||||
|
@ -169,23 +179,6 @@ public class MappingJackson2JsonView extends AbstractView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Set JSONP request parameter names. Each time a request has one of those
|
|
||||||
* parameters, the resulting JSON will be wrapped into a function named as
|
|
||||||
* specified by the JSONP request parameter value.
|
|
||||||
*
|
|
||||||
* <p>The parameter names configured by default are "jsonp" and "callback".
|
|
||||||
*
|
|
||||||
* @since 4.1
|
|
||||||
* @see <a href="http://en.wikipedia.org/wiki/JSONP">JSONP Wikipedia article</a>
|
|
||||||
*/
|
|
||||||
public void setJsonpParameterNames(Collection<String> jsonpParameters) {
|
|
||||||
this.jsonpParameterNames.clear();
|
|
||||||
if (jsonpParameters != null) {
|
|
||||||
this.jsonpParameterNames.addAll(jsonpParameters);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the attribute in the model that should be rendered by this view.
|
* Set the attribute in the model that should be rendered by this view.
|
||||||
* When set, all other model attributes will be ignored.
|
* When set, all other model attributes will be ignored.
|
||||||
|
@ -257,6 +250,19 @@ public class MappingJackson2JsonView extends AbstractView {
|
||||||
this.updateContentLength = updateContentLength;
|
this.updateContentLength = updateContentLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set JSONP request parameter names. Each time a request has one of those
|
||||||
|
* parameters, the resulting JSON will be wrapped into a function named as
|
||||||
|
* specified by the JSONP request parameter value.
|
||||||
|
* <p>The parameter names configured by default are "jsonp" and "callback".
|
||||||
|
* @since 4.1
|
||||||
|
* @see <a href="http://en.wikipedia.org/wiki/JSONP">JSONP Wikipedia article</a>
|
||||||
|
*/
|
||||||
|
public void setJsonpParameterNames(Set<String> jsonpParameterNames) {
|
||||||
|
this.jsonpParameterNames = jsonpParameterNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void prepareResponse(HttpServletRequest request, HttpServletResponse response) {
|
protected void prepareResponse(HttpServletRequest request, HttpServletResponse response) {
|
||||||
setResponseContentType(request, response);
|
setResponseContentType(request, response);
|
||||||
|
@ -291,10 +297,12 @@ public class MappingJackson2JsonView extends AbstractView {
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getJsonpParameterValue(HttpServletRequest request) {
|
private String getJsonpParameterValue(HttpServletRequest request) {
|
||||||
for(String name : this.jsonpParameterNames) {
|
if (this.jsonpParameterNames != null) {
|
||||||
String value = request.getParameter(name);
|
for (String name : this.jsonpParameterNames) {
|
||||||
if (!StringUtils.isEmpty(value)) {
|
String value = request.getParameter(name);
|
||||||
return value;
|
if (!StringUtils.isEmpty(value)) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -310,11 +318,10 @@ public class MappingJackson2JsonView extends AbstractView {
|
||||||
*/
|
*/
|
||||||
protected Object filterModel(Map<String, Object> model) {
|
protected Object filterModel(Map<String, Object> model) {
|
||||||
Map<String, Object> result = new HashMap<String, Object>(model.size());
|
Map<String, Object> result = new HashMap<String, Object>(model.size());
|
||||||
Set<String> renderedAttributes = (!CollectionUtils.isEmpty(this.modelKeys) ? this.modelKeys : model.keySet());
|
Set<String> modelKeys = (!CollectionUtils.isEmpty(this.modelKeys) ? this.modelKeys : model.keySet());
|
||||||
for (Map.Entry<String, Object> entry : model.entrySet()) {
|
for (Map.Entry<String, Object> entry : model.entrySet()) {
|
||||||
if (!(entry.getValue() instanceof BindingResult)
|
if (!(entry.getValue() instanceof BindingResult) && modelKeys.contains(entry.getKey()) &&
|
||||||
&& renderedAttributes.contains(entry.getKey())
|
!entry.getKey().equals(JsonView.class.getName())) {
|
||||||
&& !entry.getKey().equals(JsonView.class.getName())) {
|
|
||||||
result.put(entry.getKey(), entry.getValue());
|
result.put(entry.getKey(), entry.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -332,17 +339,7 @@ public class MappingJackson2JsonView extends AbstractView {
|
||||||
protected void writeContent(OutputStream stream, Object value, String jsonPrefix)
|
protected void writeContent(OutputStream stream, Object value, String jsonPrefix)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
|
|
||||||
// The following has been deprecated as late as Jackson 2.2 (April 2013);
|
JsonGenerator generator = this.objectMapper.getFactory().createGenerator(stream, this.encoding);
|
||||||
// preserved for the time being, for Jackson 2.0/2.1 compatibility.
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
JsonGenerator generator = this.objectMapper.getJsonFactory().createJsonGenerator(stream, 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 (jsonPrefix != null) {
|
if (jsonPrefix != null) {
|
||||||
generator.writeRaw(jsonPrefix);
|
generator.writeRaw(jsonPrefix);
|
||||||
}
|
}
|
||||||
|
@ -379,4 +376,4 @@ public class MappingJackson2JsonView extends AbstractView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -323,7 +323,7 @@ public class MappingJackson2JsonViewTests {
|
||||||
model.put("foo", "bar");
|
model.put("foo", "bar");
|
||||||
request.addParameter("otherparam", "value");
|
request.addParameter("otherparam", "value");
|
||||||
request.addParameter("custom", "jsonpCallback");
|
request.addParameter("custom", "jsonpCallback");
|
||||||
view.setJsonpParameterNames(Arrays.asList("jsonp", "callback", "custom"));
|
view.setJsonpParameterNames(new LinkedHashSet(Arrays.asList("jsonp", "callback", "custom")));
|
||||||
|
|
||||||
view.render(model, request, response);
|
view.render(model, request, response);
|
||||||
|
|
||||||
|
@ -338,8 +338,14 @@ public class MappingJackson2JsonViewTests {
|
||||||
assertEquals("application/json", response.getContentType());
|
assertEquals("application/json", response.getContentType());
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface MyJacksonView1 {};
|
|
||||||
public interface MyJacksonView2 {};
|
public interface MyJacksonView1 {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public interface MyJacksonView2 {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static class TestBeanSimple {
|
public static class TestBeanSimple {
|
||||||
|
@ -378,7 +384,6 @@ public class MappingJackson2JsonViewTests {
|
||||||
|
|
||||||
@JsonSerialize(using=TestBeanSimpleSerializer.class)
|
@JsonSerialize(using=TestBeanSimpleSerializer.class)
|
||||||
public static class TestBeanSimpleAnnotated extends TestBeanSimple {
|
public static class TestBeanSimpleAnnotated extends TestBeanSimple {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue