Tao
Tao

Implementing Custom Validators in the Spring Framework

In the Spring framework, data validation is a common requirement. While Spring provides many built-in validation methods, there are cases where we may need to implement custom validation logic. This blog will show you how to implement a custom Validator in Spring, including a practical example.

The Validator interface in the Spring framework allows us to implement custom validation logic. This interface primarily contains two methods:

  • supports(Class<?> clazz)
  • validate(Object target, Errors errors)

The supports method checks if the current validator can validate instances of the given class, while the validate method contains the actual validation logic.

This method determines whether the Validator can validate objects of a specific type. It takes a Class type parameter and returns a boolean value.

  • Parameter: Class<?> clazz The class type of the object to be validated.
  • Returns: boolean Returns true if the Validator supports validating instances of the specified class type; otherwise, false.

java

@Override
public boolean supports(Class<?> clazz) {
    return SomeObject.class.equals(clazz);
}

In this example, the Validator only validates instances of the SomeObject class.

The validate method contains the actual validation logic. It checks if the properties of the object meet specific validation rules and registers any errors found using the Errors object.

  • Parameters:
    • Object target – the object to be validated.
    • Errors errors – the interface for reporting validation errors. If any issues are found during validation, error messages should be added to this object.
  • Returns: None.

java

@Override
public void validate(Object target, Errors errors) {
    SomeObject someObject = (SomeObject) target;
    if (someObject.getSomeField() < requiredValue) {
        errors.rejectValue("someField", "field.invalid", "The value is too low.");
    }
}

In this example, the Validator checks if the someField property of the SomeObject instance is less than a specified value. If it is, an error is added.

The Errors interface provides various methods to handle error messages, including:

  • reject(String errorCode): Registers a global error not tied to any specific field.
  • rejectValue(String field, String errorCode): Registers an error for a specific field.
  • hasErrors(): Returns a boolean indicating whether any errors are present.
  • getAllErrors(): Returns a list of all errors.

The Validator interface in Spring is widely used in scenarios such as:

  • Form validation: Ensuring user input meets expectations when processing data from web forms.
  • Data binding: Validating data before binding request data to model objects to ensure correctness.
  • Service layer validation: Ensuring data integrity and correctness before business logic processing.
  • Creating a Custom Validator First, we need to implement Spring’s Validator interface. Here is a simple example:

java

import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;

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

    @Override
    public void validate(Object target, Errors errors) {
        MyModel myModel = (MyModel) target;
        ValidationUtils.rejectIfEmpty(errors, "name", "name.empty");
        if (myModel.getValue() < 0) {
            errors.rejectValue("value", "value.negative");
        }
        // More validation logic
    }
}

In this example, we define a CustomValidator class that validates an instance of the MyModel class. We first check if the name property is empty and then check if the value is negative.

  • Integrating into Spring MVC Once we have defined the custom validator, we can use it in a Spring MVC controller. Here is an example of how to use the custom validator in a controller:

java

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.validation.BindingResult;

@Controller
public class MyController {
    private final CustomValidator customValidator;

    @Autowired
    public MyController(CustomValidator customValidator) {
        this.customValidator = customValidator;
    }

    @PostMapping("/submitData")
    public ModelAndView submitData(@ModelAttribute("myModel") MyModel myModel, BindingResult result) {
        customValidator.validate(myModel, result);
        if (result.hasErrors()) {
            return new ModelAndView("form", "myModel", myModel);
        }
        // Business logic
        return new ModelAndView("success");
    }
}

In this controller, we inject the custom validator using @Autowired and call the validate method in the method handling the POST request.

  • Advantages of Custom Validation Logic The main advantage of using a custom validator is flexibility. You can define any validation logic according to specific requirements. Additionally, it is easier to maintain and test because the validation logic is encapsulated in a separate class.

Implementing custom validators in the Spring framework is a powerful and flexible feature. By implementing the Validator interface, we can easily add any business-specific validation logic. This approach can be further extended and customized to meet various complex business requirements.

Related Content