Close

Spring Framework - org.springframework.validation.Validator Examples

Spring Framework 

Spring core Validator#validate method performs validations on the provided target object. In this core (not MVC) example we are using low-level DataBinder to initiate validation process and collect error information.

package com.logicbig.example;

import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.validation.DataBinder;
import java.math.BigDecimal;
import java.util.Locale;

public class ValidatorExample {

public static void main(String[] args) {
Order order = new Order();
order.setPrice(BigDecimal.ZERO);

DataBinder dataBinder = new DataBinder(order);
dataBinder.addValidators(new OrderValidator());
dataBinder.validate();

if (dataBinder.getBindingResult().hasErrors()) {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("ValidationMessages");

System.err.println(messageSource.getMessage("order.invalid", null, Locale.US));
dataBinder.getBindingResult().getAllErrors().stream()
.forEach(e -> System.err.println(messageSource.getMessage(e, Locale.US)));
} else {
System.out.println("No Validation errors");
}
}

}

Output

Order has validation errors:
Date cannot be empty
Price should be more than zero

package com.logicbig.example;

import java.math.BigDecimal;
import java.util.Date;

public class Order {
private Date date;
private BigDecimal price;

public void setDate(Date date) {
this.date = date;
}

public void setPrice(BigDecimal price) {
this.price = price;
}

public Date getDate() {
return date;
}

public BigDecimal getPrice() {
return price;
}

@Override
public String toString() {
return "Order{'date='" + date + "', price=" + price + '}';
}
}

package com.logicbig.example;

import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
import java.math.BigDecimal;

public class OrderValidator implements Validator {

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

@Override
public void validate(Object target, Errors errors) {
ValidationUtils.rejectIfEmpty(errors, "date", "date.empty");
ValidationUtils.rejectIfEmpty(errors, "price", "price.empty");
Order order = (Order) target;
if (order.getPrice() != null &&
order.getPrice().compareTo(BigDecimal.ZERO) <= 0) {
errors.rejectValue("price", "price.invalid");
}
}
}
Original Post




In this example we are using ValidationUtils#invokeValidator to perform validation.

package com.logicbig.example;

import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.ValidationUtils;
import java.math.BigDecimal;
import java.util.Locale;

public class ValidatorExample2 {

public static void main(String[] args) {

ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("ValidationMessages");

Order order = new Order();
order.setPrice(BigDecimal.ZERO);
BeanPropertyBindingResult result = new BeanPropertyBindingResult(order, "order");
ValidationUtils.invokeValidator(new OrderValidator(), order, result);
if (result.getAllErrors().size() > 0) {
result.getAllErrors().stream().
forEach(e -> System.err.println(messageSource.getMessage(e, Locale.US)));
} else {
System.out.println("No Validation errors");
}
}
}

Output

Date cannot be empty
Price should be more than zero

package com.logicbig.example;

import java.math.BigDecimal;
import java.util.Date;

public class Order {
private Date date;
private BigDecimal price;

public void setDate(Date date) {
this.date = date;
}

public void setPrice(BigDecimal price) {
this.price = price;
}

public Date getDate() {
return date;
}

public BigDecimal getPrice() {
return price;
}

@Override
public String toString() {
return "Order{'date='" + date + "', price=" + price + '}';
}
}

package com.logicbig.example;

import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
import java.math.BigDecimal;

public class OrderValidator implements Validator {

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

@Override
public void validate(Object target, Errors errors) {
ValidationUtils.rejectIfEmpty(errors, "date", "date.empty");
ValidationUtils.rejectIfEmpty(errors, "price", "price.empty");
Order order = (Order) target;
if (order.getPrice() != null &&
order.getPrice().compareTo(BigDecimal.ZERO) <= 0) {
errors.rejectValue("price", "price.invalid");
}
}
}
Original Post




This example uses both org.springframework.validation.Validator and JSR 349/303 based validation annotation to perform validation.

package com.logicbig.example;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class ValidationMixedExample {

public static void main(String[] args) {

AnnotationConfigApplicationContext context = new
AnnotationConfigApplicationContext(Config.class);

ClientBean clientBean = context.getBean(ClientBean.class);
Order order = new Order();
// order.setPrice(BigDecimal.TEN);
// order.setDate(new Date(System.currentTimeMillis() + 100000));
order.setCustomerId("111");
clientBean.processOrder(order);
}

}

Output

Order has validation errors:
Date cannot be empty
No customer found with id 111
Price cannot be empty
package com.logicbig.example;

import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.Future;
import jakarta.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.util.Date;

public class Order {
@NotNull(message = "{date.empty}")
@Future(message = "{date.future}")
private Date date;

@NotNull(message = "{price.empty}")
@DecimalMin(value = "0", inclusive = false, message = "{price.invalid}")
private BigDecimal price;

String customerId;

public void setDate(Date date) {
this.date = date;
}

public void setPrice(BigDecimal price) {
this.price = price;
}

public Date getDate() {
return date;
}

public BigDecimal getPrice() {
return price;
}

public String getCustomerId() {
return customerId;
}

public void setCustomerId(String customerId) {
this.customerId = customerId;
}

@Override
public String toString() {
return "Order{ date=" + date + ", price=" + price +
", customerId='" + customerId + "'}";
}
}
package com.logicbig.example;

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

