From 8f5dc17ebc53dbfd729da89f58c9e3865a6f6117 Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Fri, 4 Mar 2011 14:19:14 +0000 Subject: [PATCH] SPR-6932 Add option to extract value from single-key models in MappingJacksonJsonView git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@4058 50f2f4bb-b051-0410-bef5-90022cba6387 --- .../view/json/MappingJacksonJsonView.java | 20 +++++++++++-- .../view/json/MappingJacksonJsonViewTest.java | 30 +++++++++++++++++++ spring-framework-reference/src/view.xml | 4 ++- 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/view/json/MappingJacksonJsonView.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/view/json/MappingJacksonJsonView.java index c06ba11478e..c74ea2ba9dc 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/view/json/MappingJacksonJsonView.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/view/json/MappingJacksonJsonView.java @@ -43,6 +43,7 @@ import org.springframework.web.servlet.view.AbstractView; * * @author Jeremy Grelle * @author Arjen Poutsma + * @author Rossen Stoyanchev * @see org.springframework.http.converter.json.MappingJacksonHttpMessageConverter * @since 3.0 */ @@ -61,8 +62,10 @@ public class MappingJacksonJsonView extends AbstractView { private Set renderedAttributes; - private boolean disableCaching = true; + private boolean extractValueFromSingleKeyModel = false; + private boolean disableCaching = true; + /** * Construct a new {@code JacksonJsonView}, setting the content type to {@code application/json}. */ @@ -127,6 +130,19 @@ public class MappingJacksonJsonView extends AbstractView { this.disableCaching = disableCaching; } + /** + * Set whether to serialize models containing a single attribute as a map or whether to + * extract the single value from the model and serialize it directly. + * The effect of setting this flag is similar to using + * {@code MappingJacksonHttpMessageConverter} with an {@code @ResponseBody}. + * request-handling method. + * + *

Default is {@code false}. + */ + public void setExtractValueFromSingleKeyModel(boolean extractValueFromSingleKeyModel) { + this.extractValueFromSingleKeyModel = extractValueFromSingleKeyModel; + } + @Override protected void prepareResponse(HttpServletRequest request, HttpServletResponse response) { response.setContentType(getContentType()); @@ -170,7 +186,7 @@ public class MappingJacksonJsonView extends AbstractView { result.put(entry.getKey(), entry.getValue()); } } - return result; + return (this.extractValueFromSingleKeyModel && result.size() == 1) ? result.values().iterator().next() : result; } } diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/view/json/MappingJacksonJsonViewTest.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/view/json/MappingJacksonJsonViewTest.java index aa3ab2f9eee..7762e05a0ff 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/view/json/MappingJacksonJsonViewTest.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/view/json/MappingJacksonJsonViewTest.java @@ -194,6 +194,36 @@ public class MappingJacksonJsonViewTest { validateResult(); } + @Test + public void filterSingleKeyModel() throws Exception { + view.setExtractValueFromSingleKeyModel(true); + + Map model = new HashMap(); + TestBeanSimple bean = new TestBeanSimple(); + model.put("foo", bean); + + Object actual = view.filterModel(model); + + assertSame(bean, actual); + } + + @Test + public void filterTwoKeyModel() throws Exception { + view.setExtractValueFromSingleKeyModel(true); + + Map model = new HashMap(); + TestBeanSimple bean1 = new TestBeanSimple(); + TestBeanSimple bean2 = new TestBeanSimple(); + model.put("foo1", bean1); + model.put("foo2", bean2); + + Object actual = view.filterModel(model); + + assertTrue(actual instanceof Map); + assertSame(bean1, ((Map) actual).get("foo1")); + assertSame(bean2, ((Map) actual).get("foo2")); + } + private void validateResult() throws Exception { Object jsResult = jsContext.evaluateString(jsScope, "(" + response.getContentAsString() + ")", "JSON Stream", 1, null); diff --git a/spring-framework-reference/src/view.xml b/spring-framework-reference/src/view.xml index 6b607d07e64..2ddab20a443 100644 --- a/spring-framework-reference/src/view.xml +++ b/spring-framework-reference/src/view.xml @@ -2610,7 +2610,9 @@ simpleReport.reportDataKey=myBeanData of framework-specific classes) will be encoded as JSON. For cases where the contents of the map need to be filtered, users may specify a specific set of model attributes to encode via the RenderedAttributes - property. + property. The extractValueFromSingleKeyModel property + may also be used to have the value in single-key models extracted and + serialized directly rather than as a map of model attributes. JSON mapping can be customized as needed through the use of Jackson's provided annotations. When further control is needed, a custom