From bc81e66e91f94ee542aedb10630d58da45c1809f Mon Sep 17 00:00:00 2001 From: Lukasz Lenart Date: Wed, 2 Jan 2013 21:44:41 +0000 Subject: [PATCH] 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 --- .../validators/DateRangeFieldValidator.java | 132 ++++++++++++------ .../validator/DateRangeValidatorTest.java | 26 +++- .../DateRangeFieldValidatorTest.java | 83 +++++++++++ 3 files changed, 190 insertions(+), 51 deletions(-) create mode 100644 xwork-core/src/test/java/com/opensymphony/xwork2/validator/validators/DateRangeFieldValidatorTest.java diff --git a/xwork-core/src/main/java/com/opensymphony/xwork2/validator/validators/DateRangeFieldValidator.java b/xwork-core/src/main/java/com/opensymphony/xwork2/validator/validators/DateRangeFieldValidator.java index 24d30b925..4903400cf 100644 --- a/xwork-core/src/main/java/com/opensymphony/xwork2/validator/validators/DateRangeFieldValidator.java +++ b/xwork-core/src/main/java/com/opensymphony/xwork2/validator/validators/DateRangeFieldValidator.java @@ -17,20 +17,19 @@ package com.opensymphony.xwork2.validator.validators; import java.util.Date; - /** * - * + * * Field Validator that checks if the date supplied is within a specific range. - * + * * NOTE: If no date converter is specified, XWorkBasicConverter will kick - * in to do the date conversion, which by default using the Date.SHORT format using - * the a programmatically specified locale else falling back to the system + * in to do the date conversion, which by default using the Date.SHORT format using + * the a problematically specified locale else falling back to the system * default locale. - * - * + * + * * - * + * *

* * @@ -38,50 +37,64 @@ import java.util.Date; *

  • fieldName - The field name this validator is validating. Required if using Plain-Validator Syntax otherwise not required
  • *
  • min - the min date range. If not specified will not be checked.
  • *
  • max - the max date range. If not specified will not be checked.
  • + *
  • parse - if set to true, minExpression and maxExpression will be evaluated to find min/max
  • + *
  • minExpression - expression to calculate the minimum value (if none is specified, it will not be checked)
  • + *
  • maxExpression - expression to calculate the maximum value (if none is specified, it will not be checked)
  • * + * + * 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! + * * - * - * + * + * *
      * 
    - *    <validators>
    - *    		<!-- Plain Validator syntax -->
    - *    		<validator type="date">
    - *    	        <param name="fieldName">birthday</param>
    - *              <param name="min">01/01/1990</param>
    - *              <param name="max">01/01/2000</param>
    - *              <message>Birthday must be within ${min} and ${max}</message>
    - *    		</validator>
    - *    
    - *          <!-- Field Validator Syntax -->
    - *          <field name="birthday">
    - *          	<field-validator type="date">
    - *           	    <param name="min">01/01/1990</param>
    - *                  <param name="max">01/01/2000</param>
    - *                  <message>Birthday must be within ${min} and ${max}</message>
    - *          	</field>
    - *          </field>
    - *    
    - *    </validators>
    + * <validators>
    + *     <!-- Plain Validator syntax -->
    + *     <validator type="date">
    + *         <param name="fieldName">birthday</param>
    + *         <param name="min">01/01/1990</param>
    + *         <param name="max">01/01/2000</param>
    + *         <message>Birthday must be within ${min} and ${max}</message>
    + *     </validator>
    + *
    + *     <!-- Field Validator Syntax -->
    + *     <field name="birthday">
    + *         <field-validator type="date">
    + *      	   <param name="min">01/01/1990</param>
    + *             <param name="max">01/01/2000</param>
    + *             <message>Birthday must be within ${min} and ${max}</message>
    + *     	   </field>
    + *     </field>
    + *
    + *     <!-- Field Validator Syntax with expression -->
    + *     <field name="birthday">
    + *         <field-validator type="date">
    + *             <param name="parse">true</param>
    + *             <param name="minExpression">${minValue}</param> <!-- will be evaluated as: Date getMinValue() -->
    + *             <param name="maxExpression">${maxValue}</param> <!-- will be evaluated as: Date getMaxValue() -->
    + *             <message>Age needs to be between ${minExpression} and ${maxExpression}</message>
    + *         </field-validator>
    + *     </field>
    + * </validators>
      * 
      * 
    - * + * * * @author Jason Carreira * @version $Date$ $Id$ */ -public class DateRangeFieldValidator extends AbstractRangeValidator { +public class DateRangeFieldValidator extends AbstractRangeValidator { - 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(); + } + } diff --git a/xwork-core/src/test/java/com/opensymphony/xwork2/validator/DateRangeValidatorTest.java b/xwork-core/src/test/java/com/opensymphony/xwork2/validator/DateRangeValidatorTest.java index b57a482af..2c8de2cae 100644 --- a/xwork-core/src/test/java/com/opensymphony/xwork2/validator/DateRangeValidatorTest.java +++ b/xwork-core/src/test/java/com/opensymphony/xwork2/validator/DateRangeValidatorTest.java @@ -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 context = new HashMap(); + HashMap params = new HashMap(); + 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> errors = ((ValidationAware) proxy.getAction()).getFieldErrors(); - List errorMessages = (List) errors.get("date"); + List 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 { diff --git a/xwork-core/src/test/java/com/opensymphony/xwork2/validator/validators/DateRangeFieldValidatorTest.java b/xwork-core/src/test/java/com/opensymphony/xwork2/validator/validators/DateRangeFieldValidatorTest.java new file mode 100644 index 000000000..37454593b --- /dev/null +++ b/xwork-core/src/test/java/com/opensymphony/xwork2/validator/validators/DateRangeFieldValidatorTest.java @@ -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; + } + +}