fugdev

fug dev · @fugdev

11th Nov 2015 from TwitLonger

As you’ve seen, the default implementation of the Validator instantiates the ConstraintValidators via reflection. Although good enough for most cases, sometimes the validation logic requires interaction with external services (for example, finding out whether a username is unique in the system). If you have this requirement and you’re using spring, you probably want these services to be injected into the validator, and in fact, let spring instantiate the validator all together. To achieve that you’ll need to modify the BeanValidator implementation a bit:

public class BeanValidator implements org.springframework.validation.Validator,
InitializingBean, ApplicationContextAware, ConstraintValidatorFactory {

private Validator validator;

private ApplicationContext applicationContext;

public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}

public void afterPropertiesSet() throws Exception {
ValidatorFactory validatorFactory = Validation.byDefaultProvider().configure()
.constraintValidatorFactory(this).buildValidatorFactory();
validator = validatorFactory.usingContext().getValidator();
}

public <T extends ConstraintValidator<?, ?>> T getInstance(Class<T> key) {

Map beansByNames = applicationContext.getBeansOfType(key);
if (beansByNames.isEmpty()) {
try {
return key.newInstance();
} catch (InstantiationException e) {
throw new RuntimeException("Could not instantiate constraint validator class '" + key.getName() + "'", e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Could not instantiate constraint validator class '" + key.getName() + "'", e);
}
}
if (beansByNames.size() > 1) {
throw new RuntimeException("Only one bean of type '" + key.getName() + "' is allowed in the application context");
}
return (T) beansByNames.values().iterator().next();
}

public boolean supports(Class clazz) {
return true;
}

public void validate(Object target, Errors errors) {
Set<ConstraintViolation<Object>> constraintViolations = validator.validate(target);
for (ConstraintViolation<Object> constraintViolation : constraintViolations) {
String propertyPath = constraintViolation.getPropertyPath().toString();
String message = constraintViolation.getMessage();
errors.rejectValue(propertyPath, "", message);
}
}

Reply · Report Post