Close

Spring Framework - LocalValidatorFactoryBean Examples

Spring Framework 

LocalValidatorFactoryBean is based on adapter pattern which unifies Validator and JSR 349/303 bean validation interface jakarta.validation.Validator This class also implements jakarta.validation.ValidatorFactory, which means it takes care of JSR 349 bootstrapping as well. In this example we are using JSR 349 based validation annotation to perform validation.

package com.logicbig.example;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import java.util.Calendar;

public class ValidationJSR349Example {

public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(Config.class);

Order order = new Order();
//order.setPrice(BigDecimal.TEN);
Calendar calendar = Calendar.getInstance();
calendar.clear();
calendar.set(2021,1,1, 0,0,0);
order.setDate(calendar.getTime());

ClientBean bean = context.getBean(ClientBean.class);
bean.processOrder(order);
}

}

Output

Order validation errors:
Date must be in future
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;

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.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;

import jakarta.validation.Validator;


@Configuration
public class Config {

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

@Bean
public Validator validatorFactory() {
return new LocalValidatorFactoryBean();
}
}
package com.logicbig.example;

import org.springframework.beans.factory.annotation.Autowired;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validator;
import java.util.Comparator;
import java.util.Locale;
import java.util.Set;

public class ClientBean {
@Autowired
Validator validator;

public void processOrder(Order order) {
if (validateOrder(order)) {
System.out.println("processing " + order);
}
}

private boolean validateOrder(Order order) {
Locale.setDefault(Locale.US);
Set<ConstraintViolation<Order>> c = validator.validate(order);
if (c.size() > 0) {
System.err.println("Order validation errors:");
c.stream().sorted(Comparator.comparing(v->v.getPropertyPath().toString()))
.map(v -> v.getMessage()).forEach(System.err::println);
return false;
}
return true;
}
}
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




See Also