Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SpringMvc How to use different validators for an Object based on the function the user is preforming

I have an Object called officers i would like to preform different types of validation based on the function the user wants to preform, for e.g when a officer record is being registered/saved i would like to preform a check if its NULL and generate a officer number and when a record is being updated i would not like to not preform this check and execute an update statement.

However i am having problems achieving this since. I have looked at different approaches and it isnt clean enough or flexible. I have tried the following approaches and the problems faced are;

  1. Using a Registered Validator with the Controller however each Controller only allows one Validator to be registered. This makes the implementation of that validation apply to all functions preformed in the controller.

    1. Using a Validator Facade could allow one validation class for the entire application however it selects validation based on instance type for objects and this limits the number of validators per object to one(stand to be corrected).

How is it possible to preform different validation for the same object without using a separate Controller for the method.

Class Officers

   public class Officers implements Serializable{


        private String userName;
        private String password;
        private String password2;
        private String fName;
        private String lName;
        private String oName;
        private int divisionNo;
        private officerNumber;

OfficerRegistrationValidation Class

    @Component
    public class OfficerRegistrationValidation implements Validator {

        public boolean supports(Class<?> clazz) {

            return Officers.class.equals(clazz);
        }

        public void validate(Object target, Errors errors) {

            Officers officer = (Officers) target;

    if (officer.getPassword() == null) {
                errors.rejectValue("password", "password.required");
            }

            if (officer.getPassword2() == null) {
                errors.rejectValue("password2", "password2.required");
            }
..............
}

Controller

@Controller
public class OfficerController {


    @InitBinder("officers")
    protected void initBinder(WebDataBinder binder){


        //removes white spaces 
        binder.registerCustomEditor(String.class, new StringTrimmerEditor(true));

        //formats date 
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");

        //By passing true this will convert empty strings to null
        binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
        dateFormat.setLenient(false);


        //binder.setValidator(new OfficerRegistrationValidation());
        binder.setValidator(officerRegistrationValidation);



    }

 @RequestMapping(value="officer_registration_save.htm", method = RequestMethod.POST)
public ModelAndView loadPage(HttpServletRequest request,HttpServletResponse response,
@ModelAttribute Officers officer,BindingResult result,ModelMap m, Model model) throws Exception {    

    if(result.hasErrors()){

          return new ModelAndView("officer_registration");

     }else 

          doSave();

}

Need to use a different type of validation for a record to be updated

 @RequestMapping(value="officer_registration_update.htm", method = RequestMethod.POST)
public ModelAndView loadPage(HttpServletRequest request,HttpServletResponse response,
@ModelAttribute Officers officer,BindingResult result,ModelMap m, Model model) throws Exception {    

    if(result.hasErrors()){

          return new ModelAndView("officer_registration");

     }else 

          doSave();

}

The approach i end up using was getting the button value either update or save via HttpServletRequest and including that in the validator to decide whether to validate for an update or a save. Has anyone done anything similar before i am looking for he cleanest and best approach. So far i have decided to use HttpServletRequest request request.getParameter("action"); I find this approach to be a little old and not clean.

like image 927
devdar Avatar asked Mar 24 '23 21:03

devdar


1 Answers

You don't need to register your validators in the WebDataBinder. Instead, you can create two (or any number) different Validator classes for each of your requirements. For example

public class OfficerRegistrationValidation implements Validator {...}

public class OfficerUpdateValidation implements Validator {...}

Create beans for each of these, either with @Component or a <bean> declaration. Inject them in your @Controller class

@Controller
public class OfficerController {
    @Inject
    private OfficerRegistrationValidation officerRegistrationValidation;

    @Inject
    private OfficerUpdateValidation officerUpdateValidation;

Then use the specific one you need in each of your methods

@RequestMapping(method = RequestMethod.POST) 
public /* or other return type */ String registerOfficer(@Valid @ModelAttribute Officer officer, BindingResult errors /*, more parameters */) {
    officerRegistrationValidation.validate(officer, errors);
    if (errors.hasErrors()) {
        ...// do something
    }
    ...// return something
}

Don't register either of these in the WebDataBinder. @Valid will perform default validation, for example, for @NotEmpty or @Pattern annotations. Your Validator instances will perform custom validation for the specific use case.

like image 103
Sotirios Delimanolis Avatar answered Mar 30 '23 01:03

Sotirios Delimanolis