-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 1 post ] 
Author Message
 Post subject: Advanced MessageInterpolator
PostPosted: Sat Apr 23, 2011 7:36 pm 
Newbie

Joined: Wed Apr 20, 2011 8:45 pm
Posts: 6
Ok, I did dig into validation standard (and impl) a bit, and found a problem.
IMHO the algorithm specified by JSR303 has an unintuitive mess with what (props) are recursively resolvable and what's not. I think, that's mainly due to bad distinction in grammar of annotation's properties and RB's properties.

I've made my own MessageInterpolator, which you can find in my repo: http://github.com/Andrey-Sisoyev/adv-msg-interpolator. It solves the problems, adds some nice caching and and also allows to address the resource bundle, where to look for the property.

Example:
Code:
@Documented
@Constraint(validatedBy = Cmp.LongCmpValidator.class)
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RUNTIME)
public @interface Cmp {
    String message() default "{${rb=home.lang.jsr303mod.validator.vm}Cmp.message}";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
    long value();
    public enum REL { LT,LT_EQ,EQ,NEQ,GT,GT_EQ;
        @Override
        public String toString() {
            return toString_property();
        }
        public String toString_property() {
            switch(this) {
                case LT   : return "{${rb=home.lang.jsr303mod.validator.vm}Cmp.REL.LT}";
                case LT_EQ: return "{${rb=home.lang.jsr303mod.validator.vm}Cmp.REL.LT_EQ}";
                case    EQ: return "{${rb=home.lang.jsr303mod.validator.vm}Cmp.REL.EQ}";
                case   NEQ: return "{${rb=home.lang.jsr303mod.validator.vm}Cmp.REL.NEQ}";
                case GT   : return "{${rb=home.lang.jsr303mod.validator.vm}Cmp.REL.GT}";
                case GT_EQ: return "{${rb=home.lang.jsr303mod.validator.vm}Cmp.REL.GT_EQ}";
            }
            throw new UnsupportedOperationException();
        }
        public String toString_common() { return super.toString(); }
        public String toString_math() { switch(this) {
                case LT   : return "<";
                case LT_EQ: return "\u2264";
                case    EQ: return "=";
                case   NEQ: return "\u2260";
                case GT   : return ">";
                case GT_EQ: return "\u2265";
            }
            throw new UnsupportedOperationException();
        }
    }
    REL prop_rel_cnstr();

    @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
    @Retention(RUNTIME)
    @Documented
    @interface List {
        Cmp[] value();
    }

    class LongCmpValidator implements ConstraintValidator<Cmp, Number> {
        long cnstr_val;
        REL prop_rel_cnstr;

        public void initialize(Cmp constraintAnnotation) {
            cnstr_val = constraintAnnotation.value();
            prop_rel_cnstr = constraintAnnotation.prop_rel_cnstr();
        }

        public boolean isValid(Number _value, ConstraintValidatorContext context) {
            if(_value == null) return true;

            if(       _value instanceof Integer) {
                int value = _value.intValue();
                switch(prop_rel_cnstr) {
                    case LT   : return value <  cnstr_val;
                    case LT_EQ: return value <= cnstr_val;
                    case    EQ: return value == cnstr_val;
                    case   NEQ: return value != cnstr_val;
                    case GT   : return value >  cnstr_val;
                    case GT_EQ: return value >= cnstr_val;
                }
            } else // ... other Number types processed

            return true;
        }
    }
}


RB:
Code:
Cmp.REL.LT=less than
Cmp.REL.LT_EQ=less than or equal
Cmp.REL.EQ=equal
Cmp.REL.NEQ=not-equal
Cmp.REL.GT=greater
Cmp.REL.GT_EQ=greater than or equal

# will work only on advanced interpolator
Cmp.message=validated value is to be in relation "{$@prop_rel_cnstr}" to {$@value}


{${rb=home.lang.jsr303mod.validator.vm}Cmp.message} means "Cmp.message" property from bundle "home.lang.jsr303mod.validator.vm".
{$@prop_rel_cnstr} means annotation property "prop_rel_cnstr".

New resolution algorithm differs from what's specified in the JSR303 (but is mostly backward compatible)
(1.) Resolve all the RB property recursively:
(1.1.) If RB name specified (by the property) look for it only in specified RB
(1.2.) Else look in the user's ValidationsMessages RB (or what he've configured) and if not found, look for it in the "org.hibernate.validator.ValidationMessages" inner core RB
(2.) If no more properties resolution possible, resolve annotations properties. On each resolved annotation fragment go recursively to (1).

The package is well tested (with hibernate-validator v4.1.0.Final) and ready for use, so you're welcome.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 1 post ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.