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.
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.
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 I’m sure you aren’t the only one struggling with this issue.
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.