All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.struts2.json.JSONResult Maven / Gradle / Ivy

There is a newer version: 6.6.1
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
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 org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.ModelDriven;
import org.apache.struts2.StrutsConstants;
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;

/**
 * 
 * 

* This result serializes an action into JSON. *

* *

Result parameters:

* *
    * *
  • excludeProperties - list of regular expressions matching the properties * to be excluded. The regular expressions are evaluated against the OGNL * expression representation of the properties.
  • * *
* *

Example:

* *
 * <!-- START SNIPPET: example -->
 * <result name="success" type="json" />
 * <!-- END SNIPPET: example -->
 * 
*/ public class JSONResult implements Result { private static final long serialVersionUID = 233903199020467341L; private static final Logger LOG = LogManager.getLogger(JSONResult.class); /** * This result type doesn't have a default param, null is ok to reduce noise in logs */ public static final String DEFAULT_PARAM = null; private String encoding; private String defaultEncoding = "UTF-8"; private List includeProperties; private List excludeProperties; private String root; private boolean wrapWithComments; private boolean prefix; private boolean enableSMD = false; private boolean enableGZIP = false; private boolean ignoreHierarchy = true; 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; private int errorCode; private String callbackParameter; private String contentType; private String wrapPrefix; private String wrapSuffix; private boolean devMode = false; private JSONUtil jsonUtil; @Inject(StrutsConstants.STRUTS_I18N_ENCODING) public void setDefaultEncoding(String val) { this.defaultEncoding = val; } @Inject(StrutsConstants.STRUTS_DEVMODE) public void setDevMode(String val) { this.devMode = BooleanUtils.toBoolean(val); } @Inject public void setJsonUtil(JSONUtil jsonUtil) { this.jsonUtil = jsonUtil; } /** * Gets a list of regular expressions of properties to exclude from the JSON * output. * * @return A list of compiled regular expression patterns */ public List getExcludePropertiesList() { return this.excludeProperties; } /** * Sets a comma-delimited list of regular expressions to match properties * that should be excluded from the JSON output. * * @param commaDelim A comma-delimited list of regular expressions */ public void setExcludeProperties(String commaDelim) { Set excludePatterns = JSONUtil.asSet(commaDelim); if (excludePatterns != null) { this.excludeProperties = new ArrayList<>(excludePatterns.size()); for (String pattern : excludePatterns) { this.excludeProperties.add(Pattern.compile(pattern)); } } } /** * Sets a comma-delimited list of wildcard expressions to match properties * that should be excluded from the JSON output. * * @param commaDelim A comma-delimited list of wildcard patterns */ public void setExcludeWildcards(String commaDelim) { Set excludePatterns = JSONUtil.asSet(commaDelim); if (excludePatterns != null) { this.excludeProperties = new ArrayList<>(excludePatterns.size()); for (String pattern : excludePatterns) { this.excludeProperties.add(WildcardUtil.compileWildcardPattern(pattern)); } } } /** * @return the includeProperties */ public List getIncludePropertiesList() { return includeProperties; } /** * Sets a comma-delimited list of regular expressions to match properties * that should be included in the JSON output. * * @param commaDelim A comma-delimited list of regular expressions */ public void setIncludeProperties(String commaDelim) { includeProperties = JSONUtil.processIncludePatterns(JSONUtil.asSet(commaDelim), JSONUtil.REGEXP_PATTERN); } /** * Sets a comma-delimited list of wildcard expressions to match properties * that should be included in the JSON output. * * @param commaDelim A comma-delimited list of wildcard patterns */ public void setIncludeWildcards(String commaDelim) { includeProperties = JSONUtil.processIncludePatterns(JSONUtil.asSet(commaDelim), JSONUtil.WILDCARD_PATTERN); } public void execute(ActionInvocation invocation) throws Exception { if (invocation == null) { throw new IllegalArgumentException("Invocation cannot be null!"); } ActionContext actionContext = invocation.getInvocationContext(); HttpServletRequest request = actionContext.getServletRequest(); HttpServletResponse response = actionContext.getServletResponse(); // only permit caching bean information when struts devMode = false cacheBeanInfo = !devMode; try { Object rootObject; rootObject = readRootObject(invocation); writeToResponse(response, createJSONString(request, rootObject), enableGzip(request)); } catch (IOException exception) { LOG.error(exception.getMessage(), exception); throw exception; } } protected Object readRootObject(ActionInvocation invocation) { if (enableSMD) { return buildSMDObject(invocation); } return findRootObject(invocation); } protected Object findRootObject(ActionInvocation invocation) { ValueStack stack = invocation.getStack(); Object rootObject; if (this.root != null) { LOG.debug("Root was defined as [{}], searching stack for it", this.root); rootObject = stack.findValue(root); } else { LOG.debug("Root was not defined, searching for #action"); rootObject = stack.findValue("#action"); if (rootObject instanceof ModelDriven) { LOG.debug("Action is an instance of ModelDriven, assuming model is on the top of the stack and using it"); rootObject = stack.peek(); } else if (rootObject == null) { LOG.debug("Neither #action nor ModelDriven, peeking up object from the top of the stack"); rootObject = stack.peek(); } } return rootObject; } protected String createJSONString(HttpServletRequest request, Object rootObject) throws JSONException { String json = jsonUtil.serialize(rootObject, excludeProperties, includeProperties, ignoreHierarchy, enumAsBean, excludeNullProperties, defaultDateFormat, cacheBeanInfo); json = addCallbackIfApplicable(request, json); return json; } protected boolean enableGzip(HttpServletRequest request) { return enableGZIP && JSONUtil.isGzipInRequest(request); } protected void writeToResponse(HttpServletResponse response, String json, boolean gzip) throws IOException { JSONUtil.writeJSONToResponse(new SerializationParams(response, getEncoding(), isWrapWithComments(), json, false, gzip, noCache, statusCode, errorCode, prefix, contentType, wrapPrefix, wrapSuffix)); } protected org.apache.struts2.json.smd.SMD buildSMDObject(ActionInvocation invocation) { return new SMDGenerator(findRootObject(invocation), excludeProperties, ignoreInterfaces).generate(invocation); } /** * Retrieve the encoding * * @return The encoding associated with this template (defaults to the value * of param 'encoding', if empty default to 'struts.i18n.encoding' property) */ protected String getEncoding() { String encoding = this.encoding; if (encoding == null) { encoding = this.defaultEncoding; } if (encoding == null) { encoding = System.getProperty("file.encoding"); } if (encoding == null) { encoding = "UTF-8"; } return encoding; } protected String addCallbackIfApplicable(HttpServletRequest request, String json) { if ((callbackParameter != null) && (callbackParameter.length() > 0)) { String callbackName = request.getParameter(callbackParameter); if (StringUtils.isNotEmpty(callbackName)) { json = callbackName + "(" + json + ")"; } } return json; } /** * @return OGNL expression of root object to be serialized */ public String getRoot() { return this.root; } /** * Sets the root object to be serialized, defaults to the Action. * If the Action implements {@link ModelDriven}, the Model will be used instead, * with the logic assuming the Model was pushed onto the top of the stack. * * @param root OGNL expression of root object to be serialized */ public void setRoot(String root) { this.root = root; } /** * @return Generated JSON must be enclosed in comments */ public boolean isWrapWithComments() { return this.wrapWithComments; } /** * @param wrapWithComments Wrap generated JSON with comments */ public void setWrapWithComments(boolean wrapWithComments) { this.wrapWithComments = wrapWithComments; } /** * @return Result has SMD generation enabled */ public boolean isEnableSMD() { return this.enableSMD; } /** * @param enableSMD Enable SMD generation for action, which can be used for JSON-RPC */ public void setEnableSMD(boolean enableSMD) { this.enableSMD = enableSMD; } public void setIgnoreHierarchy(boolean ignoreHierarchy) { this.ignoreHierarchy = ignoreHierarchy; } /** * @param ignoreInterfaces Controls whether interfaces should be inspected for method annotations * You may need to set to this true if your action is a proxy as annotations * on methods are not inherited */ public void setIgnoreInterfaces(boolean ignoreInterfaces) { this.ignoreInterfaces = ignoreInterfaces; } /** * @param enumAsBean Controls how Enum's are serialized : If true, an Enum is serialized as a * name=value pair (name=name()) (default) If false, an Enum is serialized * as a bean with a special property _name=name() */ public void setEnumAsBean(boolean enumAsBean) { this.enumAsBean = enumAsBean; } public boolean isEnumAsBean() { return enumAsBean; } public boolean isEnableGZIP() { return enableGZIP; } public void setEnableGZIP(boolean enableGZIP) { this.enableGZIP = enableGZIP; } public boolean isNoCache() { return noCache; } /** * @param noCache Add headers to response to prevent the browser from caching the response */ public void setNoCache(boolean noCache) { this.noCache = noCache; } public boolean isIgnoreHierarchy() { return ignoreHierarchy; } public boolean isExcludeNullProperties() { return excludeNullProperties; } /** * @param excludeNullProperties Do not serialize properties with a null value */ public void setExcludeNullProperties(boolean excludeNullProperties) { this.excludeNullProperties = excludeNullProperties; } /** * @param statusCode Status code to be set in the response */ public void setStatusCode(int statusCode) { this.statusCode = statusCode; } /** * @param errorCode Error code to be set in the response */ public void setErrorCode(int errorCode) { this.errorCode = errorCode; } public void setCallbackParameter(String callbackParameter) { this.callbackParameter = callbackParameter; } public String getCallbackParameter() { return callbackParameter; } /** * @param prefix Prefix JSON with "{} &&" */ public void setPrefix(boolean prefix) { this.prefix = prefix; } /** * @param contentType Content type to be set in the response */ public void setContentType(String contentType) { this.contentType = contentType; } public String getWrapPrefix() { return wrapPrefix; } /** * @param wrapPrefix Text to be inserted at the begining of the response */ public void setWrapPrefix(String wrapPrefix) { this.wrapPrefix = wrapPrefix; } public String getWrapSuffix() { return wrapSuffix; } /** * @param wrapSuffix Text to be inserted at the end of the response */ public void setWrapSuffix(String wrapSuffix) { this.wrapSuffix = wrapSuffix; } /** * If defined will be used instead of {@link #defaultEncoding}, you can define it with result * <result name="success" type="json"> * <param name="encoding">UTF-8</param> * </result> * * @param encoding valid encoding string */ public void setEncoding(String encoding) { this.encoding = encoding; } public String getDefaultDateFormat() { return defaultDateFormat; } @Inject(required = false, value = JSONConstants.DATE_FORMAT) public void setDefaultDateFormat(String defaultDateFormat) { this.defaultDateFormat = defaultDateFormat; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy