1

I've enabled spring mvc annotation driven for my project. The idea is to use @Valid annotation with spring annotations to avoid the line in the controller like: validator.validate(form, errors)

I've noticed that this stuff does not work with spring annotations from package:

org.springmodules.validation.bean.conf.loader.annotation.handle

After investigation I've found that I can use annotations from javax or org.hibernate.validator.constraints as alternative way.

But unfortunatly, I have some special cases when I cannot achieve this:

@MinSize(applyIf = "name NOT EQUALS 'default'", value = 1)

Will be good to know in which way spring annotation can be used with @Valid or any other alternative way to avoid refactoring related to applyIf attributes(Move conditions to java code).

2 Answers 2

1

Here is an example how to create a custom Validator.

At first create your own Annotation:

@Target({ ElementType.METHOD, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = StringValidator.class)
public @interface ValidString {

    String message() default "Invalid data";
    int min() default -1;
    int max() default -1;
    String regex() default "";

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

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

Then you will need a custom validator:

public class StringValidator implements ConstraintValidator<ValidString, String> {

    private int              _min;
    private int              _max;
    private String           _regex;
    private boolean          _decode;

    public void initialize(ValidString constraintAnnotation) {
        _min = constraintAnnotation.min();
        _max = constraintAnnotation.max();
        _regex = constraintAnnotation.regex();
        _decode = constraintAnnotation.decode();
    }

    public boolean isValid(String value, ConstraintValidatorContext context) {

        if (value == null) {
            return false;
        }

        String test = value.trim();

        if (_min >= 0) {
            if (test.length() < _min) {
                return false;
            }
        }

        if (_max > 0) {
            if (test.length() > _max) {
                return false;
            }
        }

        if (_regex != null && !_regex.isEmpty()) {
            if (!test.matches(_regex)) {
                return false;
            }
        }

        return true;
    }
}

Finally you can use it in your Beans and Controller:

public class UserForm {

    @ValidString(min=4, max=20, regex="^[a-z0-9]+")
    private String name;

    //...
}

// Method from Controller
@RequestMapping(method = RequestMethod.POST)
public String saveUser(@Valid UserForm form, BindingResult brResult) {

    if (brResult.hasErrors()) {
        //TODO:
    }

    return "somepage";
}
0

Something like this might help you out

public class UserValidator implements Validator {

    @Override
    public boolean supports(Class clazz) {
      return User.class.equals(clazz);
    }

    @Override
    public void validate(Object target, Errors errors) {
      User user = (User) target;

      if(user.getName() == null) {
          errors.rejectValue("name", "your_error_code");
      }

      // do "complex" validation here

    }

}

Then in your controller you would have :

@RequestMapping(value="/user", method=RequestMethod.POST)
    public createUser(Model model, @ModelAttribute("user") User user, BindingResult result){
        UserValidator userValidator = new UserValidator();
        userValidator.validate(user, result);

        if (result.hasErrors()){
          // do something
        }
        else {
          // do something else
        }
}

If there are validation errors, result.hasErrors() will be true.

Note : You can also set the validator in a @InitBinder method of the controller, with "binder.setValidator(...)" . Or you could instantiate it in the default constructor of the controller. Or have a @Component/@Service UserValidator that you inject (@Autowired) in your controller : very useful, because most validators are singletons + unit test mocking becomes easier + your validator could call other Spring components.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.