/*
* Copyright 2000-2016 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.vaadin.data;
import java.time.LocalDate;
import org.junit.Assert;
import org.junit.Test;
import com.vaadin.annotations.PropertyId;
import com.vaadin.data.converter.StringToIntegerConverter;
import com.vaadin.data.validator.StringLengthValidator;
import com.vaadin.tests.data.bean.Person;
import com.vaadin.ui.AbstractField;
import com.vaadin.ui.AbstractTextField;
import com.vaadin.ui.DateField;
import com.vaadin.ui.FormLayout;
import com.vaadin.ui.TextField;
public class BinderInstanceFieldTest {
public static class BindAllFields extends FormLayout {
private TextField firstName;
private DateField birthDate;
}
public static class BindFieldsUsingAnnotation extends FormLayout {
@PropertyId("firstName")
private TextField nameField;
@PropertyId("birthDate")
private DateField birthDateField;
}
public static class BindOnlyOneField extends FormLayout {
private TextField firstName;
private TextField noFieldInPerson;
}
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 {
private CustomField<String> firstName;
}
public static class BindGenericWrongTypeParameterField extends FormLayout {
private CustomField<Boolean> firstName;
}
public static class BindWrongTypeParameterField extends FormLayout {
private IntegerTextField firstName;
}
public static class BindOneFieldRequiresConverter extends FormLayout {
private TextField firstName;
private TextField age;
}
public static class BindGeneric<T> extends FormLayout {
private CustomField<T> firstName;
}
public static class BindRaw extends FormLayout {
private CustomField firstName;
}
public static class BindAbstract extends FormLayout {
private AbstractTextField firstName;
}
public static class BindNonInstantiatableType extends FormLayout {
private NoDefaultCtor firstName;
}
public static class BindComplextHierarchyGenericType extends FormLayout {
private ComplexHierarchy firstName;
}
public static class NoDefaultCtor extends TextField {
public NoDefaultCtor(int arg) {
}
}
public static class IntegerTextField extends CustomField<Integer> {
}
public static class ComplexHierarchy extends Generic<Long> {
}
public static class Generic<T> extends ComplexGeneric<Boolean, String, T> {
}
public static class ComplexGeneric<U, V, S> extends CustomField<V> {
}
public static class CustomField<T> extends AbstractField<T> {
private T value;
@Override
public T getValue() {
return value;
}
@Override
protected void doSetValue(T value) {
this.value = value;
}
}
@Test
public void bindInstanceFields_bindAllFields() {
BindAllFields form = new BindAllFields();
Binder<Person> binder = new Binder<>(Person.class);
binder.bindInstanceFields(form);
Person person = new Person();
person.setFirstName("foo");
person.setBirthDate(LocalDate.now());
binder.setBean(person);
Assert.assertEquals(person.getFirstName(), form.firstName.getValue());
Assert.assertEquals(person.getBirthDate(), form.birthDate.getValue());
form.firstName.setValue("bar");
form.birthDate.setValue(person.getBirthDate().plusDays(345));
Assert.assertEquals(form.firstName.getValue(), person.getFirstName());
Assert.assertEquals(form.birthDate.getValue(), person.getBirthDate());
}
@Test(expected = IllegalStateException.class)
public void bind_instanceFields_noArgsConstructor() {
BindAllFields form = new BindAllFields();
Binder<Person> binder = new Binder<>();
binder.bindInstanceFields(form);
}
@Test
public void bindInstanceFields_bindOnlyOneFields() {
BindOnlyOneField form = new BindOnlyOneField();
Binder<Person> binder = new Binder<>(Person.class);
binder.bindInstanceFields(form);
Person person = new Person();
person.setFirstName("foo");
binder.setBean(person);
Assert.assertEquals(person.getFirstName(), form.firstName.getValue());
Assert.assertNull(form.noFieldInPerson);
form.firstName.setValue("bar");
Assert.assertEquals(form.firstName.getValue(), person.getFirstName());
}
@Test
public void bindInstanceFields_bindNotHasValueField_fieldIsNull() {
BindFieldHasWrongType form = new BindFieldHasWrongType();
Binder<Person> binder = new Binder<>(Person.class);
binder.bindInstanceFields(form);
Person person = new Person();
person.setFirstName("foo");
binder.setBean(person);
Assert.assertNull(form.firstName);
}
@Test
public void bindInstanceFields_genericField() {
BindGenericField form = new BindGenericField();
Binder<Person> binder = new Binder<>(Person.class);
binder.bindInstanceFields(form);
Person person = new Person();
person.setFirstName("foo");
binder.setBean(person);
Assert.assertEquals(person.getFirstName(), form.firstName.getValue());
form.firstName.setValue("bar");
Assert.assertEquals(form.firstName.getValue(), person.getFirstName());
}
@Test(expected = IllegalStateException.class)
public void bindInstanceFields_genericFieldWithWrongTypeParameter() {
BindGenericWrongTypeParameterField form = new BindGenericWrongTypeParameterField();
Binder<Person> binder = new Binder<>(Person.class);
binder.bindInstanceFields(form);
}
@Test(expected = IllegalStateException.class)
public void bindInstanceFields_generic() {
BindGeneric<String> form = new BindGeneric<>();
Binder<Person> binder = new Binder<>(Person.class);
binder.bindInstanceFields(form);
}
@Test(expected = IllegalStateException.class)
public void bindInstanceFields_rawFieldType() {
BindRaw form = new BindRaw();
Binder<Person> binder = new Binder<>(Person.class);
binder.bindInstanceFields(form);
}
@Test(expected = IllegalStateException.class)
public void bindInstanceFields_abstractFieldType() {
BindAbstract form = new BindAbstract();
Binder<Person> binder = new Binder<>(Person.class);
binder.bindInstanceFields(form);
}
@Test(expected = IllegalStateException.class)
public void bindInstanceFields_noInstantiatableFieldType() {
BindNonInstantiatableType form = new BindNonInstantiatableType();
Binder<Person> binder = new Binder<>(Person.class);
binder.bindInstanceFields(form);
}
@Test(expected = IllegalStateException.class)
public void bindInstanceFields_wrongFieldType() {
BindWrongTypeParameterField form = new BindWrongTypeParameterField();
Binder<Person> binder = new Binder<>(Person.class);
binder.bindInstanceFields(form);
}
@Test
public void bindInstanceFields_complexGenericHierarchy() {
BindComplextHierarchyGenericType form = new BindComplextHierarchyGenericType();
Binder<Person> binder = new Binder<>(Person.class);
binder.bindInstanceFields(form);
Person person = new Person();
person.setFirstName("foo");
binder.setBean(person);
Assert.assertEquals(person.getFirstName(), form.firstName.getValue());
form.firstName.setValue("bar");
Assert.assertEquals(form.firstName.getValue(), person.getFirstName());
}
@Test
public void bindInstanceFields_bindNotHasValueField_fieldIsNotReplaced() {
BindFieldHasWrongType form = new BindFieldHasWrongType();
Binder<Person> binder = new Binder<>(Person.class);
String name = "foo";
form.firstName = name;
Person person = new Person();
person.setFirstName("foo");
binder.setBean(person);
Assert.assertEquals(name, form.firstName);
}
@Test
public void bindInstanceFields_bindAllFieldsUsingAnnotations() {
BindFieldsUsingAnnotation form = new BindFieldsUsingAnnotation();
Binder<Person> binder = new Binder<>(Person.class);
binder.bindInstanceFields(form);
Person person = new Person();
person.setFirstName("foo");
person.setBirthDate(LocalDate.now());
binder.setBean(person);
Assert.assertEquals(person.getFirstName(), form.nameField.getValue());
Assert.assertEquals(person.getBirthDate(),
form.birthDateField.getValue());
form.nameField.setValue("bar");
form.birthDateField.setValue(person.getBirthDate().plusDays(345));
Assert.assertEquals(form.nameField.getValue(), person.getFirstName());
Assert.assertEquals(form.birthDateField.getValue(),
person.getBirthDate());
}
@Test
public void bindInstanceFields_bindNotBoundFieldsOnly_customBindingIsNotReplaced() {
BindAllFields form = new BindAllFields();
Binder<Person> binder = new Binder<>(Person.class);
TextField name = new TextField();
form.firstName = name;
binder.forField(form.firstName)
.withValidator(
new StringLengthValidator("Name is invalid", 3, 10))
.bind("firstName");
binder.bindInstanceFields(form);
Person person = new Person();
String personName = "foo";
person.setFirstName(personName);
person.setBirthDate(LocalDate.now());
binder.setBean(person);
Assert.assertEquals(person.getFirstName(), form.firstName.getValue());
Assert.assertEquals(person.getBirthDate(), form.birthDate.getValue());
// the instance is not overridden
Assert.assertEquals(name, form.firstName);
form.firstName.setValue("aa");
form.birthDate.setValue(person.getBirthDate().plusDays(345));
Assert.assertEquals(personName, person.getFirstName());
Assert.assertEquals(form.birthDate.getValue(), person.getBirthDate());
Assert.assertFalse(binder.validate().isOk());
}
@Test
public void bindInstanceFields_fieldsAreConfigured_customBindingIsNotReplaced() {
BindWithNoFieldInPerson form = new BindWithNoFieldInPerson();
Binder<Person> binder = new Binder<>(Person.class);
TextField name = new TextField();
form.firstName = name;
binder.forField(form.firstName)
.withValidator(
new StringLengthValidator("Name is invalid", 3, 10))
.bind("firstName");
TextField ageField = new TextField();
form.noFieldInPerson = ageField;
binder.forField(form.noFieldInPerson)
.withConverter(new StringToIntegerConverter(""))
.bind(Person::getAge, Person::setAge);
binder.bindInstanceFields(form);
Person person = new Person();
String personName = "foo";
int age = 11;
person.setFirstName(personName);
person.setAge(age);
binder.setBean(person);
Assert.assertEquals(person.getFirstName(), form.firstName.getValue());
Assert.assertEquals(String.valueOf(person.getAge()),
form.noFieldInPerson.getValue());
// the instances are not overridden
Assert.assertEquals(name, form.firstName);
Assert.assertEquals(ageField, form.noFieldInPerson);
form.firstName.setValue("aa");
age += 56;
form.noFieldInPerson.setValue(String.valueOf(age));
Assert.assertEquals(personName, person.getFirstName());
Assert.assertEquals(form.noFieldInPerson.getValue(),
String.valueOf(person.getAge()));
Assert.assertFalse(binder.validate().isOk());
}
@Test
public void bindInstanceFields_preconfiguredFieldNotBoundToPropertyPreserved() {
BindOneFieldRequiresConverter form = new BindOneFieldRequiresConverter();
form.age = new TextField();
form.firstName = new TextField();
Binder<Person> binder = new Binder<>(Person.class);
binder.forField(form.age)
.withConverter(str -> Integer.parseInt(str) / 2,
integer -> Integer.toString(integer * 2))
.bind(Person::getAge, Person::setAge);
binder.bindInstanceFields(form);
Person person = new Person();
person.setFirstName("first");
person.setAge(45);
binder.setBean(person);
Assert.assertEquals("90", form.age.getValue());
}
@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);
}
}