public class OrderValidator implements Validator {

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

@Override
public void validate(Object target, Errors errors) {
ValidationUtils.rejectIfEmpty(errors, "customerId", "customerId.empty");

Order order = (Order) target;
if (order.getCustomerId() != null) {
Customer customer = getCustomerById(order.getCustomerId());
if (customer == null) {
errors.reject("customer.id.invalid",
new Object[]{order.getCustomerId()},
"Customer id is not valid");
}
}
}

private Customer getCustomerById(String customerId) {
//just for test returning null.
// in real example the customer could be loop up in database etc.
return null;
}
}
package com.logicbig.example;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.validation.BindingResult;
import org.springframework.validation.DataBinder;
import org.springframework.validation.ObjectError;
import org.springframework.validation.Validator;
import jakarta.validation.ConstraintViolation;
import java.awt.print.Book;
import java.util.Comparator;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

public class GenericValidator {

@Autowired
ApplicationContext context;

/**
* This is a framework style generic method which can
* validate any object given that the corresponding
* validator is register as bean.
*/
public boolean validateObject(Object objectToValidate) {

Map<String, Validator> validatorMap = context.getBeansOfType(Validator.class);
if (validatorMap == null) {
return true;
}

DataBinder binder = new DataBinder(objectToValidate);

//in this example two validators are register OrderValidator
// and LocalValidatorFactoryBean which will do JSR 349 validations.
for (Validator validator : validatorMap.values()) {

if (validator.supports(objectToValidate.getClass())) {
binder.addValidators(validator);
}
}

binder.validate();
BindingResult bindingResult = binder.getBindingResult();
if (bindingResult.hasErrors()) {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("ValidationMessages");

System.err.println(messageSource.getMessage("object.invalid",
new Object[]{objectToValidate.getClass().getSimpleName()}, Locale.US));

bindingResult.getAllErrors()
.stream()
.map(e -> messageSource.getMessage(e, Locale.US))
.sorted(Comparator.naturalOrder())
.forEach(System.err::println);
return false;
}

return true;
}
}
package com.logicbig.example;

import org.springframework.beans.factory.annotation.Autowired;

public class ClientBean {

@Autowired
private GenericValidator genericValidator;

public void processOrder(Order order) {
if (genericValidator.validateObject(order)) {
System.out.println("processing " + order);
}
}
}
package com.logicbig.example;

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 Config {

@Bean
public ClientBean clientBean() {
return new ClientBean();
}

@Bean
public Validator validatorFactory() {
return new LocalValidatorFactoryBean();
}

@Bean
public OrderValidator orderValidator() {
return new OrderValidator();
}

@Bean
public GenericValidator genericValidator() {
return new GenericValidator();
}
}
Original Post




Validator#forInstanceOf return a Validator that checks whether the target object's class is identical to targetClass, applying the given delegate to populate Errors if it is.

package com.logicbig.example;

import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;

import java.math.BigDecimal;

public class ValidatorForInstanceOfExample {

public static void main(String[] args) {
Validator validator = Validator.forInstanceOf(Number.class, (number, errors) -> {
if (number.doubleValue() < 0) {
errors.reject("number.negative", String.format("Number (%s) cannot be negative. Found: %s",
number.getClass(), number));
}
});

if (validator.supports(Integer.class)) {
Errors errors = validator.validateObject(Integer.valueOf(-1));
errors.getAllErrors().stream()
.map(DefaultMessageSourceResolvable::getDefaultMessage)
.forEach(System.out::println);
}
if (validator.supports(BigDecimal.class)) {
Errors errors = validator.validateObject(BigDecimal.valueOf(-10));
errors.getAllErrors().stream()
.map(DefaultMessageSourceResolvable::getDefaultMessage)
.forEach(System.out::println);
}
}
}

Output

Number (class java.lang.Integer) cannot be negative. Found: -1
Number (class java.math.BigDecimal) cannot be negative. Found: -10
Original Post

Validator#forInstanceOf return a Validator that checks whether the target object is an instance of targetClass, applying the given delegate to populate Errors if it is.

package com.logicbig.example;

import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;

import java.math.BigDecimal;

public class ValidatorForTypeExample {

public static void main(String[] args) {
Validator validator = Validator.forType(Integer.class, (number, errors) -> {
if (number.doubleValue() < 0) {
errors.reject("number.negative", String.format("Number (%s) cannot be negative. Found: %s",
number.getClass(), number));
}
});

if (validator.supports(Integer.class)) {
Errors errors = validator.validateObject(Integer.valueOf(-1));
errors.getAllErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).forEach(System.out::println);
}
if (validator.supports(BigDecimal.class)) {
Errors errors = validator.validateObject(BigDecimal.valueOf(-10));
errors.getAllErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).forEach(System.out::println);
}
}
}

Output

Number (class java.lang.Integer) cannot be negative. Found: -1
Original Post




See Also