Changed behavior when setting read only

I’ve got a question about a change in the behavior of binders after upgrading our dependencies from Vaadin 8.3.3 to 8.4.0 (and later).

From 8.4.0 and onwards, setting Binder.setReadOnly(true) and afterwards AbstractField.setReadOnly(false) results in a value change event being fired but the bean in the binder not being changed.
In 8.3.3 the behavior has been different: In the mentioned case, a value change event would have been fired and the bean itself would have been changed as well.

Is this a planned change in behavior? I’m asking because I could not find a relevant release note mentioning this change.

I have added a minimal working example below:

public class TestDesign extends VerticalLayout {

protected Button btnPrint;
protected DateField date;
protected DateTimeField datetime;

public TestDesign() {
	Design.read(this);
}

}

import java.time.LocalDate;
import java.time.LocalDateTime;

import javax.annotation.PostConstruct;

import com.vaadin.data.Binder;
import com.vaadin.data.HasValue.ValueChangeEvent;
import com.vaadin.navigator.View;
import com.vaadin.spring.annotation.SpringView;
import com.vaadin.spring.annotation.UIScope;

@SpringView(name = “test”)
@UIScope
@SuppressWarnings({“serial”, “nls”})
public class TestView extends TestDesign implements View {

protected final Binder<TestPojo> binder = new Binder<>(TestPojo.class);

public TestView() {
	bind();
}

private void bind() {
	binder.forMemberField(date);
	binder.forMemberField(datetime);
	binder.addValueChangeListener(TestView::showChanges);
	binder.bindInstanceFields(this);

// binder.setReadOnly(true); // setting this to true will always change changes to the bean, even if AbstractField.setReadOnly(false) is called afterwards

	TestPojo pojo = new TestPojo();
	binder.setBean(pojo);
}

@PostConstruct
private void initComponents() {
	date.setReadOnly(false);
	datetime.setReadOnly(false);
	btnPrint.addClickListener(event -> printPojoValues());
}

private void printPojoValues() {
	TestPojo pojo = binder.getBean();

	System.out.println("Bean:");
	System.out.println("date: " + pojo.getDate());
	System.out.println("datetime: " + pojo.getDatetime());
}


private static <T> void showChanges(ValueChangeEvent<T> event) {
	System.out.println("Event:");
	System.out.println("user? " + event.isUserOriginated());
	System.out.println("old: " + event.getOldValue());
	System.out.println("new: " + event.getValue());
}

public static class TestPojo {
	private LocalDate date;
	private LocalDateTime datetime;
	
	public LocalDate getDate() {
		return date;
	}
	
	public LocalDateTime getDatetime() {
		return datetime;
	}
	
	public void setDate(LocalDate date) {
		this.date = date;
	}
	
	public void setDatetime(LocalDateTime datetime) {
		this.datetime = datetime;
	}
}

}

Hey Fabian,

There’s a commit related to this in the new release:
https://github.com/vaadin/framework/commit/4cacbf7d7fda2918bfb030c49cc6776a07bf6a9c

from the code, calling binder.setReadOnly(boolean) will trigger the field.setReadOnly. But doesn’t work the other way around, which is his case. So i think it is normal to have the current behavior…

binder is a quite complicated part of framework, so I might be wrong…

and in the javadoc, it stated
This helper method is the preferred way to control the read-only state of the bound field. which means
You give the Field to the Binder, after which the Binder should be the one responsible to keep it's state correct. ie. set value, set required.. Making the binding read-only makes it also so that you can use the binder to copy values from one bean to another, but only display some value (for example creation timestamp or an id). setting the timestamp binding read-only will show the value it read from, but will not write it to the new bean you store the value to. If you only call it for the field, then the timestamp will be written to the new object.

Hope this helps!

Thank you. It’s good to know that this is indeed an intended change of behavior and not a bug. I have updated our programs to, instead, use the methods on the bindings now.

I hope that the amount of changes breaking backwards compatibility is not going to increase in future releases.