protected ConstraintValidationResult processSingleLengthConstraint( DictionaryValidationResult result, Object value, LengthConstraint constraint, AttributeValueReader attributeValueReader) throws AttributeValidationException { // Can't process any range constraints on null values if (ValidationUtils.isNullOrEmpty(value)) { return result.addSkipped(attributeValueReader, CONSTRAINT_NAME); } DataType dataType = constraint.getDataType(); Object typedValue = value; if (dataType != null) { typedValue = ValidationUtils.convertToDataType(value, dataType, dateTimeService); } // The only thing that can have a length constraint currently is a string. if (typedValue instanceof String) { return validateLength(result, (String) typedValue, constraint, attributeValueReader); } return result.addSkipped(attributeValueReader, CONSTRAINT_NAME); }
protected ConstraintValidationResult validateLength( DictionaryValidationResult result, String value, LengthConstraint constraint, AttributeValueReader attributeValueReader) throws IllegalArgumentException { Integer valueLength = Integer.valueOf(value.length()); Integer maxLength = constraint.getMaxLength(); Integer minLength = constraint.getMinLength(); Result lessThanMax = ValidationUtils.isLessThanOrEqual(valueLength, maxLength); Result greaterThanMin = ValidationUtils.isGreaterThanOrEqual(valueLength, minLength); // It's okay for one end of the range to be undefined - that's not an error. It's only an error // if one of them is invalid if (lessThanMax != Result.INVALID && greaterThanMin != Result.INVALID) { // Of course, if they're both undefined then we didn't actually have a real constraint if (lessThanMax == Result.UNDEFINED && greaterThanMin == Result.UNDEFINED) { return result.addNoConstraint(attributeValueReader, CONSTRAINT_NAME); } // In this case, we've succeeded return result.addSuccess(attributeValueReader, CONSTRAINT_NAME); } String maxErrorParameter = maxLength != null ? maxLength.toString() : null; String minErrorParameter = minLength != null ? minLength.toString() : null; // If both comparisons happened then if either comparison failed we can show the end user the // expected range on both sides. if (lessThanMax != Result.UNDEFINED && greaterThanMin != Result.UNDEFINED) { return result.addError( RANGE_KEY, attributeValueReader, CONSTRAINT_NAME, RiceKeyConstants.ERROR_OUT_OF_RANGE, minErrorParameter, maxErrorParameter); } // If it's the max comparison that fails, then just tell the end user what the max can be else if (lessThanMax == Result.INVALID) { return result.addError( MAX_LENGTH_KEY, attributeValueReader, CONSTRAINT_NAME, RiceKeyConstants.ERROR_INCLUSIVE_MAX, maxErrorParameter); } // Otherwise, just tell them what the min can be else { return result.addError( MIN_LENGTH_KEY, attributeValueReader, CONSTRAINT_NAME, RiceKeyConstants.ERROR_EXCLUSIVE_MIN, minErrorParameter); } }
/** * checks whether the value provided is in the range specified by inclusiveMax and exclusiveMin * * @param result a holder for any already run validation results * @param value the value to check * @param inclusiveMax the maximum value of the attribute * @param inclusiveMaxText the string representation of inclusiveMax * @param exclusiveMin the minimum value of the attribute * @param exclusiveMinText the string representation of exclusiveMin * @param attributeValueReader provides access to the attribute being validated * @return the passed in result, updated with the results of the range check */ private <T> ConstraintValidationResult isInRange( DictionaryValidationResult result, T value, Comparable<T> inclusiveMax, String inclusiveMaxText, Comparable<T> exclusiveMin, String exclusiveMinText, AttributeValueReader attributeValueReader) { // What we want to know is that the maximum value is greater than or equal to the number passed // (the number can be equal to the max, i.e. it's 'inclusive') Result lessThanMax = ValidationUtils.isLessThanOrEqual(value, inclusiveMax); // On the other hand, since the minimum is exclusive, we just want to make sure it's less than // the number (the number can't be equal to the min, i.e. it's 'exclusive') Result greaterThanMin = ValidationUtils.isGreaterThan(value, exclusiveMin); // It's okay for one end of the range to be undefined - that's not an error. It's only an error // if one of them is actually invalid. if (lessThanMax != Result.INVALID && greaterThanMin != Result.INVALID) { // Of course, if they're both undefined then we didn't actually have a real constraint if (lessThanMax == Result.UNDEFINED && greaterThanMin == Result.UNDEFINED) { return result.addNoConstraint(attributeValueReader, CONSTRAINT_NAME); } // In this case, we've succeeded return result.addSuccess(attributeValueReader, CONSTRAINT_NAME); } // If both comparisons happened then if either comparison failed we can show the end user the // expected range on both sides. if (lessThanMax != Result.UNDEFINED && greaterThanMin != Result.UNDEFINED) { return result.addError( RANGE_KEY, attributeValueReader, CONSTRAINT_NAME, RiceKeyConstants.ERROR_OUT_OF_RANGE, exclusiveMinText, inclusiveMaxText); } // If it's the max comparison that fails, then just tell the end user what the max can be else if (lessThanMax == Result.INVALID) { return result.addError( MAX_INCLUSIVE_KEY, attributeValueReader, CONSTRAINT_NAME, RiceKeyConstants.ERROR_INCLUSIVE_MAX, inclusiveMaxText); } // Otherwise, just tell them what the min can be else { return result.addError( MIN_EXCLUSIVE_KEY, attributeValueReader, CONSTRAINT_NAME, RiceKeyConstants.ERROR_EXCLUSIVE_MIN, exclusiveMinText); } }
@Test public void testValueWithSpecialCharsAllowWhitespace() { ConstraintValidationResult result = process(sydneyAUSAddress, "street1", street1AlphaPatternConstraint); Assert.assertEquals(0, dictionaryValidationResult.getNumberOfWarnings()); Assert.assertEquals(1, dictionaryValidationResult.getNumberOfErrors()); Assert.assertEquals(ErrorLevel.ERROR, result.getStatus()); Assert.assertEquals( new ValidCharactersConstraintProcessor().getName(), result.getConstraintName()); }
@Test public void testValueNotValidChars() { ConstraintValidationResult result = process(newYorkNYAddress, "city", cityAlphaPatternConstraint); Assert.assertEquals(0, dictionaryValidationResult.getNumberOfWarnings()); Assert.assertEquals(1, dictionaryValidationResult.getNumberOfErrors()); Assert.assertEquals(ErrorLevel.ERROR, result.getStatus()); Assert.assertEquals( new ValidCharactersConstraintProcessor().getName(), result.getConstraintName()); }
@Before public void setUp() throws Exception { processor = new ValidCharactersConstraintProcessor(); dictionaryValidationResult = new DictionaryValidationResult(); dictionaryValidationResult.setErrorLevel(ErrorLevel.NOCONSTRAINT); addressEntry = new BusinessObjectEntry(); List<AttributeDefinition> attributes = new ArrayList<AttributeDefinition>(); cityAlphaPatternConstraint = new AlphaPatternConstraint(); cityAlphaPatternConstraint.setMessageKey("validate.dummykey"); cityAlphaPatternConstraint.setValidationMessageParams(new ArrayList<String>()); cityDefinition = new AttributeDefinition(); cityDefinition.setName("city"); cityDefinition.setValidCharactersConstraint(cityAlphaPatternConstraint); attributes.add(cityDefinition); street1AlphaPatternConstraint = new AlphaPatternConstraint(); street1AlphaPatternConstraint.setMessageKey("validate.dummykey"); street1AlphaPatternConstraint.setValidationMessageParams(new ArrayList<String>()); street1AlphaPatternConstraint.setAllowWhitespace(true); street1Definition = new AttributeDefinition(); street1Definition.setName("street1"); street1Definition.setValidCharactersConstraint(street1AlphaPatternConstraint); attributes.add(street1Definition); addressEntry.setAttributes(attributes); }
/** * validates the value provided using {@code RangeConstraint} * * @param result - a holder for any already run validation results * @param value - the value to validate * @param constraint - the range constraint to use * @param attributeValueReader - provides access to the attribute being validated * @return the passed in result, updated with the results of the processing * @throws AttributeValidationException if validation fails */ protected ConstraintValidationResult processSingleRangeConstraint( DictionaryValidationResult result, Object value, RangeConstraint constraint, AttributeValueReader attributeValueReader) throws AttributeValidationException { // Can't process any range constraints on null values if (ValidationUtils.isNullOrEmpty(value) || (constraint.getExclusiveMin() == null && constraint.getInclusiveMax() == null)) { return result.addSkipped(attributeValueReader, CONSTRAINT_NAME); } // This is necessary because sometimes we'll be getting a string, for example, that represents a // date. DataType dataType = constraint.getDataType(); Object typedValue = value; if (dataType != null) { typedValue = ValidationUtils.convertToDataType(value, dataType, dateTimeService); } else if (value instanceof String) { // assume string is a number of type double try { Double d = Double.parseDouble((String) value); typedValue = d; } catch (NumberFormatException n) { // do nothing, typedValue is never reset } } // TODO: decide if there is any reason why the following would be insufficient - i.e. if // something numeric could still be cast to String at this point if (typedValue instanceof Date) { return validateRange(result, (Date) typedValue, constraint, attributeValueReader); } else if (typedValue instanceof Number) { return validateRange(result, (Number) typedValue, constraint, attributeValueReader); } return result.addSkipped(attributeValueReader, CONSTRAINT_NAME); }