Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

javax validation based on operation

I am trying to use javax validations on DTO. But I want these validations to be applied based on the operation for which this DTO is used.

Lets say I have the following DTO:

@Getter @Setter
public class CustomerDTO {

    @NotNull
    private String id;

    @NotNull 
    private String name;
}

I am using the same DTO for Create, Update and Delete operations. Incase of Update and Delete operation I want "id" to be NotNull, but in Create it has to be null.

But since I am using the same DTO, and on using @Valid annotation at controller level, it applies to all the attributes. And the following API fails as "id" cannot be null

public CustomerDTO createCustomer(@Valid CustomerDTO customer, BindingResults results){
    if(results.hasErrors()){
        throw IllegalArgumentsException("Required params are mising");
    }
    customerService.create(customer);
}
like image 934
Ram Gaddam Avatar asked Jun 12 '17 05:06

Ram Gaddam


1 Answers

Since you are using Spring, you can use its @Validated annotation and system.

How it works: every validation annotation has a field groups. This field allows you to determine when the validation should be done, based on a class. What you can do is the following:

  1. Create a ValidationGroups class with all validation groups you need. Example:
import javax.validation.groups.Default;

/**
 * Utility classes to distinct CRUD validations.<br>
 * <br>
 * Used with the
 * {@link org.springframework.validation.annotation.Validated @Validated}
 * Spring annotation.
 */
public final class ValidationGroups {

    private ValidationGroups() {
    }

    // Standard groups

    public interface Create extends Default {};
    public interface Replace extends Default {};
    public interface Update extends Default {};
    public interface Delete extends Default {};
}
  1. For your case, annotate your id field like the following:
@Null(
    groups = Create.class
)
@NotNull(
    groups = { Update.class, Delete.class }
)
private String id;
  1. Finally, tell controller-side which group(s) you want to validate with the @Validated annotation rather than the @Valid one:
public CustomerDTO createCustomer(@Validated(Create.class) CustomerDTO customer, BindingResult results) {
    if(results.hasErrors()){
        throw IllegalArgumentsException("Required params are mising");
    }
    customerService.create(customer);
}

// Etc. You can put multiple groups like @Validated({ Update.class, Delete.class })

NOTE about the extends javax.validation.groups.Default in ValidationGroups:

If you don't extend your Create class with javax.validation.groups.Default, the validation rule will not be done if you use the @Validated annotation without argument.

// @Validated without argument validate every annotation with the "Default" group
public void test(@Validated MyForm form, BindingResult results) {
    // ...
}

You can inherit validation. For example if you want your Replace to validate all your Create validation rules, make Replaceinherit Create.

public interface Create extends Default {};
public interface Replace extends Create {};
like image 126
kagmole Avatar answered Oct 05 '22 14:10

kagmole