Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best practices for validation depending on actions Spring MVC

I am trying to perform validation using Spring validation. I am wondering what is the best practice to perform validation that depends mainly on user's action, hereafter, I have three different approaches but I don't know which one is best.

Assume, we have the following class Foo to validate and many different rules of validation depending on action performed by user.

public class Foo {
    private String name;

    private int age;

    private String description;

    private int evaluation;

    // getters, setters
}

What is the best way to perform these validations (for instance: during creation only name and age are required, during evaluate action, I only need evaluation to be validated and so on)

solution 1: one validator class per validation rule

public class CreateFooValidator implements Validator {
    //validation for action create
}
public class EvaluateFooValidator implements Validator {
    //validation for evaluate action
}

solution 2: one validator class with several methods

public class FooValidator implements Validator {
    @Override
    public boolean supports(Class<?> clazz) {
        return Foo.class.equals(clazz);
    }

    //the default validate method will be used to validate during create action

    @Override
    public void validate(Object target, Errors errors) {
    //validation required
    }

    //method to validate evaluate action
    public void validateFooEvaluation(Object target, Errors errors) {
    //validation required
    }
    //other validation methods for other actions
}

solution 3: Additional property action in class Foo, one validator

public class Foo {

    private String name;

    private int age;

    private String description;

    private int evaluation;

    private String actionOnFoo;

    // getters, setters
}

public class FooValidator implements Validator {

    private final Foo foo = (Foo) target;
    @Override
    public boolean supports(Class<?> clazz) {
        return Foo.class.equals(clazz);
    }

    @Override
    public void validate(Object target, Errors errors) {
        //test which action is performed by user
        if ("create".equals(foo.getActionOnFoo())) {
            //call for private method that performs validation for create action
        }
    }
    //all private methods
}

What is the best solution among the 3 or other solution if any? Thanks!

like image 800
aslan Avatar asked Sep 30 '13 08:09

aslan


2 Answers

Use JSR-303 Validation Groups, which are since Spring MVC 3.1 also supported by @Validated.

So, for each action you should have a method in your controller. Create a validation group for each possible action that has a different set of rules, e.g.

public interface Create {
}

public interface Evaluate {
}

Annotate Foo with the validation annotations including the group, e.g.

public class Foo {

    @NotNull(groups = { Create.class, Evaluate.class })
    private String name;

    ...

    @Min(value = 1, message = "Evaluation value needs to be at least 1", groups = { Evaluate.class })
    private int evaluation;

    ...
}

Then annotate the foo argument of your controller methods with the appropriate @Validated annotation, e.g. @Validated({Evaluate.class}) for the evaluate controller method.

You can find another example here (see item 2): http://blog.goyello.com/2011/12/16/enhancements-spring-mvc31/

Update: Alternatively, if for some reason you can't / don't want to use @Validated, you can use an injected Validator instance and pass the groups to its validate method. That's the way it was done before Spring 3.1 (as is the case in the article in your comment).

like image 183
herman Avatar answered Sep 21 '22 00:09

herman


Depends that you want to do it. All solutions are good if you apply in all of your validators the same and you want to validate some business logic, not only if it's null or not (for this purpose you can use the @Valid annotation and annotation @Not null in your objects).

For me, if I have an object Foo I only want one Validator for this object, and then I have several methods for validate the data depends of I need in my controllers, for example, one for saving new Foo or other one for validating before updating, etc...

like image 30
Gerard Ribas Avatar answered Sep 20 '22 00:09

Gerard Ribas