0.4 and hibernate validator 4.1.0.Final, I created a custom validator for validating password and confirmPassword fields, but the validator thrown the following exception:
00:16:11,891 DEBUG [org.hibernate.validator.resourceloading.PlatformResourceBundleLocator] (http--192.168.1.20-8080-6) ValidationMessages not found.
00:16:11,892 DEBUG [org.hibernate.validator.resourceloading.PlatformResourceBundleLocator] (http--192.168.1.20-8080-6) org.hibernate.validator.ValidationMessages found
00:16:11,894 DEBUG [org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver] (http--192.168.1.20-8080-6) Resolving exception from handler [deliveries.manager.controller.AdminSignUpController@455901d2]: org.springframework.web.bind.annotation.support.HandlerMethodInvocationException: Failed to invoke handler method [public java.lang.String deliveries.manager.controller.AdminSignUpController.submitProduct(javax.servlet.http.HttpServletRequest,org.springframework.ui.Model,deliveries.manager.pagebean.AdminSignupBean,org.springframework.validation.BindingResult,org.springframework.ui.ModelMap)]; nested exception is java.lang.IllegalStateException: JSR-303 validated property 'password.confirmPassword' does not have a corresponding accessor for Spring data binding - check your DataBinder's configuration (bean property versus direct field access)
00:16:11,897 DEBUG [org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver] (http--192.168.1.20-8080-6) Resolving exception from handler [deliveries.manager.controller.AdminSignUpController@455901d2]: org.springframework.web.bind.annotation.support.HandlerMethodInvocationException: Failed to invoke handler method [public java.lang.String deliveries.manager.controller.AdminSignUpController.submitProduct(javax.servlet.http.HttpServletRequest,org.springframework.ui.Model,deliveries.manager.pagebean.AdminSignupBean,org.springframework.validation.BindingResult,org.springframework.ui.ModelMap)]; nested exception is java.lang.IllegalStateException: JSR-303 validated property 'password.confirmPassword' does not have a corresponding accessor for Spring data binding - check your DataBinder's configuration (bean property versus direct field access)
00:16:11,900 DEBUG [org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver] (http--192.168.1.20-8080-6) Resolving exception from handler [deliveries.manager.controller.AdminSignUpController@455901d2]: org.springframework.web.bind.annotation.support.HandlerMethodInvocationException: Failed to invoke handler method [public java.lang.String deliveries.manager.controller.AdminSignUpController.submitProduct(javax.servlet.http.HttpServletRequest,org.springframework.ui.Model,deliveries.manager.pagebean.AdminSignupBean,org.springframework.validation.BindingResult,org.springframework.ui.ModelMap)]; nested exception is java.lang.IllegalStateException: JSR-303 validated property 'password.confirmPassword' does not have a corresponding accessor for Spring data binding - check your DataBinder's configuration (bean property versus direct field access)
00:16:11,902 DEBUG [org.springframework.web.servlet.DispatcherServlet] (http--192.168.1.20-8080-6) Could not complete request: org.springframework.web.bind.annotation.support.HandlerMethodInvocationException: Failed to invoke handler method [public java.lang.String deliveries.manager.controller.AdminSignUpController.submitProduct(javax.servlet.http.HttpServletRequest,org.springframework.ui.Model,deliveries.manager.pagebean.AdminSignupBean,org.springframework.validation.BindingResult,org.springframework.ui.ModelMap)]; nested exception is java.lang.IllegalStateException: JSR-303 validated property 'password.confirmPassword' does not have a corresponding accessor for Spring data binding - check your DataBinder's configuration (bean property versus direct field access)
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:181) [spring-web-3.0.4.RELEASE.jar:3.0.4.RELEASE]
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:427) [spring-webmvc-3.0.4.RELEASE.jar:3.0.4.RELEASE]
Here is the bean class:
@CompareStrings(propertyNames={"password", "confirmPassword"}, message="Password and Comfirm Password must be matched.")
public class AdminSignupBean {
private String password = "";
private String confirmPassword = "";
private String emailAddress = "";
private String firstName = "";
private String lastName = "";
private String gender = "M";
private String loginName = "";
private String address1 = "";
private String address2 = "";
private String suburb = "";
private String state = "";
private String postcode = "";
private String phone = "";
...
<settings and getters>
Validator class:
public class CompareStringsValidator implements ConstraintValidator<CompareStrings, Object> {
public enum StringComparisonMode {
EQUAL, EQUAL_IGNORE_CASE, NOT_EQUAL, NOT_EQUAL_IGNORE_CASE
}
private String[] propertyNames;
private StringComparisonMode comparisonMode;
private boolean allowNull;
@Override
public void initialize(CompareStrings constraintAnnotation) {
this.propertyNames = constraintAnnotation.propertyNames();
this.comparisonMode = constraintAnnotation.matchMode();
this.allowNull = constraintAnnotation.allowNull();
}
@Override
public boolean isValid(Object target, ConstraintValidatorContext context) {
boolean isValid = true;
List<String> propertyValues = new ArrayList<String> (propertyNames.length);
for(int i=0; i<propertyNames.length; i++) {
String propertyValue = ConstraintValidatorHelper.getPropertyValue(String.class, propertyNames[i], target);
if(propertyValue == null) {
if(!allowNull) {
isValid = false;
break;
}
} else {
propertyValues.add(propertyValue);
}
}
if(isValid) {
isValid = ConstraintValidatorHelper.isValid(propertyValues, comparisonMode);
}
if (!isValid) {
/*
* if custom message was provided, don't touch it, otherwise build the
* default message
*/
String message = context.getDefaultConstraintMessageTemplate();
message = (message.isEmpty()) ? ConstraintValidatorHelper.resolveMessage(propertyNames, comparisonMode) : message;
context.disableDefaultConstraintViolation();
ConstraintViolationBuilder violationBuilder = context.buildConstraintViolationWithTemplate(message);
for (String propertyName : propertyNames) {
NodeBuilderDefinedContext nbdc = violationBuilder.addNode(propertyName);
nbdc.addConstraintViolation();
}
}
return isValid;
}
}
Controller class:
public String submitProduct(HttpServletRequest req, Model model,
@ModelAttribute("adminsignup") @Valid final AdminSignupBean adminsignup,
BindingResult result, ModelMap map)
{
UUID pbid=adminsignup.getPbid();
logger.debug("====adminsignup:"+adminsignup.toString());
if (result.hasErrors()) {
AdminSignupBean admin = products.get(pbid);
req.getSession().setAttribute("pbid", pbid);
BeanUtils.copyProperties(adminsignup, admin, new String[] {"pbid", "mpf", "password", "confirmPassword"});
map.addAttribute("adminsignupbean",admin);
return "adminsignup/createadmin";
}
Set<ConstraintViolation<AdminSignupBean>> violations
= validatorFactory.getValidator().validate(adminsignup);
for(ConstraintViolation<AdminSignupBean> violation : violations) {
logger.debug("=========Violation Message:- " + violation.getMessage());
}
if (!violations.isEmpty()) {
logger.debug("=====violations messages:"+violations.toString());
AdminSignupBean admin = products.get(pbid);
req.getSession().setAttribute("pbid", pbid);
BeanUtils.copyProperties(adminsignup, admin, new String[] {"pbid", "mpf", "password", "confirmPassword"});
map.addAttribute("adminsignupbean",admin);
return "adminsignup/createadmin";
}
Any suggestion is very appreciated. Thanks Sam
The Spring Framework supports JSR-303 Bean Validation adapting it to Spring's Validator interface. An application can choose to enable JSR-303 Bean Validation once globally, as described in Section 7.8, “Spring 3 Validation”, and use it exclusively for all validation needs.
The @Valid annotation ensures the validation of the whole object. Importantly, it performs the validation of the whole object graph. However, this creates issues for scenarios needing only partial validation. On the other hand, we can use @Validated for group validation, including the above partial validation.
This seems to me a problem of the SpringValidatorAdapter. It seems that this adapter post processes the constraint violations and expects that the violations match existing entity properties. This is not a requirement from the Bean Validation side. I can see that in your custom constraint validator in some cases you are building a custom error. Is this the case when the exception occurs?
I am not a Spring expert, but I think there are multiple ways to integrate Bean Validation in Spring, especially if you only need JSR 303. Have you for example looked at the LocalValidatorFactoryBean?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With