Skip to content

Commit

Permalink
fix: Skip value change event from writing back of converted value
Browse files Browse the repository at this point in the history
(#12360)

This is both a optimization by skipping duplicate validation round and
avoids ConcurrentModificationExpectation being thrown certain corner
cases.
  • Loading branch information
TatuLund authored and Ansku committed Aug 9, 2021
1 parent ab52661 commit 5a37e5f
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 1 deletion.
5 changes: 4 additions & 1 deletion server/src/main/java/com/vaadin/data/Binder.java
Original file line number Diff line number Diff line change
Expand Up @@ -1103,6 +1103,7 @@ protected static class BindingImpl<BEAN, FIELDVALUE, TARGET>

private Registration onValueChange;
private boolean valueInit = false;
private boolean convertedBack = false;

/**
* Contains all converters and validators chained together in the
Expand Down Expand Up @@ -1283,7 +1284,8 @@ private FIELDVALUE convertToFieldType(TARGET target) {
private void handleFieldValueChange(
ValueChangeEvent<FIELDVALUE> event) {
// Don't handle change events when setting initial value
if (valueInit) {
if (valueInit || convertedBack) {
convertedBack = false;
return;
}

Expand Down Expand Up @@ -1313,6 +1315,7 @@ private BindingValidationStatus<TARGET> writeFieldValue(BEAN bean) {
if (convertBackToPresentation && value != null) {
FIELDVALUE converted = convertToFieldType(value);
if (!Objects.equals(field.getValue(), converted)) {
convertedBack = true;
getField().setValue(converted);
}
}
Expand Down
31 changes: 31 additions & 0 deletions server/src/test/java/com/vaadin/data/BinderTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import com.vaadin.data.Binder.Binding;
import com.vaadin.data.Binder.BindingBuilder;
import com.vaadin.data.converter.StringToBigDecimalConverter;
import com.vaadin.data.converter.StringToDoubleConverter;
import com.vaadin.data.converter.StringToIntegerConverter;
import com.vaadin.data.validator.IntegerRangeValidator;
import com.vaadin.data.validator.NotEmptyValidator;
Expand All @@ -43,6 +44,8 @@

public class BinderTest extends BinderTestBase<Binder<Person>, Person> {

private int count;

@Rule
/*
* transient to avoid interfering with serialization tests that capture a
Expand Down Expand Up @@ -1487,6 +1490,34 @@ public void nullAcceptingField_nullValue_originalExceptionIsThrown() {
binder.readBean(new AtomicReference<>(null));
}

// See: https://github.com/vaadin/framework/issues/12356
@Test
public void validationShouldNotRunTwice() {
TextField salaryField = new TextField();
count = 0;
item.setSalaryDouble(100d);
binder.forField(salaryField)
.withConverter(new StringToDoubleConverter(""))
.bind(Person::getSalaryDouble, Person::setSalaryDouble);
binder.setBean(item);
binder.addValueChangeListener(event -> {
count++;
});

salaryField.setValue("1000");
assertTrue(binder.isValid());

salaryField.setValue("salary");
assertFalse(binder.isValid());

salaryField.setValue("2000");

// Without fix for #12356 count will be 5
assertEquals(3, count);

assertEquals(new Double(2000), item.getSalaryDouble());
}

private TextField createNullAnd42RejectingFieldWithEmptyValue(
String emptyValue) {
return new TextField() {
Expand Down

0 comments on commit 5a37e5f

Please sign in to comment.