Oleg Atamanenko

thoughts about programming

Пишем валидатор для Bean Validation API

JSR-303 предоставляет удобный API для проверки валидности объектов, а также входных параметров. Очевидно, что стандартных валидаторов в какой-то момент может быть недостаточно, поэтому необходимо писать собственный.

Хочу показать на примере валидации запроса к MongoDB, как легко это делается.

Создание аннотации

@Target({FIELD, PARAMETER})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {MongoQueryValidator.class})
public @interface MongoQuery {

    String message() default "Invalid mongo query";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

Обратите внимание на аннотацию @Constraint - она описывает, какой класс будет проводить реальную валидацию. Атрибуты groups() и payload() являются обязательными.

Написание валидатора

public class MongoQueryValidator implements ConstraintValidator<MongoQuery, CharSequence> {

    @Override
    public void initialize(MongoQuery constraintAnnotation) {
    }

    @Override
    public boolean isValid(CharSequence value, ConstraintValidatorContext context) {
        // ignore null and empty strings.
        if (null == value || value.length() == 0) {
            return true;
        }

        try {
            Query query = new BasicQuery(value.toString());
            return true;
        } catch (Exception e) {
            return false;
        }
    }
}

В данном случае, валидатор у нас простой - мы пытаемся создать Mongo Query из переданной строки, если это не удаётся, то считаем, что строка не является корректным запросом к Mongo и возвращаем false.

Если есть желание возвращать динамическое сообщение об ошибке, то это можно сделать следующим образом:

    context.disableDefaultConstraintViolation();
    context.buildConstraintViolationWithTemplate("<Custom error message>").addConstraintViolation();

Использование

На этом всё, теперь нам остаётся только добавить валидацию на нашу модель или входной параметр.

public class Model {
    @MongoQuery
    private String queryCriteria;

}