JSR303验证器消息递归解析?

发布于 2024-11-02 14:45:32 字数 3766 浏览 2 评论 0原文

我编写了一个 JSR303 验证器,它将属性值与约束进行比较:

@Documented
@Constraint(validatedBy = Cmp.LongCmpValidator.class)
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RUNTIME)
public @interface Cmp {
    String message() default "{home.lang.validator.Cmp.message}";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
    long value();
    public enum REL { LT,LT_EQ,EQ,GT,GT_EQ;
        @Override
        public String toString() {
            return toString_property();
        }
        public String toString_property() {
            switch(this) {
                case LT   : return "{home.lang.validator.Cmp.REL.LT}";
                case LT_EQ: return "{home.lang.validator.Cmp.REL.LT_EQ}";
                case    EQ: return "{home.lang.validator.Cmp.REL.EQ}";
                case GT   : return "{home.lang.validator.Cmp.REL.GT}";
                case GT_EQ: return "{home.lang.validator.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 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 GT   : return value >  cnstr_val;
                    case GT_EQ: return value >= cnstr_val;
                }
            }
            // ... handle other types
            return true;
        }
    }
}

ValidationMessages.properties :

home.lang.validator.Cmp.REL.LT=less than
home.lang.validator.Cmp.REL.LT_EQ=less than or equal
home.lang.validator.Cmp.REL.EQ=equal
home.lang.validator.Cmp.REL.GT=greater
home.lang.validator.Cmp.REL.GT_EQ=greater than or equal

home.lang.validator.Cmp.message=Failure: validated value is to be in relation "{prop_rel_cnstr}" to {value}.

工作正常。几乎。我收到的验证消息如下所示:

Failure: validated value is to be in relation "{home.lang.validator.Cmp.REL.GT}" to 0.

有人可以建议简单方便的方法,如何使验证器识别并解析嵌套的 {home.lang.validator.Cmp.REL.GT} 键?我需要它能够在处理验证的 JSF2 中很好地使用。 我没有使用 Spring,而是使用 hibernate-validator 4。

顺便说一句,看起来 hibernate-validator 4 没有完全实现 JSR303,因为 4.3.1.1 中的后续状态:

  1. 消息参数提取自 消息字符串并用作键 搜索名为的ResourceBundle ValidationMessages(通常具体化 作为属性文件 /ValidationMessages.properties 及其 区域设置变化)使用定义的 区域设置(见下文)。如果一个房产是 发现,消息参数为 替换为属性值 消息字符串。 应用第 1 步 递归直到没有替换为止 执行(即消息参数 值本身可以包含一条消息 参数)

I have written a JSR303 validator that compares property value to constraint:

@Documented
@Constraint(validatedBy = Cmp.LongCmpValidator.class)
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RUNTIME)
public @interface Cmp {
    String message() default "{home.lang.validator.Cmp.message}";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
    long value();
    public enum REL { LT,LT_EQ,EQ,GT,GT_EQ;
        @Override
        public String toString() {
            return toString_property();
        }
        public String toString_property() {
            switch(this) {
                case LT   : return "{home.lang.validator.Cmp.REL.LT}";
                case LT_EQ: return "{home.lang.validator.Cmp.REL.LT_EQ}";
                case    EQ: return "{home.lang.validator.Cmp.REL.EQ}";
                case GT   : return "{home.lang.validator.Cmp.REL.GT}";
                case GT_EQ: return "{home.lang.validator.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 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 GT   : return value >  cnstr_val;
                    case GT_EQ: return value >= cnstr_val;
                }
            }
            // ... handle other types
            return true;
        }
    }
}

ValidationMessages.properties :

home.lang.validator.Cmp.REL.LT=less than
home.lang.validator.Cmp.REL.LT_EQ=less than or equal
home.lang.validator.Cmp.REL.EQ=equal
home.lang.validator.Cmp.REL.GT=greater
home.lang.validator.Cmp.REL.GT_EQ=greater than or equal

home.lang.validator.Cmp.message=Failure: validated value is to be in relation "{prop_rel_cnstr}" to {value}.

Works fine. Almost. The validation message I get looks like this:

Failure: validated value is to be in relation "{home.lang.validator.Cmp.REL.GT}" to 0.

Would anybody please suggest easy and convenient way, how to make Validator recognize and resolve nested {home.lang.validator.Cmp.REL.GT} key? I need it to be nicely usable in JSF2, which handles validation.
I'm not using Spring, but use hibernate-validator 4.

By the way, looks like hibernate-validator 4 doesn't fully implement JSR303, since later states in the 4.3.1.1.:

  1. Message parameters are extracted from
    the message string and used as keys to
    search the ResourceBundle named
    ValidationMessages (often materialized
    as the property file
    /ValidationMessages.properties and its
    locale variations) using the defined
    locale (see below). If a property is
    found, the message parameter is
    replaced with the property value in
    the message string. Step 1 is applied
    recursively until no replacement is
    performed (i.e. a message parameter
    value can itself contain a message
    parameter)
    .

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

千鲤 2024-11-09 14:45:32

好吧,我确实深入研究了这一点。 JSR303 指定的算法对于哪些(属性)可递归解析和哪些不可递归解析存在不直观的混乱。我认为,这主要是由于注释的属性和 RB 的属性的语法区别不好。

所以我制作了自己的 MessageInterpolator,您可以在我的存储库中找到它: http:// github.com/Andrey-Sisoyev/adv-msg-interpolator。它解决了几乎所有的问题,并且还允许解决资源捆绑,在哪里寻找属性。

Ok, I did dig into this. 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.

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文