Browse Source

Throw if there are no automatically bound fields via bindInstanceFields. (#8481)

* Throw if there are no automatically bound fields via bindInstanceFields.

Fixes #8362
tags/8.0.0.rc1
Denis 7 years ago
parent
commit
8c7974592f

+ 31
- 18
server/src/main/java/com/vaadin/data/Binder.java View File

@@ -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;
}

/**

+ 38
- 6
server/src/test/java/com/vaadin/data/BinderInstanceFieldTest.java View File

@@ -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);
}
}

Loading…
Cancel
Save