Add support for Jackson serialization views

Spring MVC now supports Jackon's serialization views for rendering
different subsets of the same POJO from different controller
methods (e.g. detailed page vs summary view).

Issue: SPR-7156
This commit is contained in:
Sebastien Deleuze
2014-05-12 17:05:35 -04:00
committed by Rossen Stoyanchev
parent 673a497923
commit be0b69cbf1
15 changed files with 610 additions and 16 deletions

View File

@@ -29,6 +29,7 @@ import org.springframework.core.MethodParameter;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.MethodParameterHttpMessageConverter;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.util.CollectionUtils;
@@ -139,6 +140,17 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
if (selectedMediaType != null) {
selectedMediaType = selectedMediaType.removeQualityValue();
for (HttpMessageConverter<?> messageConverter : this.messageConverters) {
if (messageConverter instanceof MethodParameterHttpMessageConverter) {
MethodParameterHttpMessageConverter<T> c = (MethodParameterHttpMessageConverter<T>) messageConverter;
if (c.canWrite(returnValueClass, selectedMediaType, returnType)) {
c.write(returnValue, selectedMediaType, outputMessage, returnType);
if (logger.isDebugEnabled()) {
logger.debug("Written [" + returnValue + "] as \"" + selectedMediaType + "\" using [" +
messageConverter + "]");
}
return;
}
}
if (messageConverter.canWrite(returnValueClass, selectedMediaType)) {
((HttpMessageConverter<T>) messageConverter).write(returnValue, selectedMediaType, outputMessage);
if (logger.isDebugEnabled()) {

View File

@@ -26,6 +26,7 @@ import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.fasterxml.jackson.annotation.JsonView;
import com.fasterxml.jackson.core.JsonEncoding;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -253,7 +254,12 @@ public class MappingJackson2JsonView extends AbstractView {
OutputStream stream = (this.updateContentLength ? createTemporaryOutputStream() : response.getOutputStream());
Object value = filterModel(model);
writeContent(stream, value, this.jsonPrefix);
if (model.containsKey(JsonView.class.getName())) {
writeContent(stream, value, this.jsonPrefix, model);
}
else {
writeContent(stream, value, this.jsonPrefix);
}
if (this.updateContentLength) {
writeToResponse(response, (ByteArrayOutputStream) stream);
}
@@ -287,6 +293,12 @@ public class MappingJackson2JsonView extends AbstractView {
* @throws IOException if writing failed
*/
protected void writeContent(OutputStream stream, Object value, String jsonPrefix) throws IOException {
writeContent(stream, value, jsonPrefix, Collections.<String, Object>emptyMap());
}
protected void writeContent(OutputStream stream, Object value, String jsonPrefix, Map<String, Object> model)
throws IOException {
// 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")
@@ -301,7 +313,14 @@ public class MappingJackson2JsonView extends AbstractView {
if (jsonPrefix != null) {
generator.writeRaw(jsonPrefix);
}
this.objectMapper.writeValue(generator, value);
Class<?> serializationView = (Class<?>) model.get(JsonView.class.getName());
if (serializationView != null) {
this.objectMapper.writerWithView(serializationView).writeValue(generator, value);
}
else {
this.objectMapper.writeValue(generator, value);
}
}
}
}