WW-3889 adds support to specify min and max constraints as expressions

git-svn-id: https://svn.apache.org/repos/asf/struts/struts2/trunk@1428077 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Lukasz Lenart
2013-01-02 21:44:41 +00:00
parent 5d1edd6cc6
commit bc81e66e91
3 changed files with 190 additions and 51 deletions
@@ -17,20 +17,19 @@ package com.opensymphony.xwork2.validator.validators;
import java.util.Date;
/**
* <!-- START SNIPPET: javadoc -->
*
*
* Field Validator that checks if the date supplied is within a specific range.
*
*
* <b>NOTE:</b> If no date converter is specified, XWorkBasicConverter will kick
* in to do the date conversion, which by default using the <code>Date.SHORT</code> format using
* the a programmatically specified locale else falling back to the system
* in to do the date conversion, which by default using the <code>Date.SHORT</code> format using
* the a problematically specified locale else falling back to the system
* default locale.
*
*
*
*
* <!-- END SNIPPET: javadoc -->
*
*
* <p/>
*
* <!-- START SNIPPET: parameters -->
@@ -38,50 +37,64 @@ import java.util.Date;
* <li>fieldName - The field name this validator is validating. Required if using Plain-Validator Syntax otherwise not required</li>
* <li>min - the min date range. If not specified will not be checked.</li>
* <li>max - the max date range. If not specified will not be checked.</li>
* <li>parse - if set to true, minExpression and maxExpression will be evaluated to find min/max</li>
* <li>minExpression - expression to calculate the minimum value (if none is specified, it will not be checked) </li>
* <li>maxExpression - expression to calculate the maximum value (if none is specified, it will not be checked) </li>
* </ul>
*
* You can either use the min / max value or minExpression / maxExpression (when parse is set to true) -
* using expression can be slightly slower, see the example below.
* WARNING! Do not use ${minExpression} and ${maxExpression} as an expression as this will turn into infinitive loop!
*
* <!-- END SNIPPET: parameters -->
*
*
*
*
* <pre>
* <!-- START SNIPPET: examples -->
* &lt;validators>
* &lt;!-- Plain Validator syntax --&gt;
* &lt;validator type="date"&gt;
* &lt;param name="fieldName"&gt;birthday&lt;/param&gt;
* &lt;param name="min"&gt;01/01/1990&lt;/param&gt;
* &lt;param name="max"&gt;01/01/2000&lt;/param&gt;
* &lt;message&gt;Birthday must be within ${min} and ${max}&lt;/message&gt;
* &lt;/validator&gt;
*
* &lt;!-- Field Validator Syntax --&gt;
* &lt;field name="birthday"&gt;
* &lt;field-validator type="date"&gt;
* &lt;param name="min"&gt;01/01/1990&lt;/param&gt;
* &lt;param name="max"&gt;01/01/2000&lt;/param&gt;
* &lt;message&gt;Birthday must be within ${min} and ${max}&lt;/message&gt;
* &lt;/field&gt;
* &lt;/field&gt;
*
* &lt;/validators&gt;
* &lt;validators>
* &lt;!-- Plain Validator syntax --&gt;
* &lt;validator type="date"&gt;
* &lt;param name="fieldName"&gt;birthday&lt;/param&gt;
* &lt;param name="min"&gt;01/01/1990&lt;/param&gt;
* &lt;param name="max"&gt;01/01/2000&lt;/param&gt;
* &lt;message&gt;Birthday must be within ${min} and ${max}&lt;/message&gt;
* &lt;/validator&gt;
*
* &lt;!-- Field Validator Syntax --&gt;
* &lt;field name="birthday"&gt;
* &lt;field-validator type="date"&gt;
* &lt;param name="min"&gt;01/01/1990&lt;/param&gt;
* &lt;param name="max"&gt;01/01/2000&lt;/param&gt;
* &lt;message&gt;Birthday must be within ${min} and ${max}&lt;/message&gt;
* &lt;/field&gt;
* &lt;/field&gt;
*
* &lt;!-- Field Validator Syntax with expression --&gt;
* &lt;field name="birthday"&gt;
* &lt;field-validator type="date"&gt;
* &lt;param name="parse"&gt;true&lt;/param&gt;
* &lt;param name="minExpression"&gt;${minValue}&lt;/param&gt; &lt;!-- will be evaluated as: Date getMinValue() --&gt;
* &lt;param name="maxExpression"&gt;${maxValue}&lt;/param&gt; &lt;!-- will be evaluated as: Date getMaxValue() --&gt;
* &lt;message&gt;Age needs to be between ${minExpression} and ${maxExpression}&lt;/message&gt;
* &lt;/field-validator&gt;
* &lt;/field&gt;
* &lt;/validators&gt;
* <!-- END SNIPPET: examples -->
* </pre>
*
*
*
* @author Jason Carreira
* @version $Date$ $Id$
*/
public class DateRangeFieldValidator extends AbstractRangeValidator {
public class DateRangeFieldValidator extends AbstractRangeValidator<Date> {
private Date max;
private Date min;
private Date max;
private String minExpression;
private String maxExpression;
public void setMax(Date max) {
this.max = max;
}
public Date getMax() {
return max;
public DateRangeFieldValidator() {
super(Date.class);
}
public void setMin(Date min) {
@@ -92,13 +105,44 @@ public class DateRangeFieldValidator extends AbstractRangeValidator {
return min;
}
@Override
protected Comparable getMaxComparatorValue() {
return max;
public String getMinExpression() {
return minExpression;
}
public void setMinExpression(String minExpression) {
this.minExpression = minExpression;
}
@Override
protected Comparable getMinComparatorValue() {
return min;
public Date getMinComparatorValue() {
if (parse) {
return parse(getMinExpression());
}
return getMin();
}
public void setMax(Date max) {
this.max = max;
}
public Date getMax() {
return max;
}
public String getMaxExpression() {
return maxExpression;
}
public void setMaxExpression(String maxExpression) {
this.maxExpression = maxExpression;
}
@Override
public Date getMaxComparatorValue() {
if (parse) {
return parse(getMaxExpression());
}
return getMax();
}
}
@@ -15,13 +15,19 @@
*/
package com.opensymphony.xwork2.validator;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionProxy;
import com.opensymphony.xwork2.ValidationAware;
import com.opensymphony.xwork2.XWorkTestCase;
import com.opensymphony.xwork2.config.providers.MockConfigurationProvider;
import com.opensymphony.xwork2.validator.validators.DateRangeFieldValidator;
import java.util.*;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
/**
@@ -40,19 +46,25 @@ public class DateRangeValidatorTest extends XWorkTestCase {
* because the action config sets date to 12/20/2002 while expected range is Dec 22-25.
*/
public void testRangeValidation() throws Exception {
ActionProxy proxy = actionProxyFactory.createActionProxy("", MockConfigurationProvider.VALIDATION_ACTION_NAME, null);
Calendar date = Calendar.getInstance();
date.set(2002, Calendar.NOVEMBER, 20);
Map<String, Object> context = new HashMap<String, Object>();
HashMap<String, Object> params = new HashMap<String, Object>();
params.put("date", date.getTime());
context.put(ActionContext.PARAMETERS, params);
ActionProxy proxy = actionProxyFactory.createActionProxy("", MockConfigurationProvider.VALIDATION_ACTION_NAME, context);
proxy.execute();
assertTrue(((ValidationAware) proxy.getAction()).hasFieldErrors());
Map errors = ((ValidationAware) proxy.getAction()).getFieldErrors();
Iterator it = errors.entrySet().iterator();
Map<String, List<String>> errors = ((ValidationAware) proxy.getAction()).getFieldErrors();
List errorMessages = (List) errors.get("date");
List<String> errorMessages = errors.get("date");
assertNotNull("Expected date range validation error message.", errorMessages);
assertEquals(1, errorMessages.size());
String errorMessage = (String) errorMessages.get(0);
assertNotNull(errorMessage);
String errorMessage = errorMessages.get(0);
assertEquals("The date must be between 12-22-2002 and 12-25-2002.", errorMessage);
}
public void testGetSetMinMax() throws Exception {
@@ -0,0 +1,83 @@
package com.opensymphony.xwork2.validator.validators;
import com.opensymphony.xwork2.XWorkTestCase;
import com.opensymphony.xwork2.util.ValueStack;
import com.opensymphony.xwork2.util.ValueStackFactory;
import com.opensymphony.xwork2.validator.GenericValidatorContext;
import com.opensymphony.xwork2.validator.ValidatorContext;
import java.util.Calendar;
import java.util.Date;
public class DateRangeFieldValidatorTest extends XWorkTestCase {
public void testPassValidation() throws Exception {
// given
ValidationAction action = prepareAction(createDate(2013, 6, 6));
ValidatorContext context = new GenericValidatorContext(action);
DateRangeFieldValidator validator = prepareValidator(action, context);
// when
validator.validate(action);
// then
assertTrue(context.getFieldErrors().size() == 0);
}
public void testMinValidation() throws Exception {
// given
ValidationAction action = prepareAction(createDate(2012, Calendar.MARCH, 3));
ValidatorContext context = new GenericValidatorContext(action);
DateRangeFieldValidator validator = prepareValidator(action, context);
// when
validator.validate(action);
// then
assertTrue(context.getFieldErrors().size() == 1);
assertEquals("Max is 12/12/13, min is 1/1/13 but value is 3/3/12", context.getFieldErrors().get("dateRange").get(0));
}
public void testMaxValidation() throws Exception {
// given
ValidationAction action = prepareAction(createDate(2014, Calendar.APRIL, 4));
ValidatorContext context = new GenericValidatorContext(action);
DateRangeFieldValidator validator = prepareValidator(action, context);
// when
validator.validate(action);
// then
assertTrue(context.getFieldErrors().size() == 1);
assertEquals("Max is 12/12/13, min is 1/1/13 but value is 4/4/14", context.getFieldErrors().get("dateRange").get(0));
}
private ValidationAction prepareAction(Date range) {
ValidationAction action = new ValidationAction();
action.setDateMinValue(createDate(2013, Calendar.JANUARY, 1));
action.setDateMaxValue(createDate(2013, Calendar.DECEMBER, 12));
action.setDateRange(range);
return action;
}
private Date createDate(int year, int month, int day) {
Calendar cal = Calendar.getInstance();
cal.set(year, month, day);
return cal.getTime();
}
private DateRangeFieldValidator prepareValidator(ValidationAction action, ValidatorContext context) {
DateRangeFieldValidator validator = new DateRangeFieldValidator();
validator.setMaxExpression("${dateMaxValue}");
validator.setMinExpression("${dateMinValue}");
ValueStack valueStack = container.getInstance(ValueStackFactory.class).createValueStack();
valueStack.push(action);
validator.setValueStack(valueStack);
validator.setValidatorContext(context);
validator.setFieldName("dateRange");
validator.setParse(true);
validator.setDefaultMessage("Max is ${dateMaxValue}, min is ${dateMinValue} but value is ${dateRange}");
return validator;
}
}