aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDenis <denis@vaadin.com>2017-02-08 09:43:34 +0200
committerPekka Hyvönen <pekka@vaadin.com>2017-02-08 09:43:34 +0200
commit8c7974592f2a3fb289773c53c5ffe06481ff51b8 (patch)
tree16bf3f3f28d784af539e9d752ff3d864460739df
parentb57a9cbd6e2d6eeed83e7d9ddd0e61561b3cd557 (diff)
downloadvaadin-framework-8c7974592f2a3fb289773c53c5ffe06481ff51b8.tar.gz
vaadin-framework-8c7974592f2a3fb289773c53c5ffe06481ff51b8.zip
Throw if there are no automatically bound fields via bindInstanceFields. (#8481)
* Throw if there are no automatically bound fields via bindInstanceFields. Fixes #8362
-rw-r--r--server/src/main/java/com/vaadin/data/Binder.java49
-rw-r--r--server/src/test/java/com/vaadin/data/BinderInstanceFieldTest.java44
2 files changed, 69 insertions, 24 deletions
diff --git a/server/src/main/java/com/vaadin/data/Binder.java b/server/src/main/java/com/vaadin/data/Binder.java
index 5fa486319a..8c5bd09938 100644
--- a/server/src/main/java/com/vaadin/data/Binder.java
+++ b/server/src/main/java/com/vaadin/data/Binder.java
@@ -31,7 +31,7 @@ import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
-import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -1579,7 +1579,7 @@ public class Binder<BEAN> implements Serializable {
fireStatusChangeEvent(validationStatus.hasErrors());
return validationStatus;
}
-
+
/**
* Runs all currently configured field level validators, as well as all bean
* level validators if a bean is currently set with
@@ -1593,10 +1593,9 @@ public class Binder<BEAN> implements Serializable {
*/
public boolean isValid() {
if (getBean() == null && !validators.isEmpty()) {
- throw new IllegalStateException(
- "Cannot validate binder: "
- + "bean level validators have been configured "
- + "but no bean is currently set");
+ throw new IllegalStateException("Cannot validate binder: "
+ + "bean level validators have been configured "
+ + "but no bean is currently set");
}
if (validateBindings().stream().filter(BindingValidationStatus::isError)
.findAny().isPresent()) {
@@ -2104,13 +2103,23 @@ public class Binder<BEAN> implements Serializable {
public void bindInstanceFields(Object objectWithMemberFields) {
Class<?> objectClass = objectWithMemberFields.getClass();
- getFieldsInDeclareOrder(objectClass).stream()
+ Integer numberOfBoundFields = getFieldsInDeclareOrder(objectClass)
+ .stream()
.filter(memberField -> HasValue.class
.isAssignableFrom(memberField.getType()))
- .forEach(memberField -> handleProperty(memberField,
+ .map(memberField -> handleProperty(memberField,
objectWithMemberFields,
(property, type) -> bindProperty(objectWithMemberFields,
- memberField, property, type)));
+ memberField, property, type)))
+ .reduce(0, this::accumulate, Integer::sum);
+ if (numberOfBoundFields == 0) {
+ throw new IllegalStateException("There are no instance fields "
+ + "found for automatic binding");
+ }
+ }
+
+ private int accumulate(int count, boolean value) {
+ return value ? count + 1 : count;
}
@SuppressWarnings("unchecked")
@@ -2141,9 +2150,10 @@ public class Binder<BEAN> implements Serializable {
* property name to bind
* @param propertyType
* type of the property
+ * @return {@code true} if property is successfully bound
*/
- private void bindProperty(Object objectWithMemberFields, Field memberField,
- String property, Class<?> propertyType) {
+ private boolean bindProperty(Object objectWithMemberFields,
+ Field memberField, String property, Class<?> propertyType) {
Type valueType = GenericTypeReflector.getTypeParameter(
memberField.getGenericType(),
HasValue.class.getTypeParameters()[0]);
@@ -2163,7 +2173,7 @@ public class Binder<BEAN> implements Serializable {
} catch (IllegalArgumentException | IllegalAccessException
| InvocationTargetException e) {
// If we cannot determine the value, just skip the field
- return;
+ return false;
}
if (field == null) {
field = makeFieldInstance(
@@ -2171,6 +2181,7 @@ public class Binder<BEAN> implements Serializable {
initializeField(objectWithMemberFields, memberField, field);
}
forField(field).bind(property);
+ return true;
} else {
throw new IllegalStateException(String.format(
"Property type '%s' doesn't "
@@ -2243,29 +2254,31 @@ public class Binder<BEAN> implements Serializable {
}
}
- private void handleProperty(Field field, Object objectWithMemberFields,
- BiConsumer<String, Class<?>> propertyHandler) {
+ private boolean handleProperty(Field field, Object objectWithMemberFields,
+ BiFunction<String, Class<?>, Boolean> propertyHandler) {
Optional<PropertyDefinition<BEAN, ?>> descriptor = getPropertyDescriptor(
field);
if (!descriptor.isPresent()) {
- return;
+ return false;
}
String propertyName = descriptor.get().getName();
if (boundProperties.containsKey(propertyName)) {
- return;
+ return false;
}
BindingBuilder<BEAN, ?> tentativeBinding = getIncompleteMemberFieldBinding(
field, objectWithMemberFields);
if (tentativeBinding != null) {
tentativeBinding.bind(propertyName);
- return;
+ return false;
}
- propertyHandler.accept(propertyName, descriptor.get().getType());
+ Boolean isPropertyBound = propertyHandler.apply(propertyName,
+ descriptor.get().getType());
assert boundProperties.containsKey(propertyName);
+ return isPropertyBound;
}
/**
diff --git a/server/src/test/java/com/vaadin/data/BinderInstanceFieldTest.java b/server/src/test/java/com/vaadin/data/BinderInstanceFieldTest.java
index de58be5e42..4b3bff2db6 100644
--- a/server/src/test/java/com/vaadin/data/BinderInstanceFieldTest.java
+++ b/server/src/test/java/com/vaadin/data/BinderInstanceFieldTest.java
@@ -50,8 +50,15 @@ public class BinderInstanceFieldTest {
private TextField noFieldInPerson;
}
- public static class BindNoHasValueField extends FormLayout {
+ public static class BindWithNoFieldInPerson extends FormLayout {
+ private TextField firstName;
+ private DateField birthDate;
+ private TextField noFieldInPerson;
+ }
+
+ public static class BindFieldHasWrongType extends FormLayout {
private String firstName;
+ private DateField birthDate;
}
public static class BindGenericField extends FormLayout {
@@ -174,7 +181,7 @@ public class BinderInstanceFieldTest {
@Test
public void bindInstanceFields_bindNotHasValueField_fieldIsNull() {
- BindNoHasValueField form = new BindNoHasValueField();
+ BindFieldHasWrongType form = new BindFieldHasWrongType();
Binder<Person> binder = new Binder<>(Person.class);
binder.bindInstanceFields(form);
@@ -266,14 +273,12 @@ public class BinderInstanceFieldTest {
@Test
public void bindInstanceFields_bindNotHasValueField_fieldIsNotReplaced() {
- BindNoHasValueField form = new BindNoHasValueField();
+ BindFieldHasWrongType form = new BindFieldHasWrongType();
Binder<Person> binder = new Binder<>(Person.class);
String name = "foo";
form.firstName = name;
- binder.bindInstanceFields(form);
-
Person person = new Person();
person.setFirstName("foo");
@@ -343,7 +348,7 @@ public class BinderInstanceFieldTest {
@Test
public void bindInstanceFields_fieldsAreConfigured_customBindingIsNotReplaced() {
- BindOnlyOneField form = new BindOnlyOneField();
+ BindWithNoFieldInPerson form = new BindWithNoFieldInPerson();
Binder<Person> binder = new Binder<>(Person.class);
TextField name = new TextField();
@@ -385,4 +390,31 @@ public class BinderInstanceFieldTest {
Assert.assertFalse(binder.validate().isOk());
}
+
+ @Test(expected = IllegalStateException.class)
+ public void bindInstanceFields_explicitelyBoundFieldAndNotBoundField_throwNoBoundFields() {
+ BindOnlyOneField form = new BindOnlyOneField();
+ Binder<Person> binder = new Binder<>(Person.class);
+
+ binder.forField(new TextField()).bind("firstName");
+
+ binder.bindInstanceFields(form);
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void bindInstanceFields_tentativelyBoundFieldAndNotBoundField_throwNoBoundFields() {
+ BindOnlyOneField form = new BindOnlyOneField();
+ Binder<Person> binder = new Binder<>(Person.class);
+
+ TextField field = new TextField();
+ form.firstName = field;
+
+ // This is an incomplete binding which is supposed to be configured
+ // manually
+ binder.forMemberField(field);
+
+ // bindInstance expects at least one auto configured field (there is no
+ // such, only incomplete one) and fails
+ binder.bindInstanceFields(form);
+ }
}