Рекурсивное разрешение сообщения валидатора JSR303?

Я написал валидатор 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 применяется рекурсивно до тех пор, пока замена не будет выполнена (т. е. значение параметра сообщения может само содержать параметр сообщения).

person Andrey    schedule 20.04.2011    source источник


Ответы (1)


Хорошо, я копался в этом. Алгоритм, указанный в JSR303, имеет неинтуитивный беспорядок с тем, что (реквизиты) рекурсивно разрешимы, а что нет. Я думаю, это в основном из-за плохого различия в грамматике свойств аннотаций и свойств RB.

Поэтому я сделал свой собственный MessageInterpolator, который вы можете найти в моем репозитории: http://github.com/Andrey-Sisoyev/adv-msg-interpolator. Это решает практически все проблемы, а также позволяет обратиться к ресурсному блоку, где искать недвижимость.

person Andrey    schedule 23.04.2011