I have a form with some fields and a bean whith their properties (some with restricction annotations) binded with the form.
BeanValidationBinder<Bean> binder = new BeanValidationBinder<>(Bean.class);
binder.bindInstancesFields(form);
Suppose that one of the properties of the bean (name) is annotated with @Size that is binded with the TextField name in the Form,
@Size(min=4, message="Al menos cuatro carácteres")
String name;
Now i want to use a customize display for this error validation so i write after bindInstanceFields
binder.forField(name)
.withStatusLabel(nameStatus)
.bind(Bean::getName, Bean::setName)
When i run on server i see the error indicator (!, the red border and a tooltip with the message error) but not the label with message error.
The doc says
The easiest way of customizing this is to configure each binding to use its own Label that is used to show the status for each field.
I tried also withvalidationStatusHandler
binder.forField(name)
.withValidationStatusHandler(status ->{
nameStatus.setValue(status.getMessage().orElse(""));
nameStatus.setVisible(status.isError());
name.setComponentError(status.isError()? new UserError(""): null);
})
.bind(Bean::getName, Bean::setName)
In this case nothing occur, i can’t see neither error indicator nor label.
I suppose that is something about override the binder (first with bindInstancefields and then with forField) isn’t it?
I don’t know if it’s related but BeanValidationBinder is not working with ValueProvider. You have to bind the field by name bind(“name”) instead of bind(Bean::getName,…).
???
BeanvalidationBinder extends Binder so i can use bind(Bean::getName,…)
I first bind with bindInstanceFields because i have annotated restrictions and another with forField because i want to change the defaut error display.
Beanvalidation with valueprovider is binding with valueprovider but does not validate.
Bindinstancefields bind by name so it does validate.
So I don’t know how it’s working ( jsr303 validation) when you bind with Bindinstancefields then with valueprovider. It may cause some problems.
BeanValidationBinder<Person> binder = new BeanValidationBinder<>(Person.class);
binder.forField(name)
.withStatusLabel(nameStatus)
.bind("name"); // have to be before bindInstanceFields
binder.bindInstanceFields(this);
setContent(new FormLayout(name, nameStatus,firstName));
It will work. (nameStatus will be displayed).
This one will also work (Textfield will be in red):
BeanValidationBinder<Person> binder = new BeanValidationBinder<>(Person.class);
binder.forField(name)
.withValidationStatusHandler(status ->{
nameStatus.setValue(status.getMessage().orElse(""));
nameStatus.setVisible(status.isError());
name.setComponentError(status.isError()? new UserError(""): null);
})
.bind("name");
binder.bindInstanceFields(this);
Thank you so much Jean-Christophe
Two thing importants here:
The order: first bind for field, second bind instance fields.
Not to use valueprovider in bind method if i have BeanValidationBinder.
The doc said it !!
It can use reflection based on bean property names to bind values. This reduces the amount of code you have to write when binding to fields in the bean.
I forgot that part because i was thinking in the next…
f you have a Bean Validation implementation available in your classpath and want to use JSR 303 Bean Validation annotations then a BeanValidationBinder should be used.BeanValidationBinder extends Binder class so it has the same API but its implementation automatically adds a bean validator which takes care of JSR 303 constraints.
Now i was thinking in setValidationStatusHandle method of the binder to do the same with all the fields of the form.
But this is in another
thread