Close

Spring Framework - LocalValidatorFactoryBean Examples

Spring Framework 

LocalValidatorFactoryBean is based on adapter pattern which unifies Validator and JSR 349/303 bean validation interface Validator. This class also implements 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.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;

import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import javax.validation.constraints.DecimalMin;
import javax.validation.constraints.Future;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.util.Date;
import java.util.Locale;
import java.util.Set;

public class ValidationJSR349Example {

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

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

@Configuration
public static class Config {

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

@Bean
public Order order () {

Order order = new Order();
// order.setPrice(BigDecimal.TEN);
order.setDate(new Date(System.currentTimeMillis() - 60000));
return order;
}

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

private static class ClientBean {
@Autowired
private Order order;
@Autowired
Validator validator;

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

private boolean validateOrder () {
Locale.setDefault(Locale.US);
Set<ConstraintViolation<Order>> c = validator.validate(order);
if (c.size() > 0) {
System.out.println("Order validation errors:");
c.stream().map(v -> v.getMessage())
.forEach(System.out::println);
return false;
}
return true;
}
}

private static 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 + '}';
}
}
}

Output

Order validation errors:
Date must be in future
Price cannot be empty
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.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.validation.*;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;

import javax.validation.constraints.DecimalMin;
import javax.validation.constraints.Future;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.util.Date;
import java.util.Locale;
import java.util.Map;

public class ValidationMixedExample {


public static void main (String[] args) {

AnnotationConfigApplicationContext context = new
AnnotationConfigApplicationContext(
Config.class);

ClientBean clientBean = context.getBean(ClientBean.class);
clientBean.processOrder();
}


@Configuration
public static class Config {

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

@Bean
public Order order () {
Order order = new Order();
// order.setPrice(BigDecimal.TEN);
// order.setDate(new Date(System.currentTimeMillis() + 100000));
order.setCustomerId("111");
return order;
}

@Bean
public org.springframework.validation.Validator validatorFactory () {
return new LocalValidatorFactoryBean();
}

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

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


private static class ClientBean {
@Autowired
private Order order;

@Autowired
private GenericValidator genericValidator;

private void processOrder () {
if (genericValidator.validateObject(order)) {
System.out.println("processing " + order);
}
}

public Order getOrder () {
return order;
}
}


private static 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 + "'}";
}
}

private static class OrderValidator implements
org.springframework.validation.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..
// otherwise we have to use a backend data service here
return null;
}
}

private static class Customer {
}

private static 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.out.println(messageSource.getMessage("object.invalid",
new Object[]{objectToValidate.getClass().
getSimpleName()},
Locale.US));

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

return true;
}

}
}

Output

Order has validation errors:
No customer found with id 111
Date cannot be empty
Price cannot be empty
Original Post




See Also