From 30df43f1fa01ecbbc021d47cadb3cd759bdba8f9 Mon Sep 17 00:00:00 2001 From: Naros Date: Sat, 20 Jun 2015 13:19:29 -0500 Subject: [PATCH 1/4] WW-4516: Allow JSON plug-in to skip bean cache when devMode is enabled. --- .../org/apache/struts2/json/JSONResult.java | 47 ++++-- .../org/apache/struts2/json/JSONUtil.java | 145 ++++++++++++++++-- .../org/apache/struts2/json/JSONWriter.java | 5 + 3 files changed, 168 insertions(+), 29 deletions(-) diff --git a/plugins/json/src/main/java/org/apache/struts2/json/JSONResult.java b/plugins/json/src/main/java/org/apache/struts2/json/JSONResult.java index dfa0d6cff..2da32109e 100644 --- a/plugins/json/src/main/java/org/apache/struts2/json/JSONResult.java +++ b/plugins/json/src/main/java/org/apache/struts2/json/JSONResult.java @@ -20,12 +20,16 @@ */ package org.apache.struts2.json; -import com.opensymphony.xwork2.ActionContext; -import com.opensymphony.xwork2.ActionInvocation; -import com.opensymphony.xwork2.Result; -import com.opensymphony.xwork2.inject.Inject; -import com.opensymphony.xwork2.util.ValueStack; -import com.opensymphony.xwork2.util.WildcardUtil; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.regex.Pattern; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -33,13 +37,12 @@ import org.apache.struts2.StrutsConstants; import org.apache.struts2.StrutsStatics; import org.apache.struts2.json.smd.SMDGenerator; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import java.util.regex.Pattern; +import com.opensymphony.xwork2.ActionContext; +import com.opensymphony.xwork2.ActionInvocation; +import com.opensymphony.xwork2.Result; +import com.opensymphony.xwork2.inject.Inject; +import com.opensymphony.xwork2.util.ValueStack; +import com.opensymphony.xwork2.util.WildcardUtil; /** *

This result serializes an action @@ -84,6 +87,7 @@ public class JSONResult implements Result { private boolean ignoreInterfaces = true; private boolean enumAsBean = JSONWriter.ENUM_AS_BEAN_DEFAULT; private boolean noCache = false; + private boolean cacheBeanInfo = true; private boolean excludeNullProperties = false; private String defaultDateFormat = null; private int statusCode; @@ -92,12 +96,18 @@ public class JSONResult implements Result { private String contentType; private String wrapPrefix; private String wrapSuffix; - + private boolean debugMode = false; + @Inject(StrutsConstants.STRUTS_I18N_ENCODING) public void setDefaultEncoding(String val) { this.defaultEncoding = val; } - + + @Inject(StrutsConstants.STRUTS_DEVMODE) + public void setDebugMode(String val) { + this.debugMode = BooleanUtils.toBoolean(val); + } + /** * Gets a list of regular expressions of properties to exclude from the JSON * output. @@ -171,7 +181,10 @@ public class JSONResult implements Result { ActionContext actionContext = invocation.getInvocationContext(); HttpServletRequest request = (HttpServletRequest) actionContext.get(StrutsStatics.HTTP_REQUEST); HttpServletResponse response = (HttpServletResponse) actionContext.get(StrutsStatics.HTTP_RESPONSE); - + + // only permit caching bean information when struts devMode = false + cacheBeanInfo = !debugMode; + try { Object rootObject; rootObject = readRootObject(invocation); @@ -202,7 +215,7 @@ public class JSONResult implements Result { protected String createJSONString(HttpServletRequest request, Object rootObject) throws JSONException { String json = JSONUtil.serialize(rootObject, excludeProperties, includeProperties, ignoreHierarchy, - enumAsBean, excludeNullProperties, defaultDateFormat); + enumAsBean, excludeNullProperties, defaultDateFormat, cacheBeanInfo); json = addCallbackIfApplicable(request, json); return json; } diff --git a/plugins/json/src/main/java/org/apache/struts2/json/JSONUtil.java b/plugins/json/src/main/java/org/apache/struts2/json/JSONUtil.java index 0ee024e3d..bde729837 100644 --- a/plugins/json/src/main/java/org/apache/struts2/json/JSONUtil.java +++ b/plugins/json/src/main/java/org/apache/struts2/json/JSONUtil.java @@ -20,20 +20,34 @@ */ package org.apache.struts2.json; -import com.opensymphony.xwork2.util.TextParseUtil; -import com.opensymphony.xwork2.util.WildcardUtil; +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.io.Reader; +import java.io.Writer; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.regex.Pattern; +import java.util.zip.GZIPOutputStream; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.struts2.json.annotations.SMDMethod; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.*; -import java.lang.reflect.Method; -import java.util.*; -import java.util.regex.Pattern; -import java.util.zip.GZIPOutputStream; +import com.opensymphony.xwork2.util.TextParseUtil; +import com.opensymphony.xwork2.util.WildcardUtil; /** * Wrapper for JSONWriter with some utility methods. @@ -43,7 +57,8 @@ public class JSONUtil { public final static String RFC3339_FORMAT = "yyyy-MM-dd'T'HH:mm:ss"; private static final Logger LOG = LogManager.getLogger(JSONUtil.class); - + private static final boolean CACHE_BEAN_INFO_DEFAULT = true; + /** * Serializes an object into JSON. * @@ -53,7 +68,22 @@ public class JSONUtil { * @throws JSONException */ public static String serialize(Object object) throws JSONException { + return serialize(object, CACHE_BEAN_INFO_DEFAULT); + } + + /** + * Serializes an object into JSON. + * + * @param object + * to be serialized + * @param cacheBeanInfo + * Specifies whether to cache bean info in the JSONWriter + * @return JSON string + * @throws JSONException + */ + public static String serialize(Object object, boolean cacheBeanInfo) throws JSONException { JSONWriter writer = new JSONWriter(); + writer.setCacheBeanInfo(cacheBeanInfo); return writer.write(object); } @@ -74,8 +104,33 @@ public class JSONUtil { public static String serialize(Object object, Collection excludeProperties, Collection includeProperties, boolean ignoreHierarchy, boolean excludeNullProperties) throws JSONException { + return serialize(object, excludeProperties, includeProperties, + ignoreHierarchy, excludeNullProperties, CACHE_BEAN_INFO_DEFAULT); + } + + /** + * Serializes an object into JSON, excluding any properties matching any of + * the regular expressions in the given collection. + * + * @param object + * to be serialized + * @param excludeProperties + * Patterns matching properties to exclude + * @param ignoreHierarchy + * whether to ignore properties defined on base classes of the + * root object + * @param cacheBeanInfo + * Specifies whether to cache bean info in the JSONWriter + * @return JSON string + * @throws JSONException + */ + public static String serialize(Object object, Collection excludeProperties, + Collection includeProperties, boolean ignoreHierarchy, boolean excludeNullProperties, + boolean cacheBeanInfo) + throws JSONException { JSONWriter writer = new JSONWriter(); writer.setIgnoreHierarchy(ignoreHierarchy); + writer.setCacheBeanInfo(cacheBeanInfo); return writer.write(object, excludeProperties, includeProperties, excludeNullProperties); } @@ -100,10 +155,38 @@ public class JSONUtil { public static String serialize(Object object, Collection excludeProperties, Collection includeProperties, boolean ignoreHierarchy, boolean enumAsBean, boolean excludeNullProperties, String defaultDateFormat) throws JSONException { + return serialize(object, excludeProperties, includeProperties, ignoreHierarchy, enumAsBean, + excludeNullProperties, defaultDateFormat, CACHE_BEAN_INFO_DEFAULT); + } + + /** + * Serializes an object into JSON, excluding any properties matching any of + * the regular expressions in the given collection. + * + * @param object + * to be serialized + * @param excludeProperties + * Patterns matching properties to exclude + * @param ignoreHierarchy + * whether to ignore properties defined on base classes of the + * root object + * @param enumAsBean + * whether to serialized enums a Bean or name=value pair + * @param defaultDateFormat + * date format used to serialize dates + * @param cacheBeanInfo + * Specifies whether to cache bean info in the JSONWriter + * @return JSON string + * @throws JSONException + */ + public static String serialize(Object object, Collection excludeProperties, + Collection includeProperties, boolean ignoreHierarchy, boolean enumAsBean, + boolean excludeNullProperties, String defaultDateFormat, boolean cacheBeanInfo) throws JSONException { JSONWriter writer = new JSONWriter(); writer.setIgnoreHierarchy(ignoreHierarchy); writer.setEnumAsBean(enumAsBean); writer.setDateFormatter(defaultDateFormat); + writer.setCacheBeanInfo(cacheBeanInfo); return writer.write(object, excludeProperties, includeProperties, excludeNullProperties); } @@ -118,7 +201,23 @@ public class JSONUtil { * @throws JSONException */ public static void serialize(Writer writer, Object object) throws IOException, JSONException { - writer.write(serialize(object)); + serialize(writer, object, CACHE_BEAN_INFO_DEFAULT); + } + + /** + * Serializes an object into JSON to the given writer. + * + * @param writer + * Writer to serialize the object to + * @param object + * object to be serialized + * @param cacheBeanInfo + * Specifies whether to cache bean info in the JSONWriter + * @throws IOException + * @throws JSONException + */ + public static void serialize(Writer writer, Object object, boolean cacheBeanInfo) throws IOException, JSONException { + writer.write(serialize(object, cacheBeanInfo)); } /** @@ -138,7 +237,29 @@ public class JSONUtil { public static void serialize(Writer writer, Object object, Collection excludeProperties, Collection includeProperties, boolean excludeNullProperties) throws IOException, JSONException { - writer.write(serialize(object, excludeProperties, includeProperties, true, excludeNullProperties)); + serialize(writer, object, excludeProperties, includeProperties, excludeNullProperties, CACHE_BEAN_INFO_DEFAULT); + } + + /** + * Serializes an object into JSON to the given writer, excluding any + * properties matching any of the regular expressions in the given + * collection. + * + * @param writer + * Writer to serialize the object to + * @param object + * object to be serialized + * @param excludeProperties + * Patterns matching properties to ignore + * @param cacheBeanInfo + * Specifies whether to cache bean info in the JSONWriter + * @throws IOException + * @throws JSONException + */ + public static void serialize(Writer writer, Object object, Collection excludeProperties, + Collection includeProperties, boolean excludeNullProperties, boolean cacheBeanInfo) + throws IOException, JSONException { + writer.write(serialize(object, excludeProperties, includeProperties, true, excludeNullProperties, cacheBeanInfo)); } /** diff --git a/plugins/json/src/main/java/org/apache/struts2/json/JSONWriter.java b/plugins/json/src/main/java/org/apache/struts2/json/JSONWriter.java index 154508401..c3b888911 100644 --- a/plugins/json/src/main/java/org/apache/struts2/json/JSONWriter.java +++ b/plugins/json/src/main/java/org/apache/struts2/json/JSONWriter.java @@ -74,6 +74,7 @@ public class JSONWriter { private DateFormat formatter; private boolean enumAsBean = ENUM_AS_BEAN_DEFAULT; private boolean excludeNullProperties; + private boolean cacheBeanInfo = true; /** * @param object Object to be serialized into JSON @@ -620,6 +621,10 @@ public class JSONWriter { this.formatter = new SimpleDateFormat(defaultDateFormat); } } + + public void setCacheBeanInfo(boolean cacheBeanInfo) { + this.cacheBeanInfo = cacheBeanInfo; + } protected static class JSONAnnotationFinder { private boolean serialize = true; From a778ba1a3d4ff03ed4103569937317bf1dafb2bd Mon Sep 17 00:00:00 2001 From: Naros Date: Mon, 22 Jun 2015 09:18:24 -0500 Subject: [PATCH 2/4] Renamed debugMode to devMode. Renamed the debugMode variable to devMode. --- .../src/main/java/org/apache/struts2/json/JSONResult.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/json/src/main/java/org/apache/struts2/json/JSONResult.java b/plugins/json/src/main/java/org/apache/struts2/json/JSONResult.java index 2da32109e..ee2c58c5b 100644 --- a/plugins/json/src/main/java/org/apache/struts2/json/JSONResult.java +++ b/plugins/json/src/main/java/org/apache/struts2/json/JSONResult.java @@ -96,7 +96,7 @@ public class JSONResult implements Result { private String contentType; private String wrapPrefix; private String wrapSuffix; - private boolean debugMode = false; + private boolean devMode = false; @Inject(StrutsConstants.STRUTS_I18N_ENCODING) public void setDefaultEncoding(String val) { @@ -105,7 +105,7 @@ public class JSONResult implements Result { @Inject(StrutsConstants.STRUTS_DEVMODE) public void setDebugMode(String val) { - this.debugMode = BooleanUtils.toBoolean(val); + this.devMode = BooleanUtils.toBoolean(val); } /** @@ -183,7 +183,7 @@ public class JSONResult implements Result { HttpServletResponse response = (HttpServletResponse) actionContext.get(StrutsStatics.HTTP_RESPONSE); // only permit caching bean information when struts devMode = false - cacheBeanInfo = !debugMode; + cacheBeanInfo = !devMode; try { Object rootObject; From 88bfeb556d10dbb8ea4734e2e80dc40beca13645 Mon Sep 17 00:00:00 2001 From: Naros Date: Mon, 22 Jun 2015 09:21:13 -0500 Subject: [PATCH 3/4] Removed unused methods Removed JSONUtil.serialize(Object) in favor for using the method that accepts a boolean to control bean caching functionality. --- .../org/apache/struts2/json/JSONUtil.java | 18 +++----------- .../apache/struts2/json/JSONResultTest.java | 24 ++++++++++--------- .../org/apache/struts2/json/JSONUtilTest.java | 2 +- 3 files changed, 17 insertions(+), 27 deletions(-) diff --git a/plugins/json/src/main/java/org/apache/struts2/json/JSONUtil.java b/plugins/json/src/main/java/org/apache/struts2/json/JSONUtil.java index bde729837..5c2e9fcc7 100644 --- a/plugins/json/src/main/java/org/apache/struts2/json/JSONUtil.java +++ b/plugins/json/src/main/java/org/apache/struts2/json/JSONUtil.java @@ -55,22 +55,10 @@ import com.opensymphony.xwork2.util.WildcardUtil; public class JSONUtil { public final static String RFC3339_FORMAT = "yyyy-MM-dd'T'HH:mm:ss"; - + public static final boolean CACHE_BEAN_INFO_DEFAULT = true; + private static final Logger LOG = LogManager.getLogger(JSONUtil.class); - private static final boolean CACHE_BEAN_INFO_DEFAULT = true; - - /** - * Serializes an object into JSON. - * - * @param object - * to be serialized - * @return JSON string - * @throws JSONException - */ - public static String serialize(Object object) throws JSONException { - return serialize(object, CACHE_BEAN_INFO_DEFAULT); - } - + /** * Serializes an object into JSON. * diff --git a/plugins/json/src/test/java/org/apache/struts2/json/JSONResultTest.java b/plugins/json/src/test/java/org/apache/struts2/json/JSONResultTest.java index bcd31e682..e9ca28353 100644 --- a/plugins/json/src/test/java/org/apache/struts2/json/JSONResultTest.java +++ b/plugins/json/src/test/java/org/apache/struts2/json/JSONResultTest.java @@ -20,16 +20,6 @@ */ package org.apache.struts2.json; -import com.opensymphony.xwork2.ActionContext; -import com.opensymphony.xwork2.mock.MockActionInvocation; -import com.opensymphony.xwork2.util.ValueStack; -import org.apache.struts2.StrutsStatics; -import org.apache.struts2.StrutsTestCase; -import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.mock.web.MockHttpServletResponse; -import org.springframework.mock.web.MockServletContext; - -import javax.servlet.http.HttpServletResponse; import java.math.BigDecimal; import java.math.BigInteger; import java.text.SimpleDateFormat; @@ -45,6 +35,18 @@ import java.util.Map; import java.util.Set; import java.util.regex.Pattern; +import javax.servlet.http.HttpServletResponse; + +import org.apache.struts2.StrutsStatics; +import org.apache.struts2.StrutsTestCase; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.mock.web.MockServletContext; + +import com.opensymphony.xwork2.ActionContext; +import com.opensymphony.xwork2.mock.MockActionInvocation; +import com.opensymphony.xwork2.util.ValueStack; + /** * JSONResultTest */ @@ -60,7 +62,7 @@ public class JSONResultTest extends StrutsTestCase { Map map = new HashMap(); map.put("createtime", new Date()); try { - JSONUtil.serialize(map); + JSONUtil.serialize(map, JSONUtil.CACHE_BEAN_INFO_DEFAULT); } catch (JSONException e) { fail(e.getMessage()); } diff --git a/plugins/json/src/test/java/org/apache/struts2/json/JSONUtilTest.java b/plugins/json/src/test/java/org/apache/struts2/json/JSONUtilTest.java index 2df5e47e6..dab592453 100644 --- a/plugins/json/src/test/java/org/apache/struts2/json/JSONUtilTest.java +++ b/plugins/json/src/test/java/org/apache/struts2/json/JSONUtilTest.java @@ -45,7 +45,7 @@ public class JSONUtilTest extends TestCase { bean1.setEnumField(AnEnum.ValueA); bean1.setEnumBean(AnEnumBean.Two); - String json = JSONUtil.serialize(bean1); + String json = JSONUtil.serialize(bean1, JSONUtil.CACHE_BEAN_INFO_DEFAULT); Map result = (Map) JSONUtil.deserialize(json); assertEquals("str", result.get("stringField")); From f18e24d2ac310a043025a8ace1c6b01d4dd179b6 Mon Sep 17 00:00:00 2001 From: Naros Date: Mon, 22 Jun 2015 10:32:05 -0500 Subject: [PATCH 4/4] Renamed setter for devMode. --- .../json/src/main/java/org/apache/struts2/json/JSONResult.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/json/src/main/java/org/apache/struts2/json/JSONResult.java b/plugins/json/src/main/java/org/apache/struts2/json/JSONResult.java index ee2c58c5b..c0ae8a6e6 100644 --- a/plugins/json/src/main/java/org/apache/struts2/json/JSONResult.java +++ b/plugins/json/src/main/java/org/apache/struts2/json/JSONResult.java @@ -104,7 +104,7 @@ public class JSONResult implements Result { } @Inject(StrutsConstants.STRUTS_DEVMODE) - public void setDebugMode(String val) { + public void setDevMode(String val) { this.devMode = BooleanUtils.toBoolean(val); }