NickJ
NickJ

Reputation: 9559

Vaadin BeanValidationBinder & JSR 303 validation

I am using a Vaadin BeanValidationBinder.

If I bind a field like this:

binder.forField(email).bind("email");

then the validation works.

If I bind the field like this:

binder.forField(email).bind(PersonDTO::getEmail, PersonDTO::setEmail);

then it does not work (there is no attempt made to validate)

I prefer the latter form because it is more explicit and less error-prone, but why doesn't validation work, and how can I get it to work?

I have tried the @Email annotation on the field, the getter, and the setter. Using the annotation on the setter caused an exception, but having the annotation on either the field or the getter have the effect as described above.

Upvotes: 1

Views: 723

Answers (2)

mstahv
mstahv

Reputation: 1934

Unfortunately the way you are trying to do the binding is unsupported with the built-in BeanValidation support. The bit limited JSR 303 support in Vaadin is only available with naming based binding. Vaadin JSR 303 supports only property level binding and without using the naming convention based binding, the framework would have no way to connect errors to the related field.

If you can cope with displaying the errors separately in a generic place, like close to the save button, I'd suggest to use JSR 303 APIs directly and doing the validation yourself.

Upvotes: 1

Morfic
Morfic

Reputation: 15508

I haven't dug through the sources to see exactly where this is done, but it makes some sense if you think about it:

  • using a field with binder.bind("name"), the framework is able to inspect it and deduce the associated annotations, and thus evaluate the new value
  • using ValueProvider & Setter with binder.bind(PersonDTO::getEmail, PersonDTO::setEmail), you can supply any kind of method implementation which may not necessarily manipulate a field, although that's usually not the case. For example (not the brightest, but you get the point), you allow the user to input a series of comma separated values in a TextField, which internally you then split and save into a list.

What you can do in your case, is to explicitly add a specific email validator to the binding:

binder.forField(email)
      .withValidator(new EmailValidator("Please provide a valid e-mail address"))
      .asRequired("Please provide a valid e-mail address")
      .bind(PersonDTO::getEmail, PersonDTO::setEmail);

Upvotes: 2

Related Questions