Vaadin 8: Binder hasChanges, removeBean after readBean

Hi everyone,

I’ve a question:
I’ve got a binder.
If I read a bean and modify a field → binder.hasChanges is true (Perfect).
If I call removeBean then nothing changes on the screen and binder.hasChanges is still true.

I don’t understand why it should be true after removeBean.
I write some code to test it: (just click on READ, modify the field, CHECK, REMOVE and CHECK)

@Theme("mytheme")
public class MyUI extends UI {

    private Window popup;
    
    private TextField value = new TextField();
    private Label hasChangesLabel = new Label("");
    private Binder<Pojo> binder;
    private Pojo p = new Pojo("test");
    
    
    @Override
    protected void init(VaadinRequest vaadinRequest) {
        final VerticalLayout layout = new VerticalLayout();
        
        if (binder == null){
            binder = new Binder<Pojo>();
            binder.bind(value,Pojo::getValue, Pojo::setValue);
        }
                
        Button checkHasChangesButton = new Button("CHECK",
                e -> {hasChangesLabel.setCaption(binder.hasChanges()?"CHANGES":"NO CHANGES");}
                );
        

        Button removeBeanButton = new Button("REMOVE", e -> {binder.removeBean();});
        
        Button readBeanButton = new Button("READ", e -> {binder.readBean(p);});
        Button setBeanButton = new Button("SET", e -> {binder.setBean(p);});
        

        layout.addComponents(hasChangesLabel, value, checkHasChangesButton,removeBeanButton,readBeanButton, setBeanButton);
        
        setContent(layout);
    }
    @WebServlet(urlPatterns = "/*", name = "MyUIServlet", asyncSupported = true)
    @VaadinServletConfiguration(ui = MyUI.class, productionMode = false)
    public static class MyUIServlet extends VaadinServlet {
    }
}

Thanks,

Hi,

This looks like a bug to me, at least in the documented API behavior sense - in
https://vaadin.com/api/8.0.5/com/vaadin/data/Binder.html#hasChanges–
it pretty clearly states that hasChanges should return false after removeBean(). I think I see why it’s happening - you haven’t actually bound a bean instance to the Binder in your example with that sequence of events. Note the
readBean API doc
:

public void readBean(BEAN bean) Reads the bound property values from the given bean to the corresponding fields. The bean is not otherwise associated with this binder; in particular its property values are not bound to the field value changes. To achieve that, use #setBean(BEAN) So in your example you create a Binder, set is to the TextField and tell it to use the Bean class’s getValue and setValue methods. Then you call readBean() with a bean instance, which populates the values from the instance, but doesn’t bind anything. Do some changes, Binder has changed, remove the bound bean (=remove nothing → do nothing). Binder has changed, but it’s kind of in an invalid state at this point.

If you don’t mind, could you please create a ticket about this at
https://github.com/vaadin/framework/issues
? If you have an idea of how it should behave in this case, please write that in too - maybe Binder should throw an exception if you call remove when there is no bean bound?

Best regards,

Olli

Sounds like a bug. Please make a ticket at https://github.com/vaadin/framework/issues

I create a new ticket: https://github.com/vaadin/framework/issues/9193

I understand that:
removeBean = setBean(null) (opposite of setBean)
So in my case, I should use readBean(null).

(the difference between bound bean and bound properties is not so easy to understand)
Especially if you read this javadoc
https://vaadin.com/api/8.0.5/com/vaadin/data/Binder.html#getBean--

public BEAN getBean()
Returns the bean that has been bound with bind(com.vaadin.data.HasValue<FIELDVALUE>, com.vaadin.data.ValueProvider<BEAN, FIELDVALUE>, com.vaadin.server.Setter<BEAN, FIELDVALUE>), or null if a bean is not currently bound.Returns:
the currently bound bean if any

That’s wrong, if I understand the difference between readBean and setBean.

Hi,

think of it like this: readBean() takes the values that are stored in the object instance, but otherwise it does nothing. So basically it only calls getters. In turn setBean() takes the object instance and makes it THE object in the Binder. Once you have called setBean() and make changes to the field, the setters of the object are called and the values inside it are updated.

-Olli

I can’t clean bean after i submit form . how cam i solve my problem . thank you

I don’t understand if it’s related to the “bug”. Perhaps we can help you with a code snippet to reproduce your problem.

Thank you so much guy . Now it working normaly