Results 1 to 4 of 4

Thread: Ruby on Rails-ish validation for Spring MVC

Threaded View

  1. #1
    Join Date
    Dec 2004
    Posts
    14

    Default Ruby on Rails-ish validation for Spring MVC

    Here is some code I have been using to do Ruby on Rails-ish style validation in Spring MVC validators

    First, clients look like this:
    Code:
        public void validate(Object command, Errors errors) {
            Job job = (Job) command;
            ValidationUtil.validatePresenceOf(job, "title", errors);
            ValidationUtil.validatePresenceOf(job, "jobType", errors);
            ValidationUtil.validatePresenceOf(job, "description", errors);
            ValidationUtil.validateLengthOf(job, "title", 3, 100, errors);
            ValidationUtil.validateLengthOf(job, "employer", 0, 100, errors);
            ValidationUtil.validateLengthOf(job, "education", 0, 100, errors);        
            ValidationUtil.validateLengthOf(job, "immigrationStatus", 0, 100, errors);        
            ValidationUtil.validateLengthOf(job, "salary", 0, 100, errors);        
            ValidationUtil.validateLengthOf(job, "salaryType", 0, 100, errors);        
            ValidationUtil.validateLengthOf(job, "jobType", 0, 100, errors);        
            ValidationUtil.validateLengthOf(job, "description", 50, 10000, errors);        
            ValidationUtil.validateNumericalityOf(job, "salary", errors);
            ValidationUtil.validateFormatOf(job, "email", ValidationUtil.REGEX_EMAIL, errors);
        }
    Code:
    import java.lang.reflect.Method;
    
    import org.apache.commons.lang.StringUtils;
    import org.apache.commons.lang.math.NumberUtils;
    import org.springframework.validation.Errors;
    
    /**
     * Ruby on Rails style validation for Spring MVC applications
     * 
     * @author John Wheeler
     */
    public class ValidationUtil {
    
        public static final String REGEX_EMAIL = "^([^@\\s]+)@((?:[-a-z0-9]+\\.)+[a-z]{2,})$";
        
        private static final String KEY_REQUIRED    = "error.required";    
        private static final String KEY_MIN_LENGTH  = "error.minlength";    
        private static final String KEY_MAX_LENGTH  = "error.maxlength";    
        private static final String KEY_NUMERIC     = "error.numeric";
        private static final String KEY_FORMAT      = "error.format";
        
        private static final String DEFAULT_MSG_REQUIRED    = "Value required.";
        private static final String DEFAULT_MSG_MIN_LENGTH  = "Value under minimum length.";
        private static final String DEFAULT_MSG_MAX_LENGTH  = "Value exceeds maximum length.";
        private static final String DEFAULT_MSG_NUMERIC     = "Value must be numeric.";
        private static final String DEFAULT_MSG_FORMAT      = "Value is formatted incorrectly.";
        
        /**
         * Ensures the value of the property specified is not blank or null. 
         */
        public static void validatePresenceOf(Object bean, String property, Errors errors) {
            String value = (String) invokeGetter(bean, property);
            if (StringUtils.isBlank(value)) {
                errors.rejectValue(property, 
                        KEY_REQUIRED, 
                        new String[] { humanize(property) }, 
                        DEFAULT_MSG_REQUIRED);
            }
        }
    
        /**
         * Ensures the value of the property specified is greater than <code>min</code> and less than
         * <code>max</code>. 
         */    
        public static void validateLengthOf(Object bean, String property, int min, int max, Errors errors) {
            String value = (String) invokeGetter(bean, property);
            int length = value.length();
            if (length < min) {
                errors.rejectValue(property, 
                        KEY_MIN_LENGTH, 
                        new String[] { humanize(property), ""+min, ""+length }, 
                        DEFAULT_MSG_MIN_LENGTH);            
            } else if (length > max) {
                errors.rejectValue(property, 
                        KEY_MAX_LENGTH, 
                        new String[] { humanize(property), ""+max, ""+length }, 
                        DEFAULT_MSG_MAX_LENGTH);            
            }
        }
        
        /**
         * Ensures the value of the property specified is numeric.
         */        
        public static void validateNumericalityOf(Object bean, String property, Errors errors) {
            String value = (String) invokeGetter(bean, property);        
            if ("".equals(value)) return;        
            if (!NumberUtils.isNumber(value)) {
                errors.rejectValue(property, 
                        KEY_NUMERIC, 
                        new String[] { humanize(property) }, 
                        DEFAULT_MSG_NUMERIC);            
            }
        }
    
        /**
         * Ensures the value of the property specified matches the given regex.
         * This class comes with handy constants that start with <code>REGEX_</code>
         */            
        public static void validateFormatOf(Object bean, String property, String regex, Errors errors) {
            String value = ((String) invokeGetter(bean, property)).toLowerCase();
            if ("".equals(value)) return;
            if (!value.matches(regex)) {
                errors.rejectValue(property,
                        KEY_FORMAT,
                        new String[] { humanize(property) },
                        DEFAULT_MSG_FORMAT);
            }
        }
        
        /**
         * Trys to make a JavaBean property identifier human-readable.
         * <p>
         * e.g. <code>immigrationStatus</code> becomes Immigration status
         * 
         * @param propertyName the property to try and make human-readable
         * @return the human-readable representation of a JavaBean property identifier
         */
        private static String humanize(String propertyName) {
            return StringUtils.capitalize(propertyName.replaceAll("([A-Z]{1})", " $1").toLowerCase());
        }
        
        /**
         * Invokes a "getter" on the supplied <code>bean</code>. Clients are responsible
         * for casting the return value.
         * <p>
         * e.g. <code>String value = (String) invokeGetter(bean, property);</code>
         * 
         * @param bean The bean instance to invoke a getter on
         * @param propertyName The getter's property (don't put 'get' in front of it)
         * @return the result of the getter
         */
        private static Object invokeGetter(Object bean, String propertyName) {
            try {            
                String methodName = "get" + StringUtils.capitalize(propertyName);
                Method method = bean.getClass().getMethod(methodName, new Class[]{});
                return method.invoke(bean, new Object[]{});
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
    messages.properties
    Code:
    error.required={0} cannot be blank.
    error.minlength={0} must be at least {1} characters (currently {2} characters).
    error.maxlength={0} cannot be more than {1} characters (currently {2} characters).
    error.numeric={0} must be numeric.
    error.format={0} must be formatted correctly.
    is this pretty good, or is there a better utility?
    Last edited by john.wheeler; Jun 3rd, 2006 at 03:16 AM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •