You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

BinderTest.java 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  1. package com.vaadin.data;
  2. import static org.junit.Assert.assertEquals;
  3. import static org.junit.Assert.assertFalse;
  4. import static org.junit.Assert.assertSame;
  5. import static org.junit.Assert.assertTrue;
  6. import java.util.Locale;
  7. import java.util.Objects;
  8. import java.util.concurrent.atomic.AtomicInteger;
  9. import org.junit.Assert;
  10. import org.junit.Before;
  11. import org.junit.Test;
  12. import com.vaadin.data.Binder.BindingBuilder;
  13. import com.vaadin.data.util.converter.StringToIntegerConverter;
  14. import com.vaadin.data.validator.NotEmptyValidator;
  15. import com.vaadin.server.ErrorMessage;
  16. import com.vaadin.tests.data.bean.Person;
  17. import com.vaadin.tests.data.bean.Sex;
  18. import com.vaadin.ui.TextField;
  19. public class BinderTest extends BinderTestBase<Binder<Person>, Person> {
  20. @Before
  21. public void setUp() {
  22. binder = new Binder<>();
  23. item = new Person();
  24. item.setFirstName("Johannes");
  25. item.setAge(32);
  26. }
  27. @Test
  28. public void bindNullBean_noBeanPresent() {
  29. binder.setBean(item);
  30. assertTrue(binder.getBean().isPresent());
  31. binder.setBean(null);
  32. assertFalse(binder.getBean().isPresent());
  33. }
  34. @Test(expected = NullPointerException.class)
  35. public void bindNullField_throws() {
  36. binder.forField(null);
  37. }
  38. @Test(expected = NullPointerException.class)
  39. public void bindNullGetter_throws() {
  40. binder.bind(nameField, null, Person::setFirstName);
  41. }
  42. @Test
  43. public void fieldBound_bindItem_fieldValueUpdated() {
  44. binder.forField(nameField).bind(Person::getFirstName,
  45. Person::setFirstName);
  46. binder.setBean(item);
  47. assertEquals("Johannes", nameField.getValue());
  48. }
  49. @Test
  50. public void fieldBoundWithShortcut_bindBean_fieldValueUpdated() {
  51. bindName();
  52. assertEquals("Johannes", nameField.getValue());
  53. }
  54. @Test
  55. public void beanBound_updateFieldValue_beanValueUpdated() {
  56. binder.setBean(item);
  57. binder.bind(nameField, Person::getFirstName, Person::setFirstName);
  58. assertEquals("Johannes", nameField.getValue());
  59. nameField.setValue("Artur");
  60. assertEquals("Artur", item.getFirstName());
  61. }
  62. @Test
  63. public void bound_getBean_returnsBoundBean() {
  64. assertFalse(binder.getBean().isPresent());
  65. binder.setBean(item);
  66. assertSame(item, binder.getBean().get());
  67. }
  68. @Test
  69. public void unbound_getBean_returnsNothing() {
  70. binder.setBean(item);
  71. binder.removeBean();
  72. assertFalse(binder.getBean().isPresent());
  73. }
  74. @Test
  75. public void bound_changeFieldValue_beanValueUpdated() {
  76. bindName();
  77. nameField.setValue("Henri");
  78. assertEquals("Henri", item.getFirstName());
  79. }
  80. @Test
  81. public void unbound_changeFieldValue_beanValueNotUpdated() {
  82. bindName();
  83. nameField.setValue("Henri");
  84. binder.removeBean();
  85. nameField.setValue("Aleksi");
  86. assertEquals("Henri", item.getFirstName());
  87. }
  88. @Test
  89. public void bindNullSetter_valueChangesIgnored() {
  90. binder.bind(nameField, Person::getFirstName, null);
  91. binder.setBean(item);
  92. nameField.setValue("Artur");
  93. assertEquals(item.getFirstName(), "Johannes");
  94. }
  95. @Test
  96. public void bound_bindToAnotherBean_stopsUpdatingOriginal() {
  97. bindName();
  98. nameField.setValue("Leif");
  99. Person p2 = new Person();
  100. p2.setFirstName("Marlon");
  101. binder.setBean(p2);
  102. assertEquals("Marlon", nameField.getValue());
  103. assertEquals("Leif", item.getFirstName());
  104. assertSame(p2, binder.getBean().get());
  105. nameField.setValue("Ilia");
  106. assertEquals("Ilia", p2.getFirstName());
  107. assertEquals("Leif", item.getFirstName());
  108. }
  109. @Test
  110. public void save_unbound_noChanges() throws ValidationException {
  111. Binder<Person> binder = new Binder<>();
  112. Person person = new Person();
  113. int age = 10;
  114. person.setAge(age);
  115. binder.writeBean(person);
  116. Assert.assertEquals(age, person.getAge());
  117. }
  118. @Test
  119. public void save_bound_beanIsUpdated() throws ValidationException {
  120. Binder<Person> binder = new Binder<>();
  121. binder.bind(nameField, Person::getFirstName, Person::setFirstName);
  122. Person person = new Person();
  123. String fieldValue = "bar";
  124. nameField.setValue(fieldValue);
  125. person.setFirstName("foo");
  126. binder.writeBean(person);
  127. Assert.assertEquals(fieldValue, person.getFirstName());
  128. }
  129. @Test
  130. public void load_bound_fieldValueIsUpdated() {
  131. binder.bind(nameField, Person::getFirstName, Person::setFirstName);
  132. Person person = new Person();
  133. String name = "bar";
  134. person.setFirstName(name);
  135. binder.readBean(person);
  136. Assert.assertEquals(name, nameField.getValue());
  137. }
  138. @Test
  139. public void load_unbound_noChanges() {
  140. nameField.setValue("");
  141. Person person = new Person();
  142. String name = "bar";
  143. person.setFirstName(name);
  144. binder.readBean(person);
  145. Assert.assertEquals("", nameField.getValue());
  146. }
  147. protected void bindName() {
  148. binder.bind(nameField, Person::getFirstName, Person::setFirstName);
  149. binder.setBean(item);
  150. }
  151. @Test
  152. public void binding_with_null_representation() {
  153. String nullRepresentation = "Some arbitrary text";
  154. String realName = "John";
  155. Person namelessPerson = new Person(null, "Doe", "", 25, Sex.UNKNOWN,
  156. null);
  157. binder.forField(nameField).withNullRepresentation(nullRepresentation)
  158. .bind(Person::getFirstName, Person::setFirstName);
  159. // Bind a person with null value and check that null representation is
  160. // used
  161. binder.setBean(namelessPerson);
  162. Assert.assertEquals(
  163. "Null value from bean was not converted to explicit null representation",
  164. nullRepresentation, nameField.getValue());
  165. // Verify that changes are applied to bean
  166. nameField.setValue(realName);
  167. Assert.assertEquals(
  168. "Bean was not correctly updated from a change in the field",
  169. realName, namelessPerson.getFirstName());
  170. // Verify conversion back to null
  171. nameField.setValue(nullRepresentation);
  172. Assert.assertEquals(
  173. "Two-way null representation did not change value back to null",
  174. null, namelessPerson.getFirstName());
  175. }
  176. @Test
  177. public void binding_with_default_null_representation() {
  178. TextField nullTextField = new TextField() {
  179. @Override
  180. public String getEmptyValue() {
  181. return "null";
  182. }
  183. };
  184. Person namelessPerson = new Person(null, "Doe", "", 25, Sex.UNKNOWN,
  185. null);
  186. binder.bind(nullTextField, Person::getFirstName, Person::setFirstName);
  187. binder.setBean(namelessPerson);
  188. Assert.assertTrue(nullTextField.isEmpty());
  189. Assert.assertEquals(null, namelessPerson.getFirstName());
  190. // Change value, see that textfield is not empty and bean is updated.
  191. nullTextField.setValue("");
  192. Assert.assertFalse(nullTextField.isEmpty());
  193. Assert.assertEquals("First name of person was not properly updated", "",
  194. namelessPerson.getFirstName());
  195. // Verify that default null representation does not map back to null
  196. nullTextField.setValue("null");
  197. Assert.assertTrue(nullTextField.isEmpty());
  198. Assert.assertEquals("Default one-way null representation failed.",
  199. "null", namelessPerson.getFirstName());
  200. }
  201. @Test
  202. public void binding_with_null_representation_value_not_null() {
  203. String nullRepresentation = "Some arbitrary text";
  204. binder.forField(nameField).withNullRepresentation(nullRepresentation)
  205. .bind(Person::getFirstName, Person::setFirstName);
  206. Assert.assertFalse("First name in item should not be null",
  207. Objects.isNull(item.getFirstName()));
  208. binder.setBean(item);
  209. Assert.assertEquals("Field value was not set correctly",
  210. item.getFirstName(), nameField.getValue());
  211. }
  212. @Test
  213. public void withConverter_disablesDefaulNullRepresentation() {
  214. Integer customNullConverter = 0;
  215. binder.forField(ageField).withNullRepresentation("foo")
  216. .withConverter(new StringToIntegerConverter(""))
  217. .withConverter(age -> age,
  218. age -> age == null ? customNullConverter : age)
  219. .bind(Person::getSalary, Person::setSalary);
  220. binder.setBean(item);
  221. Assert.assertEquals(customNullConverter.toString(),
  222. ageField.getValue());
  223. Integer salary = 11;
  224. ageField.setValue(salary.toString());
  225. Assert.assertEquals(11, salary.intValue());
  226. }
  227. @Test
  228. public void beanBinder_nullRepresentationIsNotDisabled() {
  229. BeanBinder<Person> binder = new BeanBinder<>(Person.class);
  230. binder.forField(nameField).bind("firstName");
  231. Person person = new Person();
  232. binder.setBean(person);
  233. Assert.assertEquals("", nameField.getValue());
  234. }
  235. @Test
  236. public void beanBinder_withConverter_nullRepresentationIsNotDisabled() {
  237. String customNullPointerRepresentation = "foo";
  238. BeanBinder<Person> binder = new BeanBinder<>(Person.class);
  239. binder.forField(nameField)
  240. .withConverter(value -> value, value -> value == null
  241. ? customNullPointerRepresentation : value)
  242. .bind("firstName");
  243. Person person = new Person();
  244. binder.setBean(person);
  245. Assert.assertEquals(customNullPointerRepresentation,
  246. nameField.getValue());
  247. }
  248. @Test
  249. public void withValidator_doesNotDisablesDefaulNullRepresentation() {
  250. String nullRepresentation = "foo";
  251. binder.forField(nameField).withNullRepresentation(nullRepresentation)
  252. .withValidator(new NotEmptyValidator<>(""))
  253. .bind(Person::getFirstName, Person::setFirstName);
  254. item.setFirstName(null);
  255. binder.setBean(item);
  256. Assert.assertEquals(nullRepresentation, nameField.getValue());
  257. String newValue = "bar";
  258. nameField.setValue(newValue);
  259. Assert.assertEquals(newValue, item.getFirstName());
  260. }
  261. @Test
  262. public void setRequired_withErrorMessage_fieldGetsRequiredIndicatorAndValidator() {
  263. TextField textField = new TextField();
  264. Assert.assertFalse(textField.isRequiredIndicatorVisible());
  265. BindingBuilder<Person, String> binding = binder.forField(textField);
  266. Assert.assertFalse(textField.isRequiredIndicatorVisible());
  267. binding.setRequired("foobar");
  268. Assert.assertTrue(textField.isRequiredIndicatorVisible());
  269. binding.bind(Person::getFirstName, Person::setFirstName);
  270. binder.setBean(item);
  271. Assert.assertNull(textField.getErrorMessage());
  272. textField.setValue(textField.getEmptyValue());
  273. ErrorMessage errorMessage = textField.getErrorMessage();
  274. Assert.assertNotNull(errorMessage);
  275. Assert.assertEquals("foobar", errorMessage.getFormattedHtmlMessage());
  276. textField.setValue("value");
  277. Assert.assertNull(textField.getErrorMessage());
  278. Assert.assertTrue(textField.isRequiredIndicatorVisible());
  279. }
  280. @Test
  281. public void setRequired_withErrorMessageProvider_fieldGetsRequiredIndicatorAndValidator() {
  282. TextField textField = new TextField();
  283. textField.setLocale(Locale.CANADA);
  284. Assert.assertFalse(textField.isRequiredIndicatorVisible());
  285. BindingBuilder<Person, String> binding = binder.forField(textField);
  286. Assert.assertFalse(textField.isRequiredIndicatorVisible());
  287. AtomicInteger invokes = new AtomicInteger();
  288. binding.setRequired(context -> {
  289. invokes.incrementAndGet();
  290. Assert.assertSame(Locale.CANADA, context.getLocale().get());
  291. return "foobar";
  292. });
  293. Assert.assertTrue(textField.isRequiredIndicatorVisible());
  294. binding.bind(Person::getFirstName, Person::setFirstName);
  295. binder.setBean(item);
  296. Assert.assertNull(textField.getErrorMessage());
  297. Assert.assertEquals(0, invokes.get());
  298. textField.setValue(textField.getEmptyValue());
  299. ErrorMessage errorMessage = textField.getErrorMessage();
  300. Assert.assertNotNull(errorMessage);
  301. Assert.assertEquals("foobar", errorMessage.getFormattedHtmlMessage());
  302. // validation is run twice, once for the field, then for all the fields
  303. // for cross field validation...
  304. Assert.assertEquals(2, invokes.get());
  305. textField.setValue("value");
  306. Assert.assertNull(textField.getErrorMessage());
  307. Assert.assertTrue(textField.isRequiredIndicatorVisible());
  308. }
  309. @Test
  310. public void validationStatusHandler_onlyRunForChangedField() {
  311. TextField firstNameField = new TextField();
  312. TextField lastNameField = new TextField();
  313. AtomicInteger invokes = new AtomicInteger();
  314. binder.forField(firstNameField)
  315. .withValidator(new NotEmptyValidator<>(""))
  316. .withValidationStatusHandler(
  317. validationStatus -> invokes.addAndGet(1))
  318. .bind(Person::getFirstName, Person::setFirstName);
  319. binder.forField(lastNameField)
  320. .withValidator(new NotEmptyValidator<>(""))
  321. .bind(Person::getLastName, Person::setLastName);
  322. binder.setBean(item);
  323. // setting the bean causes 2:
  324. Assert.assertEquals(2, invokes.get());
  325. lastNameField.setValue("");
  326. Assert.assertEquals(2, invokes.get());
  327. firstNameField.setValue("");
  328. Assert.assertEquals(3, invokes.get());
  329. binder.removeBean();
  330. Person person = new Person();
  331. person.setFirstName("a");
  332. person.setLastName("a");
  333. binder.readBean(person);
  334. // reading from a bean causes 2:
  335. Assert.assertEquals(5, invokes.get());
  336. lastNameField.setValue("");
  337. Assert.assertEquals(5, invokes.get());
  338. firstNameField.setValue("");
  339. Assert.assertEquals(6, invokes.get());
  340. }
  341. }