diff --git a/xwork-core/src/main/java/com/opensymphony/xwork2/validator/AnnotationValidationConfigurationBuilder.java b/xwork-core/src/main/java/com/opensymphony/xwork2/validator/AnnotationValidationConfigurationBuilder.java index d26e5b410..fde9f8172 100644 --- a/xwork-core/src/main/java/com/opensymphony/xwork2/validator/AnnotationValidationConfigurationBuilder.java +++ b/xwork-core/src/main/java/com/opensymphony/xwork2/validator/AnnotationValidationConfigurationBuilder.java @@ -16,6 +16,7 @@ package com.opensymphony.xwork2.validator; import com.opensymphony.xwork2.validator.annotations.*; +import org.apache.commons.lang3.StringUtils; import java.lang.annotation.Annotation; import java.lang.reflect.Method; @@ -559,12 +560,16 @@ public class AnnotationValidationConfigurationBuilder { .build(); } - private Date parseDateString(String value) { + private Date parseDateString(String value, String format) { + SimpleDateFormat d0 = null; + if (StringUtils.isNotEmpty(format)) { + d0 = new SimpleDateFormat(format); + } SimpleDateFormat d1 = (SimpleDateFormat) DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.LONG, Locale.getDefault()); SimpleDateFormat d2 = (SimpleDateFormat)DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM, Locale.getDefault()); SimpleDateFormat d3 = (SimpleDateFormat)DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.getDefault()); - SimpleDateFormat[] dfs = {d1, d2, d3}; + SimpleDateFormat[] dfs = (d0 != null ? new SimpleDateFormat[]{d0, d1, d2, d3} : new SimpleDateFormat[]{d1, d2, d3}); for (SimpleDateFormat df : dfs) try { Date check = df.parse(value); @@ -574,7 +579,6 @@ public class AnnotationValidationConfigurationBuilder { } catch (ParseException ignore) { } return null; - } private ValidatorConfig processRequiredStringValidatorAnnotation(RequiredStringValidator v, String fieldName, String methodName) { @@ -767,12 +771,19 @@ public class AnnotationValidationConfigurationBuilder { params.put("fieldName", v.fieldName()); } if ( v.min() != null && v.min().length() > 0) { - final Date minDate = parseDateString(v.min()); - params.put("min", String.valueOf(minDate == null ? v.min() : minDate)); + final Date minDate = parseDateString(v.min(), v.dateFormat()); + params.put("min", minDate == null ? v.min() : minDate); } if ( v.max() != null && v.max().length() > 0) { - final Date maxDate = parseDateString(v.max()); - params.put("max", String.valueOf(maxDate == null ? v.max() : maxDate)); + final Date maxDate = parseDateString(v.max(), v.dateFormat()); + params.put("max", maxDate == null ? v.max() : maxDate); + } + + if (StringUtils.isNotEmpty(v.minExpression())) { + params.put("minExpression", v.minExpression()); + } + if (StringUtils.isNotEmpty(v.maxExpression())) { + params.put("maxExpression", v.maxExpression()); } validatorFactory.lookupRegisteredValidatorType(validatorType); @@ -782,6 +793,7 @@ public class AnnotationValidationConfigurationBuilder { .shortCircuit(v.shortCircuit()) .defaultMessage(v.message()) .messageKey(v.key()) + .messageParams(v.messageParams()) .build(); } diff --git a/xwork-core/src/main/java/com/opensymphony/xwork2/validator/annotations/DateRangeFieldValidator.java b/xwork-core/src/main/java/com/opensymphony/xwork2/validator/annotations/DateRangeFieldValidator.java index fd47fce8d..c6b81b70f 100644 --- a/xwork-core/src/main/java/com/opensymphony/xwork2/validator/annotations/DateRangeFieldValidator.java +++ b/xwork-core/src/main/java/com/opensymphony/xwork2/validator/annotations/DateRangeFieldValidator.java @@ -55,6 +55,12 @@ import java.lang.annotation.Target; * i18n key from language specific properties file. * * + * messageParams + * no + *   + * Additional params to be used to customize message - will be evaluated against the Value Stack + * + * * fieldName * no *   @@ -109,11 +115,26 @@ public @interface DateRangeFieldValidator { */ String min() default ""; + /** + * An expression which will be evaluated against the Value Stack to get the min value + */ + String minExpression() default ""; + /** * Date property. The maximum date can be. */ String max() default ""; + /** + * An expression which will be evaluated against the Value Stack to get the max value + */ + String maxExpression() default ""; + + /** + * Date format used to parse min and mac value + */ + String dateFormat() default ""; + /** * The default error message for this validator. * NOTE: It is required to set a message, if you are not using the message key for 18n lookup! @@ -125,6 +146,11 @@ public @interface DateRangeFieldValidator { */ String key() default ""; + /** + * Additional params to be used to customize message - will be evaluated against the Value Stack + */ + String[] messageParams() default {}; + /** * The optional fieldName for SIMPLE validator types. */ diff --git a/xwork-core/src/main/java/com/opensymphony/xwork2/validator/validators/AbstractRangeValidator.java b/xwork-core/src/main/java/com/opensymphony/xwork2/validator/validators/AbstractRangeValidator.java index 2ffaaba2d..aa17a0e8b 100644 --- a/xwork-core/src/main/java/com/opensymphony/xwork2/validator/validators/AbstractRangeValidator.java +++ b/xwork-core/src/main/java/com/opensymphony/xwork2/validator/validators/AbstractRangeValidator.java @@ -18,6 +18,7 @@ package com.opensymphony.xwork2.validator.validators; import com.opensymphony.xwork2.util.logging.Logger; import com.opensymphony.xwork2.util.logging.LoggerFactory; import com.opensymphony.xwork2.validator.ValidationException; +import org.apache.commons.lang3.StringUtils; /** @@ -33,7 +34,9 @@ public abstract class AbstractRangeValidator extends Field private final Class type; private T min; + private String minExpression; private T max; + private String maxExpression; protected AbstractRangeValidator(Class type) { this.type = type; @@ -67,14 +70,20 @@ public abstract class AbstractRangeValidator extends Field } public T getMin() { - return min; + if (min != null) { + return min; + } else if (StringUtils.isNotEmpty(minExpression)) { + return (T) parse(minExpression, type); + } else { + return null; + } } public void setMinExpression(String minExpression) { if (LOG.isDebugEnabled()) { LOG.debug("${minExpression} was defined as [#0]", minExpression); } - this.min = (T) parse(minExpression, type); + this.minExpression = minExpression; } public void setMax(T max) { @@ -82,14 +91,20 @@ public abstract class AbstractRangeValidator extends Field } public T getMax() { - return max; + if (max != null) { + return max; + } else if (StringUtils.isNotEmpty(maxExpression)) { + return (T) parse(maxExpression, type); + } else { + return null; + } } public void setMaxExpression(String maxExpression) { if (LOG.isDebugEnabled()) { LOG.debug("${maxExpression} was defined as [#0]", maxExpression); } - this.max = (T) parse(maxExpression, type); + this.maxExpression = maxExpression; } } diff --git a/xwork-core/src/test/java/com/opensymphony/xwork2/validator/AnnotationValidationAction.java b/xwork-core/src/test/java/com/opensymphony/xwork2/validator/AnnotationValidationAction.java index 62608fe63..da9ee67c3 100644 --- a/xwork-core/src/test/java/com/opensymphony/xwork2/validator/AnnotationValidationAction.java +++ b/xwork-core/src/test/java/com/opensymphony/xwork2/validator/AnnotationValidationAction.java @@ -4,6 +4,7 @@ import com.opensymphony.xwork2.ActionSupport; import com.opensymphony.xwork2.validator.annotations.ConditionalVisitorFieldValidator; import com.opensymphony.xwork2.validator.annotations.ConversionErrorFieldValidator; import com.opensymphony.xwork2.validator.annotations.CustomValidator; +import com.opensymphony.xwork2.validator.annotations.DateRangeFieldValidator; import com.opensymphony.xwork2.validator.annotations.RegexFieldValidator; import com.opensymphony.xwork2.validator.annotations.ValidationParameter; @@ -26,6 +27,8 @@ public class AnnotationValidationAction extends ActionSupport { @ValidationParameter(name = "value", value = "1") } ) + @DateRangeFieldValidator(fieldName = "foo", key = "date.foo", max = "2012", min = "2011", dateFormat = "yyyy", + message = "Foo isn't in range!", shortCircuit = true, messageParams = {"one", "two", "three"}) public String execute() { return SUCCESS; } diff --git a/xwork-core/src/test/java/com/opensymphony/xwork2/validator/AnnotationValidationConfigurationBuilderTest.java b/xwork-core/src/test/java/com/opensymphony/xwork2/validator/AnnotationValidationConfigurationBuilderTest.java index e957d2106..920aea27c 100644 --- a/xwork-core/src/test/java/com/opensymphony/xwork2/validator/AnnotationValidationConfigurationBuilderTest.java +++ b/xwork-core/src/test/java/com/opensymphony/xwork2/validator/AnnotationValidationConfigurationBuilderTest.java @@ -16,8 +16,11 @@ import com.opensymphony.xwork2.util.ValueStackFactory; import com.opensymphony.xwork2.util.location.LocatableProperties; import com.opensymphony.xwork2.validator.validators.ConditionalVisitorFieldValidator; import com.opensymphony.xwork2.validator.validators.ConversionErrorFieldValidator; +import com.opensymphony.xwork2.validator.validators.DateRangeFieldValidator; import com.opensymphony.xwork2.validator.validators.RegexFieldValidator; +import java.text.ParseException; +import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.HashMap; import java.util.List; @@ -36,7 +39,7 @@ public class AnnotationValidationConfigurationBuilderTest extends XWorkTestCase List validators = manager.getValidators(AnnotationValidationAction.class, null); // then - assertEquals(validators.size(), 4); + assertEquals(validators.size(), 5); for (Validator validator : validators) { validate(validator); } @@ -53,14 +56,14 @@ public class AnnotationValidationConfigurationBuilderTest extends XWorkTestCase ValueStack valueStack = container.getInstance(ValueStackFactory.class).createValueStack(); valueStack.push(new AnnotationValidationExpAction()); - assertEquals(validators.size(), 4); + assertEquals(validators.size(), 5); for (Validator validator : validators) { validator.setValueStack(valueStack); validate(validator); } } - private void validate(Validator validator) { + private void validate(Validator validator) throws Exception { if (validator.getValidatorType().equals("regex")) { validateRegexValidator((RegexFieldValidator) validator); } else if (validator.getValidatorType().equals("conditionalvisitor")) { @@ -69,9 +72,21 @@ public class AnnotationValidationConfigurationBuilderTest extends XWorkTestCase validateConversionFieldErrorVisitorValidator((ConversionErrorFieldValidator) validator); } else if (validator.getValidatorType().equals("myValidator")) { validateMyValidator((MyValidator) validator); + } else if (validator.getValidatorType().equals("date")) { + validateDateRangeFieldValidator((DateRangeFieldValidator) validator); } } + private void validateDateRangeFieldValidator(DateRangeFieldValidator validator) throws ParseException { + assertEquals("foo", validator.getFieldName()); + assertEquals("Foo isn't in range!", validator.getDefaultMessage()); + assertEquals("date.foo", validator.getMessageKey()); + assertEquals(true, validator.isShortCircuit()); + assertTrue(Arrays.equals(new String[]{"one", "two", "three"}, validator.getMessageParameters())); + assertEquals(new SimpleDateFormat("yyyy").parse("2011"), validator.getMin()); + assertEquals(new SimpleDateFormat("yyyy").parse("2012"), validator.getMax()); + } + private void validateMyValidator(MyValidator validator) { assertEquals("Foo is invalid!", validator.getDefaultMessage()); assertEquals("foo", validator.getFieldName()); diff --git a/xwork-core/src/test/java/com/opensymphony/xwork2/validator/AnnotationValidationExpAction.java b/xwork-core/src/test/java/com/opensymphony/xwork2/validator/AnnotationValidationExpAction.java index c18a7f91d..9a485e869 100644 --- a/xwork-core/src/test/java/com/opensymphony/xwork2/validator/AnnotationValidationExpAction.java +++ b/xwork-core/src/test/java/com/opensymphony/xwork2/validator/AnnotationValidationExpAction.java @@ -4,9 +4,14 @@ import com.opensymphony.xwork2.ActionSupport; import com.opensymphony.xwork2.validator.annotations.ConditionalVisitorFieldValidator; import com.opensymphony.xwork2.validator.annotations.ConversionErrorFieldValidator; import com.opensymphony.xwork2.validator.annotations.CustomValidator; +import com.opensymphony.xwork2.validator.annotations.DateRangeFieldValidator; import com.opensymphony.xwork2.validator.annotations.RegexFieldValidator; import com.opensymphony.xwork2.validator.annotations.ValidationParameter; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; + /** * Sets up all available validation annotations with params as expressions */ @@ -26,6 +31,8 @@ public class AnnotationValidationExpAction extends ActionSupport { @ValidationParameter(name = "value", value = "1") } ) + @DateRangeFieldValidator(fieldName = "foo", key = "date.foo", maxExpression = "${dateMax}", minExpression = "${dateMin}", dateFormat = "yyyy", + message = "Foo isn't in range!", shortCircuit = true, messageParams = {"one", "two", "three"}) public String execute() { return SUCCESS; } @@ -42,4 +49,12 @@ public class AnnotationValidationExpAction extends ActionSupport { return false; } + public Date getDateMin() throws ParseException { + return new SimpleDateFormat("yyyy").parse("2011"); + } + + public Date getDateMax() throws ParseException { + return new SimpleDateFormat("yyyy").parse("2012"); + } + }