Adding Validation Error to Field When Using Javax Validation

Hi,

I was trying to use javax validation with binder.writeBean and then add the validation errors to the respective fields. It took me a while to get to this and I thought it might be useful for someone else. Maybe there’s a better easier way to do the same thing?

private void clickSaveButton(ClickEvent event) {
   try {
    studentBinder.writeBean(student);
   } catch (ValidationException ex) {
    List<BindingValidationStatus<?>> fieldValidationErrors = ex.getFieldValidationErrors();
    for (BindingValidationStatus<?> fieldValidationError : fieldValidationErrors) {
     String message = fieldValidationError.getMessage().get();
     HasValue<?> field = fieldValidationError.getField();
     if (field instanceof AbstractComponent) {
      ((AbstractComponent)field).setComponentError(new UserError(message));
     }
     Notification.show(message);
    }
   }
   
   System.out.println(student);
  }

If the constraints are placed inside your bean, would that be an easier option:

https://vaadin.com/docs/v8/framework/articles/UsingBeanValidationToValidateInput.html


A^2

This link is not working for vaadin 8. This link is better https://vaadin.com/docs/v8/framework/datamodel/datamodel-forms.html

Normally the validation errors should be automatically linked to the field. The only problem should be for Bean validation (crossfield validation because it’s not linked to a field).

And if your bean is not valid when you enter in your screen (for example when you create a new bean), then you can call studentBinder.validate() before writeBean or you can wait for Vaadin 8.2.

Hi Jean-Christophe,

Can you share a bit more on why
this link
does not work with Vaadin 8? Will be a great feedback for me.

I have made a working demo https://github.com/amahdy/vaadin-stepbystep-demo-contacts that uses a backend with validation on the bean level: https://github.com/amahdy/person-service


A^2

Hi AMahdy,

Of course, in this link you’ve got this code:

Person person = new Person("John", 26);
BeanItem<Person> item = new BeanItem<Person>(person);

TextField firstName = new TextField("First name",
item.getItemProperty("name"));
firstName.setImmediate(true);
setContent(firstName);

BeanItem has been removed since Vaadin 8.
setImmediate is true by default since Vaadin 8.

And after there is this code:

firstName.addValidator(new BeanValidator(Person.class, "name")); addValidator has been removed since Vaadin 8 from TextField.

So I prefer the other documentation for Vaadin 8 :).

This code is ok for Vaadin 8:

TextField firstName = new TextField("First name");
Person person = new Person("John", 26);

BeanValidationBinder<Person> binder = new BeanValidationBinder<>(Person.class);
binder.forField(firstName).bind("name");
binder.setBean(person);
setContent(firstName);

I clone it and don’t see any JSR validation done by Vaadin, when I try it and put invalid data I’ve got a stacktrace:

Caused by: javax.validation.ConstraintViolationException: Validation failed for classes [org.vaadin.stepbystep.person.backend.Person]
during update time for groups [javax.validation.groups.Default, ]

List of constraint violations:[
ConstraintViolationImpl{interpolatedMessage=‘First Name must be longer than 3 and less than 40 characters’, propertyPath=firstName, rootBeanClass=class org.vaadin.stepbystep.person.backend.Person, messageTemplate=‘First Name must be longer than 3 and less than 40 characters’}
]

Good catch! Thank you for reporting this. I have
filled an issue
and
suggested a modification
based on your contribution. Feel free to do so on Github :slight_smile:


A^2

Thank you for reporting this as well! I have
fixed the code
to report the bean validation errors on the UI, and
one more tweak
to prevent saving at all till all errors are gone.


A^2

Hi AMahdy, thanks for the link, it worked really well!

Hi AMahdy,

Thanks for the pull request.
The problem in your example with the tweak setValidationStatusHandler is: the default behaviour is removed (display errors on each field).
So your save button is disabled but you don’t know why (email invalid or less than 3 chars in your name).
I don’t how to add a new validationStatushandler and keep the default one. (Perhaps if you extend binder)
Perhaps you can use this (don’t know if it’s ok or not):
binder.addValueChangeListener(e → save.setEnabled(!binder.hasChanges())); // no uncommited changes = bean is valid
instead of:
binder.setValidationStatusHandler(status → { save.setEnabled(status.isOk()); });

Thanks again,
fixed
by monitoring the status change instead of overriding the validation handler.

Another way of doing it is to keep a reference of the old handler and apply the new status on it:

oldHandler = binder.getValidationStatusHandler(); binder.setValidationStatusHandler(status -> { save.setEnabled(status.isOk()); oldHandler.statusChange(status); }); Having a possiblity to add handler would be better, that’s why I made a
feature request
on Github.

I like this change :slight_smile: (didn’t like my change with hasChanges :D).

Thanks for the tip.