BeanFieldGroup and Nested Properties (BEAN VALIDATION)

I´m not able to get BeanValidation working with BeanFieldGroup on nested properties

My code:


        binder = new BeanFieldGroup<ContaEmpresa>(ContaEmpresa.class);
        binder.setFieldFactory(new CustomFieldFactory());
        ContaEmpresa bean = controller.getCurrentBean();
        binder.setItemDataSource(bean);
        
        TextField nomeTextField = (TextField) binder.buildAndBind("Seu nome", "nome");        
        TextField empresaTextField = (TextField) binder.buildAndBind("Nome da sua Empresa", "empresa.nomeFantasia");

When user clicks save Button this action is fired


try {
    					binder.commit();
    					ContaEmpresa c= binder.getItemDataSource().getBean();
    					loginPanel.removeComponent(error);
    				} catch (CommitException e) {
    					// TODO Auto-generated catch block
    					loginPanel.removeComponent(error);
    					showErrorMessage("Verifique os campos preenchidos, corrija e tente novamente.");
    					for(Field f :binder.getFields()){
    						((AbstractField ) f).setValidationVisible(true);
    					}
    					e.printStackTrace();
    					 
    				}	

The errors are correctly mapped for the first field (nomeTextField) . But the second one (empresaTextField) dont get the bean validation errors because is a nested property.

Besides that, hibernates bean validation dont let my Bean to persist into the database because its not a valid one (empresa property is invalid).

So, Bean Validation is ok, but BeanFieldGroup commit() apperantly not.

Any ideas or suggestions? I looked a lot on Vaadin Forums and some guys are sayng that this is not implemented yet.

Thanks in advance!

Is the validation annotation in the empresa or the empresa.nomeFantasia? If the first, the fieldGroup really can’t notice there’s something wrong, since it doesn’t have a field for empresa at all, as it only adds BeanValidators for each configured field, not each possible propertyId. You could perhaps try adding validation for that value yourself before the commit, or into a ValueChangeListener of the nomeFantasia field?

The validation annotation is in empresa.nomeFantasia field. Empresa is an entity , that its a field of the Bean, In this case we have

:: Ususario(Bean)
:::::::Empresa(attribute of usuario a regular bean) empresa ;
:::::::::::::: String nomeFantasia (empresa´s attribute)
:::::::String nome (correctly mapped and validated on fieldGroup commit() method).

So, as you said it should work. empresa.NomeFantasia was added as a field in the FieldGroup, and has a validation annotation that is not being processed.

I saw in another thread that nested validation was a missing feature on BeanFieldGroup. Is that true?

Ah, then I misunderstood the original question. Sounds like a bug to me, you should consider making a ticket if there isn’t one already. I haven’t used nested fields much in that way myself, my most recent project ended up using a customField for the nested entity (for a completely different reason) and the annotation was on the entity itself, so I’m not sure what could be a handy workaround for your situation. I guess you
could
make a custom-made annotation that you can give to empresa instead of the nomeFantasia, and then use my workaround, but that doesn’t sound handy at all.

I hope someone else has something more useful to add.

Thaks Anna. It seems that we found a bug (not sure yet)

Is was looking in VaadinSource Code and we have the following in the BeanFieldGroup class:


 @Override
    protected void configureField(Field<?> field) {
        super.configureField(field);
        // Add Bean validators if there are annotations
        if (isBeanValidationImplementationAvailable()) {
            BeanValidator validator = new BeanValidator(beanType,
                    getPropertyId(field).toString());
            field.addValidator(validator);
            if (field.getLocale() != null) {
                validator.setLocale(field.getLocale());
            }
        }
    }

The BeanValidator is created for the nested property. But the beanType argument is my parent class (not the nested one). Maybe that´s the reason why validation problem aren´t detected. In this case maybe property id should be just the second part of the string => Split(.) . Just the nested bean property, in my case ‘nomeFantasia’.

I didn´t found any special handling code for nested bean validation, so , we can say that it´s a missing feature on Vaadin.

Perhaps someone at Vaadin Team could say something to make things more clear.

But anyway, i´ll try a workaround. Thanks!

Yes, that’s where I would start hunting for the solution myself. I’m not sure how it would react if you added a BeanValidator to the field yourself, but it might be worth trying. Might be something that requires changes to the Vaadin core, though, to get it working properly.

I hope you’ll get it working, good luck! And if you figure out a clever workaround, please share :slight_smile: I’m sure you aren’t the only one struggling with this issue.

Thanks Anna, yout suggestion worked perferctlly.


myTextField.addValidator(new BeanValidator(Empresa.class, "nomeFantasia"));

This adds the validation using the NestedType validation to the textField.

Hope it helps other people too.

Glad to hear it worked :slight_smile:

I had the same problem and don’t want to add an validator for each nestest property. So the soution was to handle nested properties by myself overriding configureField.
I adapted my version and use your class:


 beanGroup = new BeanFieldGroup<ContaEmpresa>(ContaEmpresa.class) {
            @Override
            protected void configureField(Field<?> field) {
                // Workaround for a bug in vaadin with validator and BeanFieldGroups
                // http://dev.vaadin.com/ticket/10752
                // we need to remove all validators first
                field.removeAllValidators();

                // Workaround for a bug in Vaadin and validation for nested properties
                // https://vaadin.com/forum#!/thread/3566803
                // we need to add a validator for nested properties manualy 
                if (getPropertyId(field).toString().contains(".") && isBeanValidationImplementationAvailable()) {
                    String[] propertyId = getPropertyId(field).toString().split("\\.");
                    Class<?> beanClass = getPropertyType(propertyId[0]
);
                    String propertyName = propertyId[1]
;

                    //System.out.println("Handle nested property with anotation:\n\tpropertyId: " + getPropertyId(field).toString() + "\n\tbeanClass: " + beanClass.getName() + "\n\tpropertyName: " + propertyName);
                    BeanValidator validator = new BeanValidator(beanClass, propertyName);
                    field.addValidator(validator);
                    if (field.getLocale() != null) {
                        validator.setLocale(field.getLocale());
                    }
                } else {
                    super.configureField(field);
                }
            }
        };

As you see in the code comments this will also contains a workaround to get rid of multiple validator instances.

Using hibernate validator annotations on entity properties, I got the nested validation to work with a bean field group without overriding the configureField described above. The key piece that I needed was the @Valid annotation on the property in the parent object.

Simplified Example:

class car{
@Valid
private Wheel wheel;
}

class wheel{
@NotNull
private String type;
}

Is there always the problem with last version since I’ve the problem with last Vaadin version?

Seth M’s solution works like a charm! Thanks :wink: