Creating Custom Validators in Spring Framework

Answered using GPT-4o-mini by Java Q&A Hub

Question:

How to create custom validators in spring?

Answer:

Creating custom validators in Spring can be accomplished using the Validator interface or by using annotations with the ConstraintValidator interface. Below are the steps for both approaches.

Approach 1: Using the Validator Interface

  1. Create a Custom Validator Class: Implement the Validator interface.
import org.springframework.validation.Validator;
import org.springframework.validation.Errors;

public class CustomValidator implements Validator {

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

    @Override
    public void validate(Object target, Errors errors) {
        YourModelClass yourModel = (YourModelClass) target;

        // Custom validation logic
        if (yourModel.getSomeField() == null) {
            errors.rejectValue("someField", "field.required", "Field is required");
        }
        // Add more validation rules as needed
    }
}
  1. Register the Validator: You can register your custom validator in a Spring configuration class.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.Validator;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;

@Configuration
public class AppConfig {

    @Bean
    public Validator validator() {
        return new CustomValidator();
    }
}
  1. Use the Validator: You can use the validator in your controller or service.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PostMapping;

@Controller
public class YourController {

    @Autowired
    private Validator validator;

    @PostMapping("/submit")
    public String submitForm(YourModelClass yourModel, BindingResult bindingResult) {
        validator.validate(yourModel, bindingResult);

        if (bindingResult.hasErrors()) {
            return "formView"; // return to the form view with errors
        }

        // Process the valid data
        return "successView";
    }
}

Approach 2: Using Annotations with ConstraintValidator

  1. Create a Custom Annotation: Define a custom annotation for your validation.
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Constraint(validatedBy = CustomValidator.class)
@Target({ ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidCustom {
    String message() default "Invalid value";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}
  1. Implement the ConstraintValidator: Create a class that implements ConstraintValidator.
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class CustomValidator implements ConstraintValidator<ValidCustom, String> {

    @Override
    public void initialize(ValidCustom constraintAnnotation) {
    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        // Custom validation logic
        return value != null && !value.isEmpty(); // Example: check if not null or empty
    }
}
  1. Use the Custom Annotation: Apply your custom annotation to the fields in your model class.
public class YourModelClass {

    @ValidCustom(message = "Custom validation failed")
    private String someField;

    // Getters and Setters
}
  1. Enable Validation in Your Controller: Use @Valid to trigger validation.
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PostMapping;

@Controller
public class YourController {

    @PostMapping("/submit")
    public String submitForm(@Valid YourModelClass yourModel, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            return "formView"; // return to the form view with errors
        }

        // Process the valid data
        return "successView";
    }
}

Summary

  • Using the Validator Interface: This approach is more manual and gives you full control over the validation process.
  • Using Annotations with ConstraintValidator: This approach is more declarative and integrates well with the Java Bean Validation API (JSR 380).

Choose the approach that best fits your needs based on the complexity of your validation logic and your application's architecture.