WW-4599: backport JSONActionRedirectResult to struts 2.3

This commit is contained in:
cnenning
2016-01-11 14:36:32 +01:00
parent 15c79e1398
commit 69bc2947c1
15 changed files with 735 additions and 3 deletions
@@ -0,0 +1,152 @@
package org.apache.struts2.showcase.validation;
import java.sql.Date;
import com.opensymphony.xwork2.validator.annotations.DateRangeFieldValidator;
import com.opensymphony.xwork2.validator.annotations.EmailValidator;
import com.opensymphony.xwork2.validator.annotations.FieldExpressionValidator;
import com.opensymphony.xwork2.validator.annotations.IntRangeFieldValidator;
import com.opensymphony.xwork2.validator.annotations.RegexFieldValidator;
import com.opensymphony.xwork2.validator.annotations.RequiredFieldValidator;
import com.opensymphony.xwork2.validator.annotations.RequiredStringValidator;
import com.opensymphony.xwork2.validator.annotations.StringLengthFieldValidator;
import com.opensymphony.xwork2.validator.annotations.UrlValidator;
/**
* <!-- START SNIPPET: ajaxFormSubmit -->
*/
/**
* Example Action that shows how forms can be validated and submitted via AJAX
* only. Form-submit-and-page-reload functionality of browsers is not used for
* this action.
* <p>Some things to note:
* <ul>
* <li>Depends on <code>json-plugin</code>.</li>
* <li>Requires <code>jsonValidationInterceptor</code> to be on stack.</li>
* <li>Uses a special json redirect result type.</li>
* <li>Uses http parameters <code>struts.enableJSONValidation=true</code> and <code>struts.validateOnly=false</code>.</li>
* <li>Uses a customized theme to make sure html elements required as error containers are always present and easily selectable in JS.</li>
* <li>Uses some custom JS code depending on jQuery to issue AJAX request and to render errors in html.</li>
* <li>Shows visual feedback while waiting for AJAX response.</li>
* </ul>
* </p>
*
*/
public class AjaxFormSubmitAction extends AbstractValidationActionSupport {
private String requiredValidatorField = null;
private String requiredStringValidatorField = null;
private Integer integerValidatorField = null;
private Date dateValidatorField = null;
private String emailValidatorField = null;
private String urlValidatorField = null;
private String stringLengthValidatorField = null;
private String regexValidatorField = null;
private String fieldExpressionValidatorField = null;
@Override
public void validate() {
if (hasFieldErrors()) {
addActionError("Errors present!");
}
}
public Date getDateValidatorField() {
return dateValidatorField;
}
@DateRangeFieldValidator(
min="01/01/1990",
max="01/01/2000",
message="must be a min 01-01-1990 max 01-01-2000 if supplied")
public void setDateValidatorField(Date dateValidatorField) {
this.dateValidatorField = dateValidatorField;
}
public String getEmailValidatorField() {
return emailValidatorField;
}
@EmailValidator(message="must be a valid email if supplied")
public void setEmailValidatorField(String emailValidatorField) {
this.emailValidatorField = emailValidatorField;
}
public Integer getIntegerValidatorField() {
return integerValidatorField;
}
@IntRangeFieldValidator(min="1", max="10", message="must be integer min 1 max 10 if supplied")
public void setIntegerValidatorField(Integer integerValidatorField) {
this.integerValidatorField = integerValidatorField;
}
public String getRegexValidatorField() {
return regexValidatorField;
}
@RegexFieldValidator(
regex="[^<>]+",
message="regexValidatorField must match a regexp (.*\\.txt) if specified")
public void setRegexValidatorField(String regexValidatorField) {
this.regexValidatorField = regexValidatorField;
}
public String getRequiredStringValidatorField() {
return requiredStringValidatorField;
}
@RequiredStringValidator(trim=true, message="required and must be string")
public void setRequiredStringValidatorField(String requiredStringValidatorField) {
this.requiredStringValidatorField = requiredStringValidatorField;
}
public String getRequiredValidatorField() {
return requiredValidatorField;
}
@RequiredFieldValidator(message="required")
public void setRequiredValidatorField(String requiredValidatorField) {
this.requiredValidatorField = requiredValidatorField;
}
public String getStringLengthValidatorField() {
return stringLengthValidatorField;
}
@StringLengthFieldValidator(
minLength="2",
maxLength="4",
trim=true,
message="must be a String of a specific greater than 1 less than 5 if specified")
public void setStringLengthValidatorField(String stringLengthValidatorField) {
this.stringLengthValidatorField = stringLengthValidatorField;
}
public String getFieldExpressionValidatorField() {
return fieldExpressionValidatorField;
}
@FieldExpressionValidator(
expression = "(fieldExpressionValidatorField == requiredValidatorField)",
message = "must be the same as the Required Validator Field if specified")
public void setFieldExpressionValidatorField(
String fieldExpressionValidatorField) {
this.fieldExpressionValidatorField = fieldExpressionValidatorField;
}
public String getUrlValidatorField() {
return urlValidatorField;
}
@UrlValidator(message="must be a valid url if supplied")
public void setUrlValidatorField(String urlValidatorField) {
this.urlValidatorField = urlValidatorField;
}
}
/**
* <!-- END SNIPPET: ajaxFormSubmit -->
*/
@@ -0,0 +1,7 @@
package org.apache.struts2.showcase.validation;
public class AjaxFormSubmitSuccessAction {
public String execute() {
return "success";
}
}
@@ -29,6 +29,19 @@
<result name="input">quiz-ajax.jsp</result>
<result>quiz-success.jsp</result>
</action>
<!-- =========================================== -->
<!-- === ajax form submit === -->
<!-- =========================================== -->
<action name="ajaxFormSubmit" class="org.apache.struts2.showcase.validation.AjaxFormSubmitAction">
<interceptor-ref name="jsonValidationWorkflowStack" />
<result name="input">/WEB-INF/validation/ajaxFormSubmit.jsp</result>
<result type="jsonActionRedirect">ajaxFormSubmitSuccess</result>
</action>
<action name="ajaxFormSubmitSuccess" class="org.apache.struts2.showcase.validation.AjaxFormSubmitSuccessAction">
<result>/WEB-INF/validation/ajaxFormSubmitSuccess.jsp</result>
</action>
</package>
@@ -0,0 +1,46 @@
<#--
/*
* $Id$
*
* 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.
*/
-->
<#--
Make sure element is always present. To be filled later via JS.
-->
<ul<#rt/>
<#if parameters.id??>
id="${parameters.id?html}"<#rt/>
</#if>
<#if parameters.cssClass??>
class="${parameters.cssClass?html}"<#rt/>
<#else>
class="errorMessage"<#rt/>
</#if>
<#if parameters.cssStyle??>
style="${parameters.cssStyle?html}"<#rt/>
</#if>
>
<#if (actionErrors?? && actionErrors?size > 0)>
<#list actionErrors as error>
<#if error??>
<li><span><#if parameters.escape>${error!?html}<#else>${error!}</#if></span><#rt/></li><#rt/>
</#if>
</#list>
</#if>
</ul>
@@ -0,0 +1,39 @@
<#--
/*
* $Id$
*
* 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.
*/
-->
${parameters.after!}<#t/>
</td><#lt/>
</tr>
<#if (parameters.errorposition!"top") == 'bottom'>
<#assign hasFieldErrors = parameters.name?? && fieldErrors?? && fieldErrors[parameters.name]??/>
<#if hasFieldErrors>
<tr errorFor="${parameters.id}">
<td class="tdErrorMessage" colspan="2"><#rt/>
<#if hasFieldErrors>
<#list fieldErrors[parameters.name] as error>
<div class="errorMessage">${error?html}</div><#t/>
</#list>
</#if>
</td><#lt/>
</tr>
</#if>
</#if>
@@ -0,0 +1,80 @@
<#--
/*
* $Id$
*
* 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.
*/
-->
<#--
Always include elements to show errors. They may be filled later via AJAX.
-->
<#assign hasFieldErrors = parameters.name?? && fieldErrors?? && fieldErrors[parameters.name]??/>
<#if (parameters.errorposition!"top") == 'top'>
<tr errorFor="${parameters.id}">
<td class="tdErrorMessage" colspan="2" data-error-for-fieldname="${parameters.name}"><#rt/>
<#if hasFieldErrors>
<#list fieldErrors[parameters.name] as error>
<div class="errorMessage">${error?html}</div><#t/>
</#list>
</#if>
</td><#lt/>
</tr>
</#if>
<#if !parameters.labelposition?? && (parameters.form.labelposition)??>
<#assign labelpos = parameters.form.labelposition/>
<#elseif parameters.labelposition??>
<#assign labelpos = parameters.labelposition/>
</#if>
<#--
if the label position is top,
then give the label it's own row in the table
-->
<tr>
<#if (labelpos!"") == 'top'>
<td class="tdLabelTop" colspan="2"><#rt/>
<#else>
<td class="tdLabel"><#rt/>
</#if>
<#if parameters.label??>
<label <#t/>
<#if parameters.id??>
for="${parameters.id?html}" <#t/>
</#if>
<#if hasFieldErrors>
class="errorLabel"<#t/>
<#else>
class="label"<#t/>
</#if>
><#t/>
<#if parameters.required!false && parameters.requiredPosition!"right" != 'right'>
<span class="required">*</span><#t/>
</#if>
${parameters.label?html}<#t/>
<#if parameters.required!false && parameters.requiredPosition!"right" == 'right'>
<span class="required">*</span><#t/>
</#if>
${parameters.labelseparator!":"?html}<#t/>
<#include "/${parameters.templateDir}/${parameters.expandTheme}/tooltip.ftl" />
</label><#t/>
</#if>
</td><#lt/>
<#-- add the extra row -->
<#if (labelpos!"") == 'top'>
</tr>
<tr>
</#if>
@@ -0,0 +1,21 @@
#
# $Id$
#
# 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.
#
parent = xhtml
@@ -246,7 +246,6 @@
</li>
<li><s:a value="/interactive/index.action">Interactive Demo</s:a></li>
</ul>
<ul class="nav pull-right">
<li class="dropdown last">
<a href="#" class="dropdown-toggle" data-toggle="dropdown"><i class="icon-flag"></i> Help<b
@@ -0,0 +1,177 @@
<%@taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title>Struts2 Showcase - Validation - AJAX Form Submit</title>
<s:head theme="xhtml"/>
<style type="text/css">
/* see comment of script element below! */
.ajaxVisualFeedback {
width: 16px;
height: 16px;
background-image: url('../images/indicator.gif');
background-repeat: no-repeat;
float: right;
}
</style>
</head>
<body>
<div class="page-header">
<h1>AJAX Form Submit</h1>
</div>
<div class="container-fluid">
<div class="row">
<div class="col-md-12">
<!-- START SNIPPET: ajaxFormSubmit -->
<h3>Action Errors Will Appear Here</h3>
<s:actionerror theme="ajaxErrorContainers"/>
<hr/>
<s:form method="POST" theme="xhtml">
<s:textfield label="Required Validator Field" name="requiredValidatorField" theme="ajaxErrorContainers"/>
<s:textfield label="Required String Validator Field" name="requiredStringValidatorField" theme="ajaxErrorContainers"/>
<s:textfield label="Integer Validator Field" name="integerValidatorField" theme="ajaxErrorContainers"/>
<s:textfield label="Date Validator Field" name="dateValidatorField" theme="ajaxErrorContainers"/>
<s:textfield label="Email Validator Field" name="emailValidatorField" theme="ajaxErrorContainers"/>
<s:textfield label="URL Validator Field" name="urlValidatorField" theme="ajaxErrorContainers"/>
<s:textfield label="String Length Validator Field" name="stringLengthValidatorField" theme="ajaxErrorContainers"/>
<s:textfield label="Regex Validator Field" name="regexValidatorField" theme="ajaxErrorContainers"/>
<s:textfield label="Field Expression Validator Field" name="fieldExpressionValidatorField" theme="ajaxErrorContainers"/>
<s:submit label="Submit" cssClass="btn btn-primary"/>
</s:form>
<!-- END SNIPPET: ajaxFormSubmit -->
</div>
</div>
</div>
<script type="text/javascript">
/********************************************************************
* JS just used on this page.
* Usually this would be placed in a JS file
* but as this showcase app is already hard to follow
* I place it here so it is easier to find.
*
* note: this requires jQuery.
*******************************************************************/
/**
* Validates given form per AJAX. To be called as onSubmit handler.
*
* @param event onSubmit event
*/
function ajaxFormValidation(event) {
event.preventDefault();
_removeValidationErrors();
var _form = $(event.target);
var _formData = _form.serialize(true);
// prepare visual feedback
// you may want to use other elements here
var originalButton = _form.find('.btn-primary');
// note: jQuery returns an array-like object
if (originalButton && originalButton.length && originalButton.length > 0) {
originalButton.hide();
var feedbackElement = $('<div class="ajaxVisualFeedback"></div>').insertAfter(originalButton);
var restoreFunction = function() {
originalButton.show();
feedbackElement.remove();
}
}
var options = {
data: 'struts.enableJSONValidation=true&struts.validateOnly=false&' + _formData,
async: true,
processData: false,
type: 'POST',
success: function (response, statusText, xhr) {
if (response.location) {
// no validation errors
// action has been executed and sent a redirect URL wrapped as JSON
// cannot use a normal http-redirect (status-code 3xx) as this would be followed by browsers and would not be available here
// follow JSON-redirect
window.location.href = response.location;
} else {
if (restoreFunction) {
restoreFunction();
}
_handleValidationResult(_form, response);
}
},
error: function(xhr, textStatus, errorThrown) {
if (restoreFunction) {
restoreFunction();
}
// show user an error message
_handleValidationResult(_form, {errors: ['Network or server error!']})
}
}
// send request, after delay to make sure everybody notices the visual feedback :)
window.setTimeout(function() {
var url = _form[0].action;
jQuery.ajax(url, options);
}, 1000);
}
/**
* Removes validation errors from HTML DOM.
*/
function _removeValidationErrors() {
// action errors
// you might want to use a custom ID here
$('ul.errorMessage li').remove();
// field errors
$('div.errorMessage').remove();
}
/**
* Incorporates validation errors in HTML DOM.
*
* @param form Form containing errors.
* @param errors Errors from server.
* @returns {Boolean} True if form can be submitted.
*/
function _handleValidationResult(form, errors) {
// action errors
if (errors.errors) {
// you might want to use a custom ID here
var errorContainer = $('ul.errorMessage');
$.each(errors.errors, function(index, errorMsg) {
var li = $('<li><span></span></li>');
li.text(errorMsg);
errorContainer.append(li);
});
}
// field errors
if (errors.fieldErrors) {
$.each(errors.fieldErrors, function(fieldName, errorMsg) {
var td = $('td[data-error-for-fieldname="' + fieldName + '"]');
if (td) {
var div = $('<div class="errorMessage"></div>');
div.text(errorMsg);
td.append(div);
}
});
}
}
// register onSubmit handler
$(window).bind('load', function() {
$('form').bind('submit', ajaxFormValidation);
});
</script>
</body>
</html>
@@ -0,0 +1,17 @@
<%@taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title>Struts2 Showcase - Validation - Success Field Validators Example</title>
<s:head/>
</head>
<body>
<div class="page-header">
<h1>Success !</h1>
</div>
<div class="container-fluid">
Form has been submitted.
</div>
</body>
</html>
@@ -31,6 +31,7 @@
<s:url var="clientSideValidationUrl" action="clientSideValidationExample" namespace="/validation"/>
<s:url var="backToShowcase" action="showcase" namespace="/"/>
<s:url var="storeMessageAcrossRequestExample" namespace="/validation" action="storeErrorsAcrossRequestExample"/>
<s:url var="ajaxFormSubmitAction" namespace="/validation" action="ajaxFormSubmit!input"/>
<ul>
<li><s:a href="%{fieldValidatorUrl}">Field Validators</s:a></li>
@@ -42,6 +43,7 @@
<li><s:a href="%{quizClient}">Validation (client)</s:a></li>
<li><s:a href="%{quizClientCss}">Validation (client using css_xhtml theme)</s:a></li>
<li><s:a href="%{visitorValidatorUrl}">Visitor Validator</s:a></li>
<li><s:a href="%{ajaxFormSubmitAction}">AJAX Form Submit</s:a></li>
</ul>
</div>
</div>
@@ -0,0 +1,71 @@
package org.apache.struts2.json;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.dispatcher.ServletActionRedirectResult;
/**
* Specialized form of {@link ServletActionRedirectResult} which takes care of
* situation that browser has a JS/AJAX context, there are no validation errors
* and action is executed. In this case a http redirect is harmful as browsers
* don't pass them to JS handlers. So this result produces a JSON response
* containing redirect data.
*
*<p>
* To be used along with {@link JSONValidationInterceptor}.
*</p>
*<p>
* Response JSON looks like this:
* <pre>{"location": "$redirect url$"}</pre>
*</p>
*
*/
public class JSONActionRedirectResult extends ServletActionRedirectResult {
private static final long serialVersionUID = 3107276294073879542L;
@Override
protected void sendRedirect(HttpServletResponse response, String finalLocation) throws IOException {
if (sendJsonInsteadOfRedirect()) {
printJson(response, finalLocation);
} else {
super.sendRedirect(response, finalLocation);
}
}
/**
* If browser has called action in a JS/AJAX context we cannot send a
* redirect as response.
*
* @return true if a JSON response shall be generated, false if a redirect
* shall be sent.
*/
static boolean sendJsonInsteadOfRedirect() {
HttpServletRequest request = ServletActionContext.getRequest();
return isJsonEnabled(request) && !isValidateOnly(request);
}
static void printJson(HttpServletResponse response, String finalLocation) throws IOException {
response.setStatus(HttpServletResponse.SC_OK);
response.setContentType("application/json");
response.setHeader("Location", finalLocation);
PrintWriter writer = response.getWriter();
writer.write("{\"location\": \"");
writer.write(finalLocation);
writer.write("\"}");
writer.close();
}
private static boolean isJsonEnabled(HttpServletRequest request) {
return "true".equals(request.getParameter(JSONValidationInterceptor.VALIDATE_JSON_PARAM));
}
private static boolean isValidateOnly(HttpServletRequest request) {
return "true".equals(request.getParameter(JSONValidationInterceptor.VALIDATE_ONLY_PARAM));
}
}
@@ -61,6 +61,8 @@ import java.util.Map;
* <p>If the request has a parameter 'struts.validateOnly' execution will return after
* validation (action won't be executed).</p>
*
* <p>If 'struts.validateOnly' is set to false you may want to use {@link JSONActionRedirectResult}.</p>
*
* <p>A request parameter named 'struts.enableJSONValidation' must be set to 'true' to
* use this interceptor</p>
*
@@ -72,8 +74,8 @@ public class JSONValidationInterceptor extends MethodFilterInterceptor {
private static final Logger LOG = LoggerFactory.getLogger(JSONValidationInterceptor.class);
private static final String VALIDATE_ONLY_PARAM = "struts.validateOnly";
private static final String VALIDATE_JSON_PARAM = "struts.enableJSONValidation";
static final String VALIDATE_ONLY_PARAM = "struts.validateOnly";
static final String VALIDATE_JSON_PARAM = "struts.enableJSONValidation";
private static final String NO_ENCODING_SET_PARAM = "struts.JSONValidation.no.encoding";
private static final String DEFAULT_ENCODING = "UTF-8";
@@ -9,6 +9,7 @@
<result-types>
<result-type name="json" class="org.apache.struts2.json.JSONResult"/>
<result-type name="jsonActionRedirect" class="org.apache.struts2.json.JSONActionRedirectResult"/>
</result-types>
<interceptors>
@@ -0,0 +1,105 @@
package org.apache.struts2.json;
import org.apache.struts2.StrutsStatics;
import org.apache.struts2.StrutsTestCase;
import org.apache.struts2.dispatcher.mapper.DefaultActionMapper;
import org.apache.struts2.views.util.DefaultUrlHelper;
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.config.entities.ActionConfig;
import com.opensymphony.xwork2.mock.MockActionInvocation;
import com.opensymphony.xwork2.mock.MockActionProxy;
import com.opensymphony.xwork2.util.ValueStack;
public class JSONActionRedirectResultTest extends StrutsTestCase {
MockActionInvocation invocation;
MockHttpServletResponse response;
MockServletContext servletContext;
ActionContext context;
ValueStack stack;
MockHttpServletRequest request;
public void testNormalRedirect() throws Exception {
JSONActionRedirectResult result = new JSONActionRedirectResult();
result.setActionName("targetAction");
result.setActionMapper(new DefaultActionMapper());
result.setUrlHelper(new DefaultUrlHelper());
Object action = new Object();
stack.push(action);
this.invocation.setAction(action);
result.execute(this.invocation);
String content = response.getContentAsString();
assertEquals("", content);
String location = response.getHeader("Location");
assertEquals("/targetAction.action", location);
assertEquals(302, response.getStatus());
}
public void testJsonRedirect() throws Exception {
JSONActionRedirectResult result = new JSONActionRedirectResult();
result.setActionName("targetAction");
result.setActionMapper(new DefaultActionMapper());
result.setUrlHelper(new DefaultUrlHelper());
request.setParameter("struts.enableJSONValidation", "true");
request.setParameter("struts.validateOnly", "false");
Object action = new Object();
stack.push(action);
this.invocation.setAction(action);
result.execute(this.invocation);
String content = response.getContentAsString();
assertEquals("{\"location\": \"/targetAction.action\"}", content);
assertEquals(200, response.getStatus());
}
public void testValidateOnlyFalse() throws Exception {
JSONActionRedirectResult result = new JSONActionRedirectResult();
result.setActionName("targetAction");
result.setActionMapper(new DefaultActionMapper());
result.setUrlHelper(new DefaultUrlHelper());
request.setParameter("struts.enableJSONValidation", "true");
request.setParameter("struts.validateOnly", "true");
Object action = new Object();
stack.push(action);
this.invocation.setAction(action);
result.execute(this.invocation);
String content = response.getContentAsString();
assertEquals("", content);
String location = response.getHeader("Location");
assertEquals("/targetAction.action", location);
assertEquals(302, response.getStatus());
}
@Override
protected void setUp() throws Exception {
super.setUp();
this.response = new MockHttpServletResponse();
this.request = new MockHttpServletRequest();
this.context = ActionContext.getContext();
this.context.put(StrutsStatics.HTTP_RESPONSE, this.response);
this.context.put(StrutsStatics.HTTP_REQUEST, this.request);
this.stack = context.getValueStack();
this.servletContext = new MockServletContext();
this.context.put(StrutsStatics.SERVLET_CONTEXT, this.servletContext);
this.invocation = new MockActionInvocation();
this.invocation.setInvocationContext(this.context);
this.invocation.setStack(this.stack);
MockActionProxy mockActionProxy = new MockActionProxy();
mockActionProxy.setConfig(new ActionConfig.Builder(null, null, null).build());
this.invocation.setProxy(mockActionProxy);
}
}