Hi Vaadin community,
I found some weird behavior with the Binder in Vaadin 8.2 and need some help or explanations:
I am using Binder.read/writeBean and try to use the output of binder.hasChanges() to implement a check for changes on any components to prevent the Navigator to change views. Unfortunately, the return value of binder.hasChanges doesn’t work as expected:
Binder.hasChanges javadoc:
Check whether any of the bound fields’ have uncommitted changes since last explicit call to readBean(Object), removeBean(), writeBean(Object) or writeBeanIfValid(Object)}. Unsuccessful write operations will not affect this value.
Looking at the stack, Binder.readBean first clears changedBindings, then values are being set to all binded fields. AbstractField.setValue fires an event with userOriginated=false, but the event still arrives in Binder.handleFieldValueChange and adds a new entry to changedBindings…
After readBean, setBean or removeBean hasChanged should be false.
I don’t know why (don’t check the code) but I think it’s a bug. You should open a issue in github. Perhaps you may create a sample project to reproduce this bug easily.
I tried to reproduce the behavior in a sample project, but couldn’t. After some digging, I found two bindings for the same field in my code… Without the second binding, binder.hasChanges works as expected.
[/font]
[font=Arial]
Are there any use cases where a binder needs tow bindings for the same field? If not, developers should get an exception when adding a second one (like the one you get when adding a component to an already used field in a gridlayout). Is this worth an issue in github?
Here is some code to reproduce the behavior:
[/font]
@Theme("mytheme")
public class MyUI extends UI {
@Override
protected void init(VaadinRequest vaadinRequest) {
final VerticalLayout layout = new VerticalLayout();
final RSTextField pojoText = new RSTextField();
layout.addComponents(pojoText);
setContent(layout);
Pojo pojo = new Pojo("Test");
BeanValidationBinder<Pojo> binder = new BeanValidationBinder<>(Pojo.class);
binder.bind(pojoText, "property");
binder.bind(pojoText, "property");
binder.setReadOnly(true);
System.out.println(binder.hasChanges());
binder.readBean(pojo);
System.out.println(binder.hasChanges());
}
@WebServlet(urlPatterns = "/*", name = "MyUIServlet", asyncSupported = true)
@VaadinServletConfiguration(ui = MyUI.class, productionMode = false)
public static class MyUIServlet extends VaadinServlet {
}
}
public class Pojo {
String property;
public Pojo(String property) {
super();
this.property = property;
}
public String getProperty() {
return property;
}
public void setProperty(String property) {
this.property = property;
}
}
I do have same issue with 8.3.2. And funny enough, also I tried to prevent navigation away from view with changes and in addition to close window with change. I don’t have several bindings, so there might be some other conditions also which result same behaviour.