diff options
author | Artur Signell <artur@vaadin.com> | 2011-12-14 22:09:43 +0200 |
---|---|---|
committer | Artur Signell <artur@vaadin.com> | 2011-12-14 22:40:57 +0200 |
commit | e137e9fdd2c5182777a0419b8cf8e146fc33fd18 (patch) | |
tree | 0e7b248aa2e5f7fb612d851375a8ecaa5dfc0ece | |
parent | 0bcd80a5ec66ca4e17fd689a5beab8de5c76559a (diff) | |
download | vaadin-framework-e137e9fdd2c5182777a0419b8cf8e146fc33fd18.tar.gz vaadin-framework-e137e9fdd2c5182777a0419b8cf8e146fc33fd18.zip |
#8110 Validation is now done on the converted value
Added type to AbstractValidator and automatic type checking so sub
classes get the correct type automatically
Added a RangeValidator that work with any type that is Comparable
CompositeValidator no longer extends AbstractValidator as it does
not validate in the same way as AbstractValidator does
18 files changed, 728 insertions, 113 deletions
diff --git a/src/com/vaadin/data/validator/AbstractStringValidator.java b/src/com/vaadin/data/validator/AbstractStringValidator.java index c47ca15d77..5267cc7b7b 100644 --- a/src/com/vaadin/data/validator/AbstractStringValidator.java +++ b/src/com/vaadin/data/validator/AbstractStringValidator.java @@ -4,9 +4,7 @@ package com.vaadin.data.validator; /** - * Validator base class for validating strings. See - * {@link com.vaadin.data.validator.AbstractValidator} for more information. - * + * Validator base class for validating strings. * <p> * To include the value that failed validation in the exception message you can * use "{0}" in the error message. This will be replaced with the failed value @@ -15,12 +13,11 @@ package com.vaadin.data.validator; * </p> * * @author Vaadin Ltd. - * @version - * @VERSION@ + * @version @VERSION@ * @since 5.4 */ @SuppressWarnings("serial") -public abstract class AbstractStringValidator extends AbstractValidator { +public abstract class AbstractStringValidator extends AbstractValidator<String> { /** * Constructs a validator for strings. @@ -38,36 +35,8 @@ public abstract class AbstractStringValidator extends AbstractValidator { super(errorMessage); } - /** - * Tests if the given value is a valid string. - * <p> - * Null values are always accepted. Values that are not {@link String}s are - * converted using {@link #toString()}. Then {@link #isValidString(String)} - * is used to validate the value. - * </p> - * - * @param value - * the value to check - * @return true if the value (or its toString()) is a valid string, false - * otherwise - */ @Override - protected boolean isValidValue(Object value) { - if (value == null) { - return true; - } - if (!(value instanceof String)) { - value = String.valueOf(value); - } - return isValidString((String) value); + public Class<String> getType() { + return String.class; } - - /** - * Checks if the given string is valid. - * - * @param value - * String to check. Can never be null. - * @return true if the string is valid, false otherwise - */ - protected abstract boolean isValidString(String value); } diff --git a/src/com/vaadin/data/validator/AbstractValidator.java b/src/com/vaadin/data/validator/AbstractValidator.java index 2bf2edbecc..27eaaca485 100644 --- a/src/com/vaadin/data/validator/AbstractValidator.java +++ b/src/com/vaadin/data/validator/AbstractValidator.java @@ -27,13 +27,14 @@ import com.vaadin.data.Validator; * applications. To check validity, {@link #validate(Object)} should be used. * </p> * + * @param <T> + * The type * @author Vaadin Ltd. * @version * @VERSION@ * @since 5.4 */ -@SuppressWarnings("serial") -public abstract class AbstractValidator implements Validator { +public abstract class AbstractValidator<T> implements Validator { /** * Error message that is included in an {@link InvalidValueException} if @@ -81,16 +82,36 @@ public abstract class AbstractValidator implements Validator { * @param value * @return */ - protected abstract boolean isValidValue(Object value); + protected abstract boolean isValidValue(T value); public void validate(Object value) throws InvalidValueException { - if (!isValidValue(value)) { - String message = errorMessage.replace("{0}", String.valueOf(value)); + // isValidType ensures that value can safely be cast to TYPE + if (!isValidType(value) || !isValidValue((T) value)) { + String message = getErrorMessage().replace("{0}", + String.valueOf(value)); throw new InvalidValueException(message); } } /** + * Checks the type of the value to validate to ensure it conforms with + * getType. Enables sub classes to handle the specific type instead of + * Object. + * + * @param value + * The value to check + * @return true if the value can safely be cast to the type specified by + * {@link #getType()} + */ + protected boolean isValidType(Object value) { + if (value == null) { + return true; + } + + return getType().isAssignableFrom(value.getClass()); + } + + /** * Returns the message to be included in the exception in case the value * does not validate. * @@ -112,4 +133,6 @@ public abstract class AbstractValidator implements Validator { public void setErrorMessage(String errorMessage) { this.errorMessage = errorMessage; } + + public abstract Class<T> getType(); } diff --git a/src/com/vaadin/data/validator/CompositeValidator.java b/src/com/vaadin/data/validator/CompositeValidator.java index 2dd5950cec..083af70f30 100644 --- a/src/com/vaadin/data/validator/CompositeValidator.java +++ b/src/com/vaadin/data/validator/CompositeValidator.java @@ -19,12 +19,11 @@ import com.vaadin.data.Validator; * <code>AND</code> and <code>OR</code>. * * @author Vaadin Ltd. - * @version - * @VERSION@ + * @version @VERSION@ * @since 3.0 */ @SuppressWarnings("serial") -public class CompositeValidator extends AbstractValidator { +public class CompositeValidator implements Validator { public enum CombinationMode { /** @@ -52,6 +51,8 @@ public class CompositeValidator extends AbstractValidator { @Deprecated public static final CombinationMode MODE_OR = CombinationMode.OR; + private String errorMessage; + /** * Operation mode. */ @@ -67,7 +68,7 @@ public class CompositeValidator extends AbstractValidator { * message. */ public CompositeValidator() { - super(""); + this(CombinationMode.AND, ""); } /** @@ -77,7 +78,7 @@ public class CompositeValidator extends AbstractValidator { * @param errorMessage */ public CompositeValidator(CombinationMode mode, String errorMessage) { - super(errorMessage); + setErrorMessage(errorMessage); setMode(mode); } @@ -100,7 +101,6 @@ public class CompositeValidator extends AbstractValidator { * @throws Validator.InvalidValueException * if the value is not valid. */ - @Override public void validate(Object value) throws Validator.InvalidValueException { switch (mode) { case AND: @@ -133,12 +133,6 @@ public class CompositeValidator extends AbstractValidator { } } - @Override - protected boolean isValidValue(Object value) { - // not used as validate() overridden - return false; - } - /** * Gets the mode of the validator. * @@ -171,10 +165,9 @@ public class CompositeValidator extends AbstractValidator { * Gets the error message for the composite validator. If the error message * is null, original error messages of the sub-validators are used instead. */ - @Override public String getErrorMessage() { - if (super.getErrorMessage() != null) { - return super.getErrorMessage(); + if (errorMessage != null) { + return errorMessage; } // TODO Return composite error message @@ -229,7 +222,7 @@ public class CompositeValidator extends AbstractValidator { * that must apply or null if none found. */ public Collection<Validator> getSubValidators(Class validatorType) { - if (mode != MODE_AND) { + if (mode != CombinationMode.AND) { return null; } @@ -251,4 +244,15 @@ public class CompositeValidator extends AbstractValidator { return found.isEmpty() ? null : found; } + /** + * Sets the message to be included in the exception in case the value does + * not validate. The exception message is typically shown to the end user. + * + * @param errorMessage + * the error message. + */ + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + } diff --git a/src/com/vaadin/data/validator/DateRangeValidator.java b/src/com/vaadin/data/validator/DateRangeValidator.java new file mode 100644 index 0000000000..36a607691e --- /dev/null +++ b/src/com/vaadin/data/validator/DateRangeValidator.java @@ -0,0 +1,37 @@ +package com.vaadin.data.validator;
+
+import java.util.Date;
+
+import com.vaadin.ui.DateField.Resolution;
+
+/**
+ * Validator for validating that a Date is inside a given range.
+ *
+ * @author Vaadin Ltd.
+ * @version
+ * @VERSION@
+ * @since 7.0
+ */
+public class DateRangeValidator extends RangeValidator<Date> {
+
+ /**
+ * Creates a validator for checking that an Date is within a given range.
+ *
+ * By default the range is inclusive i.e. both minValue and maxValue are
+ * valid values. Use {@link #setMinValueIncluded(boolean)} or
+ * {@link #setMaxValueIncluded(boolean)} to change it.
+ *
+ *
+ * @param errorMessage
+ * the message to display in case the value does not validate.
+ * @param minValue
+ * The minimum value to accept or null for no limit
+ * @param maxValue
+ * The maximum value to accept or null for no limit
+ */
+ public DateRangeValidator(String errorMessage, Date minValue,
+ Date maxValue, Resolution resolution) {
+ super(errorMessage, Date.class, minValue, maxValue);
+ }
+
+}
diff --git a/src/com/vaadin/data/validator/DoubleRangeValidator.java b/src/com/vaadin/data/validator/DoubleRangeValidator.java new file mode 100644 index 0000000000..91fcf004af --- /dev/null +++ b/src/com/vaadin/data/validator/DoubleRangeValidator.java @@ -0,0 +1,36 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.data.validator; + +/** + * Validator for validating that a {@link Double} is inside a given range. + * + * @author Vaadin Ltd. + * @version + * @VERSION@ + * @since 7.0 + */ +@SuppressWarnings("serial") +public class DoubleRangeValidator extends RangeValidator<Double> { + + /** + * Creates a validator for checking that an Double is within a given range. + * + * By default the range is inclusive i.e. both minValue and maxValue are + * valid values. Use {@link #setMinValueIncluded(boolean)} or + * {@link #setMaxValueIncluded(boolean)} to change it. + * + * + * @param errorMessage + * the message to display in case the value does not validate. + * @param minValue + * The minimum value to accept or null for no limit + * @param maxValue + * The maximum value to accept or null for no limit + */ + public DoubleRangeValidator(String errorMessage, Double minValue, Double maxValue) { + super(errorMessage, Double.class, minValue, maxValue); + } + +} diff --git a/src/com/vaadin/data/validator/DoubleValidator.java b/src/com/vaadin/data/validator/DoubleValidator.java index e90919c17d..f603f57480 100644 --- a/src/com/vaadin/data/validator/DoubleValidator.java +++ b/src/com/vaadin/data/validator/DoubleValidator.java @@ -12,7 +12,9 @@ package com.vaadin.data.validator; * @version * @VERSION@ * @since 5.4 + * @deprecated in Vaadin 7.0. Use an Double converter on the field instead. */ +@Deprecated @SuppressWarnings("serial") public class DoubleValidator extends AbstractStringValidator { @@ -22,13 +24,17 @@ public class DoubleValidator extends AbstractStringValidator { * * @param errorMessage * the message to display in case the value does not validate. + * @deprecated in Vaadin 7.0. Use a Double converter on the field instead + * and/or use a {@link DoubleRangeValidator} for validating that + * the value is inside a given range. */ + @Deprecated public DoubleValidator(String errorMessage) { super(errorMessage); } @Override - protected boolean isValidString(String value) { + protected boolean isValidValue(String value) { try { Double.parseDouble(value); return true; diff --git a/src/com/vaadin/data/validator/IntegerRangeValidator.java b/src/com/vaadin/data/validator/IntegerRangeValidator.java new file mode 100644 index 0000000000..c171dd97d8 --- /dev/null +++ b/src/com/vaadin/data/validator/IntegerRangeValidator.java @@ -0,0 +1,37 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.data.validator; + +/** + * Validator for validating that an {@link Integer} is inside a given range. + * + * @author Vaadin Ltd. + * @version + * @VERSION@ + * @since 5.4 + */ +@SuppressWarnings("serial") +public class IntegerRangeValidator extends RangeValidator<Integer> { + + /** + * Creates a validator for checking that an Integer is within a given range. + * + * By default the range is inclusive i.e. both minValue and maxValue are + * valid values. Use {@link #setMinValueIncluded(boolean)} or + * {@link #setMaxValueIncluded(boolean)} to change it. + * + * + * @param errorMessage + * the message to display in case the value does not validate. + * @param minValue + * The minimum value to accept or null for no limit + * @param maxValue + * The maximum value to accept or null for no limit + */ + public IntegerRangeValidator(String errorMessage, Integer minValue, + Integer maxValue) { + super(errorMessage, Integer.class, minValue, maxValue); + } + +} diff --git a/src/com/vaadin/data/validator/IntegerValidator.java b/src/com/vaadin/data/validator/IntegerValidator.java index 50b45b90ce..bf46497594 100644 --- a/src/com/vaadin/data/validator/IntegerValidator.java +++ b/src/com/vaadin/data/validator/IntegerValidator.java @@ -12,8 +12,10 @@ package com.vaadin.data.validator; * @version * @VERSION@ * @since 5.4 + * @deprecated in Vaadin 7.0. Use an Integer converter on the field instead. */ @SuppressWarnings("serial") +@Deprecated public class IntegerValidator extends AbstractStringValidator { /** @@ -22,14 +24,18 @@ public class IntegerValidator extends AbstractStringValidator { * * @param errorMessage * the message to display in case the value does not validate. + * @deprecated in Vaadin 7.0. Use an Integer converter on the field instead + * and/or use an {@link IntegerRangeValidator} for validating + * that the value is inside a given range. */ + @Deprecated public IntegerValidator(String errorMessage) { super(errorMessage); } @Override - protected boolean isValidString(String value) { + protected boolean isValidValue(String value) { try { Integer.parseInt(value); return true; diff --git a/src/com/vaadin/data/validator/RangeValidator.java b/src/com/vaadin/data/validator/RangeValidator.java new file mode 100644 index 0000000000..0847b8ed7b --- /dev/null +++ b/src/com/vaadin/data/validator/RangeValidator.java @@ -0,0 +1,172 @@ +package com.vaadin.data.validator;
+
+/**
+ * An base implementation for validating any objects that implement
+ * {@link Comparable}.
+ *
+ * Verifies that the value is of the given type and within the (optionally)
+ * given limits. Typically you want to use a sub class of this like
+ * {@link IntegerRangeValidator}, {@link DoubleRangeValidator} or
+ * {@link DateRangeValidator} in applications.
+ *
+ * @param <T>
+ * The type of Number to validate. Must implement Comparable so that
+ * minimum and maximum checks work.
+ * @author Vaadin Ltd.
+ * @version
+ * @VERSION@
+ * @since 7.0
+ */
+public class RangeValidator<T extends Comparable> extends AbstractValidator<T> {
+
+ private T minValue = null;
+ private boolean minValueIncluded = true;
+ private T maxValue = null;
+ private boolean maxValueIncluded = true;
+ private Class<T> type;
+
+ /**
+ * Creates a new range validator of the given type.
+ *
+ * @param errorMessage
+ * The error message to use if validation fails
+ * @param type
+ * The type of object the validator can validate.
+ * @param minValue
+ * The minimum value that should be accepted or null for no limit
+ * @param maxValue
+ * The maximum value that should be accepted or null for no limit
+ */
+ public RangeValidator(String errorMessage, Class<T> type, T minValue,
+ T maxValue) {
+ super(errorMessage);
+ this.type = type;
+ this.minValue = minValue;
+ this.maxValue = maxValue;
+ }
+
+ /**
+ * Checks if the minimum value is part of the accepted range
+ *
+ * @return true if the minimum value is part of the range, false otherwise
+ */
+ public boolean isMinValueIncluded() {
+ return minValueIncluded;
+ }
+
+ /**
+ * Sets if the minimum value is part of the accepted range
+ *
+ * @param minValueIncluded
+ * true if the minimum value should be part of the range, false
+ * otherwise
+ */
+ public void setMinValueIncluded(boolean minValueIncluded) {
+ this.minValueIncluded = minValueIncluded;
+ }
+
+ /**
+ * Checks if the maximum value is part of the accepted range
+ *
+ * @return true if the maximum value is part of the range, false otherwise
+ */
+ public boolean isMaxValueIncluded() {
+ return maxValueIncluded;
+ }
+
+ /**
+ * Sets if the maximum value is part of the accepted range
+ *
+ * @param maxValueIncluded
+ * true if the maximum value should be part of the range, false
+ * otherwise
+ */
+ public void setMaxValueIncluded(boolean maxValueIncluded) {
+ this.maxValueIncluded = maxValueIncluded;
+ }
+
+ /**
+ * Gets the minimum value of the range
+ *
+ * @return the minimum value
+ */
+ public T getMinValue() {
+ return minValue;
+ }
+
+ /**
+ * Sets the minimum value of the range. Use
+ * {@link #setMinValueIncluded(boolean)} to control whether this value is
+ * part of the range or not.
+ *
+ * @param minValue
+ * the minimum value
+ */
+ public void setMinValue(T minValue) {
+ this.minValue = minValue;
+ }
+
+ /**
+ * Gets the maximum value of the range
+ *
+ * @return the maximum value
+ */
+ public T getMaxValue() {
+ return maxValue;
+ }
+
+ /**
+ * Sets the maximum value of the range. Use
+ * {@link #setMaxValueIncluded(boolean)} to control whether this value is
+ * part of the range or not.
+ *
+ * @param maxValue
+ * the maximum value
+ */
+ public void setMaxValue(T maxValue) {
+ this.maxValue = maxValue;
+ }
+
+ /* (non-Javadoc)
+ * @see com.vaadin.data.validator.AbstractValidator#isValidValue(java.lang.Object)
+ */
+ @Override
+ protected boolean isValidValue(T value) {
+ if (value == null) {
+ return true;
+ }
+
+ if (getMinValue() != null) {
+ // Ensure that the min limit is ok
+ int result = value.compareTo(getMinValue());
+ if (result < 0) {
+ // value less than min value
+ return false;
+ } else if (result == 0 && !isMinValueIncluded()) {
+ // values equal and min value not included
+ return false;
+ }
+ }
+ if (getMaxValue() != null) {
+ // Ensure that the Max limit is ok
+ int result = value.compareTo(getMaxValue());
+ if (result > 0) {
+ // value greater than max value
+ return false;
+ } else if (result == 0 && !isMaxValueIncluded()) {
+ // values equal and max value not included
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /* (non-Javadoc)
+ * @see com.vaadin.data.validator.AbstractValidator#getType()
+ */
+ @Override
+ public Class<T> getType() {
+ return type;
+ }
+
+}
diff --git a/src/com/vaadin/data/validator/RegexpValidator.java b/src/com/vaadin/data/validator/RegexpValidator.java index 684de7697c..dec0bf0be9 100644 --- a/src/com/vaadin/data/validator/RegexpValidator.java +++ b/src/com/vaadin/data/validator/RegexpValidator.java @@ -62,8 +62,11 @@ public class RegexpValidator extends AbstractStringValidator { this.complete = complete; } + /* (non-Javadoc) + * @see com.vaadin.data.validator.AbstractValidator#isValidValue(java.lang.Object) + */ @Override - protected boolean isValidString(String value) { + protected boolean isValidValue(String value) { if (complete) { return getMatcher(value).matches(); } else { diff --git a/src/com/vaadin/data/validator/StringLengthValidator.java b/src/com/vaadin/data/validator/StringLengthValidator.java index 1f2b569726..a6242e8170 100644 --- a/src/com/vaadin/data/validator/StringLengthValidator.java +++ b/src/com/vaadin/data/validator/StringLengthValidator.java @@ -14,7 +14,7 @@ package com.vaadin.data.validator; * @since 3.0 */ @SuppressWarnings("serial") -public class StringLengthValidator extends AbstractValidator { +public class StringLengthValidator extends AbstractStringValidator { private int minLength = -1; @@ -62,15 +62,11 @@ public class StringLengthValidator extends AbstractValidator { * @return <code>true</code> for valid value, otherwise <code>false</code>. */ @Override - protected boolean isValidValue(Object value) { + protected boolean isValidValue(String value) { if (value == null) { return allowNull; } - final String s = value.toString(); - if (s == null) { - return allowNull; - } - final int len = s.length(); + final int len = value.length(); if ((minLength >= 0 && len < minLength) || (maxLength >= 0 && len > maxLength)) { return false; diff --git a/src/com/vaadin/ui/AbstractField.java b/src/com/vaadin/ui/AbstractField.java index fb7efc41f5..6b1c535a03 100644 --- a/src/com/vaadin/ui/AbstractField.java +++ b/src/com/vaadin/ui/AbstractField.java @@ -245,15 +245,12 @@ public abstract class AbstractField<T> extends AbstractComponent implements public void commit() throws Buffered.SourceException, InvalidValueException { if (dataSource != null && !dataSource.isReadOnly()) { if ((isInvalidCommitted() || isValid())) { - final T fieldValue = getFieldValue(); try { // Commits the value to datasource. valueWasModifiedByDataSourceDuringCommit = false; committingValueToDataSource = true; - getPropertyDataSource().setValue( - convertToDataSource(fieldValue)); - + getPropertyDataSource().setValue(getConvertedFieldValue()); } catch (final Throwable e) { // Sets the buffering state. @@ -518,7 +515,8 @@ public abstract class AbstractField<T> extends AbstractComponent implements * @throws Property.ConversionException */ protected void setValue(T newFieldValue, boolean repaintIsNotNeeded) - throws Property.ReadOnlyException, Property.ConversionException { + throws Property.ReadOnlyException, Property.ConversionException, + InvalidValueException { if (!equals(newFieldValue, getInternalValue())) { @@ -529,19 +527,19 @@ public abstract class AbstractField<T> extends AbstractComponent implements // Repaint is needed even when the client thinks that it knows the // new state if validity of the component may change - if (repaintIsNotNeeded && (isRequired() || getValidators() != null)) { + if (repaintIsNotNeeded + && (isRequired() || getValidators() != null || getValueConverter() != null)) { repaintIsNotNeeded = false; } - // If invalid values are not allowed, the value must be checked if (!isInvalidAllowed()) { - final Collection<Validator> v = getValidators(); - if (v != null) { - for (final Iterator<Validator> i = v.iterator(); i - .hasNext();) { - (i.next()).validate(newFieldValue); - } - } + /* + * If invalid values are not allowed the value must be validated + * before it is set. If validation fails, the + * InvalidValueException is thrown and the internal value is not + * updated. + */ + validate(newFieldValue); } // Changes the value @@ -717,15 +715,15 @@ public abstract class AbstractField<T> extends AbstractComponent implements } /** - * Sets the value converter for the field from the converter factory defined - * for the application. Clears the value converter if no application + * Retrieves a value converter for the field from the converter factory + * defined for the application. Clears the value converter if no application * reference is available or if the factory returns null. * * @param datamodelType * The type of the data model that we want to be able to convert * from */ - private void updateValueConverterFromFactory(Class<?> datamodelType) { + public void updateValueConverterFromFactory(Class<?> datamodelType) { Converter<?, T> converter = null; Application app = Application.getCurrentApplication(); @@ -822,6 +820,15 @@ public abstract class AbstractField<T> extends AbstractComponent implements } } + /** + * Returns the current field value converted to the data source type. + * + * @return The converted value that is compatible with the data source type + */ + public Object getConvertedFieldValue() { + return convertToDataSource(getFieldValue()); + } + /* Validation */ /** @@ -891,8 +898,9 @@ public abstract class AbstractField<T> extends AbstractComponent implements * Checks the validity of the Field. * * A field is invalid if it is set as required (using - * {@link #setRequired(boolean)} and is empty or if one or several of the - * validators added to the field indicate it is invalid. + * {@link #setRequired(boolean)} and is empty, if one or several of the + * validators added to the field indicate it is invalid or if the value + * cannot be converted provided a value converter has been set. * * The "required" validation is a built-in validation feature. If the field * is required and empty this method throws an EmptyValueException with the @@ -905,30 +913,49 @@ public abstract class AbstractField<T> extends AbstractComponent implements if (isRequired() && isEmpty()) { throw new Validator.EmptyValueException(requiredError); } + validate(getFieldValue()); + } - // If there is no validator, there can not be any errors - if (validators == null) { - return; - } - - final Object fieldValue = getFieldValue(); + /** + * Validates that the given value pass the validators for the field. + * <p> + * This method does not check the requiredness of the field. + * + * @param fieldValue + * The value to check + * @throws Validator.InvalidValueException + * if one or several validators fail + */ + protected void validate(T fieldValue) + throws Validator.InvalidValueException { - List<InvalidValueException> validationExceptions = null; + Object valueToValidate = fieldValue; - // Gets all the validation errors - for (Validator v : validators) { + // If there is a converter we start by converting the value as we want + // to validate the converted value + if (getValueConverter() != null) { try { - v.validate(fieldValue); - } catch (final Validator.InvalidValueException e) { - if (validationExceptions == null) { - validationExceptions = new ArrayList<InvalidValueException>(); + valueToValidate = getValueConverter() + .convertFromTargetToSource(fieldValue, getLocale()); + } catch (Exception e) { + throw new InvalidValueException(e.getMessage()); + } + } + + List<InvalidValueException> validationExceptions = new ArrayList<InvalidValueException>(); + if (validators != null) { + // Gets all the validation errors + for (Validator v : validators) { + try { + v.validate(valueToValidate); + } catch (final Validator.InvalidValueException e) { + validationExceptions.add(e); } - validationExceptions.add(e); } } - // If there were no error - if (validationExceptions == null) { + // If there were no errors + if (validationExceptions.isEmpty()) { return; } diff --git a/tests/server-side/com/vaadin/tests/server/validation/RangeValidatorTest.java b/tests/server-side/com/vaadin/tests/server/validation/RangeValidatorTest.java new file mode 100644 index 0000000000..2cb2c6a509 --- /dev/null +++ b/tests/server-side/com/vaadin/tests/server/validation/RangeValidatorTest.java @@ -0,0 +1,52 @@ +package com.vaadin.tests.server.validation;
+
+import junit.framework.TestCase;
+
+import com.vaadin.data.validator.IntegerRangeValidator;
+
+public class RangeValidatorTest extends TestCase {
+
+ // This test uses IntegerRangeValidator for simplicity.
+ // IntegerRangeValidator contains no code so we really are testing
+ // RangeValidator
+ public void testMinValueNonInclusive() {
+ IntegerRangeValidator iv = new IntegerRangeValidator("Failed", 0, 10);
+ iv.setMinValueIncluded(false);
+ assertFalse(iv.isValid(0));
+ assertTrue(iv.isValid(10));
+ assertFalse(iv.isValid(11));
+ assertFalse(iv.isValid(-1));
+ }
+
+ public void testMinMaxValuesInclusive() {
+ IntegerRangeValidator iv = new IntegerRangeValidator("Failed", 0, 10);
+ assertTrue(iv.isValid(0));
+ assertTrue(iv.isValid(1));
+ assertTrue(iv.isValid(10));
+ assertFalse(iv.isValid(11));
+ assertFalse(iv.isValid(-1));
+ }
+
+ public void testMaxValueNonInclusive() {
+ IntegerRangeValidator iv = new IntegerRangeValidator("Failed", 0, 10);
+ iv.setMaxValueIncluded(false);
+ assertTrue(iv.isValid(0));
+ assertTrue(iv.isValid(9));
+ assertFalse(iv.isValid(10));
+ assertFalse(iv.isValid(11));
+ assertFalse(iv.isValid(-1));
+ }
+
+ public void testMinMaxValuesNonInclusive() {
+ IntegerRangeValidator iv = new IntegerRangeValidator("Failed", 0, 10);
+ iv.setMinValueIncluded(false);
+ iv.setMaxValueIncluded(false);
+
+ assertFalse(iv.isValid(0));
+ assertTrue(iv.isValid(1));
+ assertTrue(iv.isValid(9));
+ assertFalse(iv.isValid(10));
+ assertFalse(iv.isValid(11));
+ assertFalse(iv.isValid(-1));
+ }
+}
diff --git a/tests/testbench/com/vaadin/tests/components/datefield/DateFieldRangeValidation.html b/tests/testbench/com/vaadin/tests/components/datefield/DateFieldRangeValidation.html new file mode 100644 index 0000000000..25bd6357c3 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/datefield/DateFieldRangeValidation.html @@ -0,0 +1,96 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="http://localhost:8888/" />
+<title>New Test</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">New Test</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.datefield.DateFieldRangeValidation?restartApplication</td>
+ <td></td>
+</tr>
+<!--select 15.12.2011-->
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRangeValidation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VPopupCalendar[0]#popupButton</td>
+ <td>11,17</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRangeValidation::Root/VOverlay[0]/VCalendarPanel[0]#day15</td>
+ <td>7,5</td>
+</tr>
+<!--should not be error-->
+<tr>
+ <td>assertElementNotPresent</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRangeValidation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[0]/domChild[4]/domChild[1]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRangeValidation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[3]/VCheckBox[0]/domChild[0]</td>
+ <td>26,6</td>
+</tr>
+<!--should be error-->
+<tr>
+ <td>assertElementPresent</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRangeValidation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[0]/domChild[4]/domChild[1]/domChild[0]</td>
+ <td></td>
+</tr>
+<!--select 3.12.2011-->
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRangeValidation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VPopupCalendar[0]#popupButton</td>
+ <td>13,17</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRangeValidation::Root/VOverlay[0]/VCalendarPanel[0]#day3</td>
+ <td>13,13</td>
+</tr>
+<!--should be error-->
+<tr>
+ <td>assertElementPresent</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRangeValidation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[0]/domChild[4]/domChild[1]/domChild[0]</td>
+ <td></td>
+</tr>
+<!--change to 4.12.2011 by writing-->
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRangeValidation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VPopupCalendar[0]#field</td>
+ <td>52,6</td>
+</tr>
+<tr>
+ <td>enterCharacter</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRangeValidation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VPopupCalendar[0]#field</td>
+ <td>12/4/11</td>
+</tr>
+<!--should not be error-->
+<tr>
+ <td>assertElementNotPresent</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRangeValidation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[0]/domChild[4]/domChild[1]/domChild[0]</td>
+ <td></td>
+</tr>
+<!--no longer include start date-->
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRangeValidation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VCheckBox[0]/domChild[0]</td>
+ <td>6,8</td>
+</tr>
+<!--should be error-->
+<tr>
+ <td>assertElementPresent</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRangeValidation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[0]/domChild[4]/domChild[1]/domChild[0]</td>
+ <td></td>
+</tr>
+
+</tbody></table>
+</body>
+</html>
diff --git a/tests/testbench/com/vaadin/tests/components/datefield/DateFieldRangeValidation.java b/tests/testbench/com/vaadin/tests/components/datefield/DateFieldRangeValidation.java new file mode 100644 index 0000000000..bd1a6655cd --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/datefield/DateFieldRangeValidation.java @@ -0,0 +1,142 @@ +package com.vaadin.tests.components.datefield;
+
+import java.util.Date;
+
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.data.Property.ValueChangeListener;
+import com.vaadin.data.util.BeanItem;
+import com.vaadin.data.validator.RangeValidator;
+import com.vaadin.tests.components.TestBase;
+import com.vaadin.ui.CheckBox;
+import com.vaadin.ui.DateField.Resolution;
+import com.vaadin.ui.PopupDateField;
+
+public class DateFieldRangeValidation extends TestBase {
+
+ public class Range {
+ private Date from, to;
+ private boolean fromInclusive = true;
+ private boolean toInclusive = true;
+
+ public boolean isFromInclusive() {
+ return fromInclusive;
+ }
+
+ public void setFromInclusive(boolean fromInclusive) {
+ this.fromInclusive = fromInclusive;
+ }
+
+ public boolean isToInclusive() {
+ return toInclusive;
+ }
+
+ public void setToInclusive(boolean toInclusive) {
+ this.toInclusive = toInclusive;
+ }
+
+ public Date getFrom() {
+ return from;
+ }
+
+ public void setFrom(Date from) {
+ this.from = from;
+ }
+
+ public Date getTo() {
+ return to;
+ }
+
+ public void setTo(Date to) {
+ this.to = to;
+ }
+
+ }
+
+ private Range range = new Range();
+ private ValueChangeListener refreshField = new ValueChangeListener() {
+
+ public void valueChange(ValueChangeEvent event) {
+ actualDateField.requestRepaint();
+ }
+ };
+
+ private PopupDateField actualDateField;
+
+ @Override
+ protected void setup() {
+ BeanItem<Range> bi = new BeanItem<Range>(range);
+ range.setFrom(new Date(2011 - 1900, 12 - 1, 4));
+ range.setTo(new Date(2011 - 1900, 12 - 1, 15));
+
+ PopupDateField fromField = createDateField();
+ fromField.setPropertyDataSource(bi.getItemProperty("from"));
+ CheckBox fromInclusive = new CheckBox("From inclusive",
+ bi.getItemProperty("fromInclusive"));
+ CheckBox toInclusive = new CheckBox("To inclusive",
+ bi.getItemProperty("toInclusive"));
+ fromInclusive.setImmediate(true);
+ fromInclusive.addListener(refreshField);
+ toInclusive.setImmediate(true);
+ toInclusive.addListener(refreshField);
+
+ PopupDateField toField = createDateField();
+ toField.setPropertyDataSource(bi.getItemProperty("to"));
+
+ actualDateField = createDateField();
+ actualDateField.addValidator(new RangeValidator<Date>("", Date.class,
+ null, null) {
+ @Override
+ public boolean isMinValueIncluded() {
+ return range.isFromInclusive();
+ }
+
+ @Override
+ public boolean isMaxValueIncluded() {
+ return range.isToInclusive();
+ }
+
+ @Override
+ public Date getMaxValue() {
+ return range.getTo();
+ }
+
+ @Override
+ public Date getMinValue() {
+ return range.getFrom();
+ }
+
+ @Override
+ public String getErrorMessage() {
+ return "Date must be in range " + getMinValue() + " - "
+ + getMaxValue();
+ }
+ });
+ addComponent(fromField);
+ addComponent(fromInclusive);
+ addComponent(toField);
+ addComponent(toInclusive);
+ addComponent(actualDateField);
+ }
+
+ private PopupDateField createDateField() {
+ PopupDateField df = new PopupDateField();
+ df.setResolution(Resolution.DAY);
+ df.setValue(new Date());
+ df.setWriteThrough(true);
+ df.setReadThrough(true);
+ df.setImmediate(true);
+ return df;
+ }
+
+ @Override
+ protected String getDescription() {
+ return "Tests the DateField range validator. The first field sets the minimum date, the second the maximum. Checkboxes control if the selected date is ok or not.";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/tests/testbench/com/vaadin/tests/components/datefield/RequiredInvalidDateField.java b/tests/testbench/com/vaadin/tests/components/datefield/RequiredInvalidDateField.java index 6721ddcbdb..a89459d37a 100644 --- a/tests/testbench/com/vaadin/tests/components/datefield/RequiredInvalidDateField.java +++ b/tests/testbench/com/vaadin/tests/components/datefield/RequiredInvalidDateField.java @@ -35,16 +35,21 @@ public class RequiredInvalidDateField extends TestBase { Date date = new Date(2011 - 1900, 9 - 1, 1); - Validator dateValidator = new AbstractValidator( + Validator dateValidator = new AbstractValidator<Date>( "Day of month must be an even number") { @Override - protected boolean isValidValue(Object value) { - if (!(value instanceof Date)) { - return false; + protected boolean isValidValue(Date value) { + if (value == null) { + return true; } - Date date = (Date) value; - return (date.getDate() % 2 == 0); + + return (value.getDate() % 2 == 0); + } + + @Override + public Class getType() { + return Date.class; } }; diff --git a/tests/testbench/com/vaadin/tests/util/AlwaysFailValidator.java b/tests/testbench/com/vaadin/tests/util/AlwaysFailValidator.java index 65b67e5077..ddb58999ee 100644 --- a/tests/testbench/com/vaadin/tests/util/AlwaysFailValidator.java +++ b/tests/testbench/com/vaadin/tests/util/AlwaysFailValidator.java @@ -2,7 +2,7 @@ package com.vaadin.tests.util; import com.vaadin.data.validator.AbstractValidator; -public class AlwaysFailValidator extends AbstractValidator { +public class AlwaysFailValidator extends AbstractValidator<Object> { public AlwaysFailValidator() { super("Validation error"); } @@ -15,4 +15,9 @@ public class AlwaysFailValidator extends AbstractValidator { protected boolean isValidValue(Object value) { return false; } + + @Override + public Class getType() { + return Object.class; + } } diff --git a/tests/testbench/com/vaadin/tests/validation/TestValidators.java b/tests/testbench/com/vaadin/tests/validation/TestValidators.java index 9523ff96b0..a530dee852 100644 --- a/tests/testbench/com/vaadin/tests/validation/TestValidators.java +++ b/tests/testbench/com/vaadin/tests/validation/TestValidators.java @@ -3,12 +3,12 @@ package com.vaadin.tests.validation; import com.vaadin.data.Validator; import com.vaadin.data.validator.AbstractStringValidator; import com.vaadin.data.validator.CompositeValidator; +import com.vaadin.data.validator.CompositeValidator.CombinationMode; import com.vaadin.data.validator.DoubleValidator; import com.vaadin.data.validator.EmailValidator; import com.vaadin.data.validator.IntegerValidator; import com.vaadin.data.validator.RegexpValidator; import com.vaadin.data.validator.StringLengthValidator; -import com.vaadin.data.validator.CompositeValidator.CombinationMode; import com.vaadin.tests.components.TestBase; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; @@ -97,8 +97,7 @@ public class TestValidators extends TestBase { // TODO CompositeValidator tf = new TextField( "A field, must be a floating point number with 4-5 chars"); - CompositeValidator cv = new CompositeValidator( - CombinationMode.AND, + CompositeValidator cv = new CompositeValidator(CombinationMode.AND, "The field must contain a floating point number with 4-5 characters"); cv.addValidator(new StringLengthValidator( "String length of '{0}' should be 4-5 characters", 4, 5, false)); @@ -128,7 +127,7 @@ public class TestValidators extends TestBase { Validator postalCodeValidator = new AbstractStringValidator( "Postal code must be a number 10000-99999.") { @Override - protected boolean isValidString(String value) { + protected boolean isValidValue(String value) { return value.matches("[1-9][0-9]{4}"); } }; |