您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

BeanBinderTest.java 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  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.io.Serializable;
  7. import java.time.LocalDate;
  8. import java.util.List;
  9. import java.util.Set;
  10. import javax.validation.constraints.Digits;
  11. import javax.validation.constraints.Max;
  12. import javax.validation.constraints.NotNull;
  13. import javax.validation.constraints.Size;
  14. import org.hibernate.validator.constraints.NotEmpty;
  15. import org.junit.Before;
  16. import org.junit.Test;
  17. import com.vaadin.data.BeanBinderTest.RequiredConstraints.SubConstraint;
  18. import com.vaadin.data.BeanBinderTest.RequiredConstraints.SubSubConstraint;
  19. import com.vaadin.data.converter.StringToIntegerConverter;
  20. import com.vaadin.tests.data.bean.BeanToValidate;
  21. import com.vaadin.ui.CheckBoxGroup;
  22. import com.vaadin.ui.TextField;
  23. @SuppressWarnings("unused")
  24. public class BeanBinderTest
  25. extends BinderTestBase<Binder<BeanToValidate>, BeanToValidate> {
  26. private enum TestEnum {
  27. }
  28. private class TestClass {
  29. private CheckBoxGroup<TestEnum> enums;
  30. private TextField number = new TextField();
  31. }
  32. private class TestClassWithoutFields {
  33. }
  34. private static class TestBean implements Serializable {
  35. private Set<TestEnum> enums;
  36. private int number;
  37. public Set<TestEnum> getEnums() {
  38. return enums;
  39. }
  40. public void setEnums(Set<TestEnum> enums) {
  41. this.enums = enums;
  42. }
  43. public int getNumber() {
  44. return number;
  45. }
  46. public void setNumber(int number) {
  47. this.number = number;
  48. }
  49. }
  50. public static class RequiredConstraints implements Serializable {
  51. @NotNull
  52. @Max(10)
  53. private String firstname;
  54. @Size(min = 3, max = 16)
  55. @Digits(integer = 3, fraction = 2)
  56. private String age;
  57. @NotEmpty
  58. private String lastname;
  59. private SubConstraint subfield;
  60. public String getFirstname() {
  61. return firstname;
  62. }
  63. public void setFirstname(String firstname) {
  64. this.firstname = firstname;
  65. }
  66. public String getAge() {
  67. return age;
  68. }
  69. public void setAge(String age) {
  70. this.age = age;
  71. }
  72. public String getLastname() {
  73. return lastname;
  74. }
  75. public void setLastname(String lastname) {
  76. this.lastname = lastname;
  77. }
  78. public SubConstraint getSubfield() {
  79. return subfield;
  80. }
  81. public void setSubfield(SubConstraint subfield) {
  82. this.subfield = subfield;
  83. }
  84. public static class SubConstraint implements Serializable {
  85. @NotNull
  86. @NotEmpty
  87. @Size(min = 5)
  88. private String name;
  89. private SubSubConstraint subsub;
  90. public String getName() {
  91. return name;
  92. }
  93. public void setName(String name) {
  94. this.name = name;
  95. }
  96. public SubSubConstraint getSubsub() {
  97. return subsub;
  98. }
  99. public void setSubsub(SubSubConstraint subsub) {
  100. this.subsub = subsub;
  101. }
  102. }
  103. public static class SubSubConstraint implements Serializable {
  104. @Size(min = 10)
  105. private String value;
  106. public String getValue() {
  107. return value;
  108. }
  109. public void setValue(String value) {
  110. this.value = value;
  111. }
  112. }
  113. }
  114. public static class Person {
  115. LocalDate mydate;
  116. public LocalDate getMydate() {
  117. return mydate;
  118. }
  119. public void setMydate(LocalDate mydate) {
  120. this.mydate = mydate;
  121. }
  122. }
  123. public static class PersonForm {
  124. private TextField mydate = new TextField();
  125. }
  126. @Before
  127. public void setUp() {
  128. binder = new BeanValidationBinder<>(BeanToValidate.class);
  129. item = new BeanToValidate();
  130. item.setFirstname("Johannes");
  131. item.setAge(32);
  132. }
  133. @Test
  134. public void bindInstanceFields_parameters_type_erased() {
  135. Binder<TestBean> otherBinder = new Binder<>(TestBean.class);
  136. TestClass testClass = new TestClass();
  137. otherBinder.forField(testClass.number)
  138. .withConverter(new StringToIntegerConverter("")).bind("number");
  139. // Should correctly bind the enum field without throwing
  140. otherBinder.bindInstanceFields(testClass);
  141. testSerialization(otherBinder);
  142. }
  143. @Test
  144. public void bindInstanceFields_automatically_binds_incomplete_forMemberField_bindings() {
  145. Binder<TestBean> otherBinder = new Binder<>(TestBean.class);
  146. TestClass testClass = new TestClass();
  147. otherBinder.forMemberField(testClass.number)
  148. .withConverter(new StringToIntegerConverter(""));
  149. otherBinder.bindInstanceFields(testClass);
  150. TestBean bean = new TestBean();
  151. otherBinder.setBean(bean);
  152. testClass.number.setValue("50");
  153. assertEquals(50, bean.number);
  154. testSerialization(otherBinder);
  155. }
  156. @Test(expected = IllegalStateException.class)
  157. public void bindInstanceFields_does_not_automatically_bind_incomplete_forField_bindings() {
  158. Binder<TestBean> otherBinder = new Binder<>(TestBean.class);
  159. TestClass testClass = new TestClass();
  160. otherBinder.forField(testClass.number)
  161. .withConverter(new StringToIntegerConverter(""));
  162. // Should throw an IllegalStateException since the binding for number is
  163. // not completed with bind
  164. otherBinder.bindInstanceFields(testClass);
  165. }
  166. @Test(expected = IllegalStateException.class)
  167. public void bindInstanceFields_throw_if_no_fields_bound() {
  168. Binder<TestBean> otherBinder = new Binder<>(TestBean.class);
  169. TestClassWithoutFields testClass = new TestClassWithoutFields();
  170. // Should throw an IllegalStateException no fields are bound
  171. otherBinder.bindInstanceFields(testClass);
  172. }
  173. @Test
  174. public void bindInstanceFields_does_not_throw_if_fields_are_bound_manually() {
  175. PersonForm form = new PersonForm();
  176. Binder<Person> binder = new Binder<>(Person.class);
  177. binder.forMemberField(form.mydate)
  178. .withConverter(str -> LocalDate.now(), date -> "Hello")
  179. .bind("mydate");
  180. binder.bindInstanceFields(form);
  181. }
  182. @Test
  183. public void bindInstanceFields_does_not_throw_if_there_are_incomplete_bindings() {
  184. PersonForm form = new PersonForm();
  185. Binder<Person> binder = new Binder<>(Person.class);
  186. binder.forMemberField(form.mydate).withConverter(str -> LocalDate.now(),
  187. date -> "Hello");
  188. binder.bindInstanceFields(form);
  189. }
  190. @Test(expected = IllegalStateException.class)
  191. public void incomplete_forMemberField_bindings() {
  192. Binder<TestBean> otherBinder = new Binder<>(TestBean.class);
  193. TestClass testClass = new TestClass();
  194. otherBinder.forMemberField(testClass.number)
  195. .withConverter(new StringToIntegerConverter(""));
  196. // Should throw an IllegalStateException since the forMemberField
  197. // binding has not been completed
  198. otherBinder.setBean(new TestBean());
  199. }
  200. @Test
  201. public void fieldBound_bindBean_fieldValueUpdated() {
  202. binder.bind(nameField, "firstname");
  203. binder.setBean(item);
  204. assertEquals("Johannes", nameField.getValue());
  205. }
  206. @Test
  207. public void beanBound_bindField_fieldValueUpdated() {
  208. binder.setBean(item);
  209. binder.bind(nameField, "firstname");
  210. assertEquals("Johannes", nameField.getValue());
  211. }
  212. @Test(expected = IllegalArgumentException.class)
  213. public void bindInvalidPropertyName_throws() {
  214. binder.bind(nameField, "firstnaem");
  215. }
  216. @Test(expected = NullPointerException.class)
  217. public void bindNullPropertyName_throws() {
  218. binder.bind(nameField, null);
  219. }
  220. @Test(expected = IllegalArgumentException.class)
  221. public void bindNonReadableProperty_throws() {
  222. binder.bind(nameField, "writeOnlyProperty");
  223. }
  224. @Test
  225. public void beanBound_setValidFieldValue_propertyValueChanged() {
  226. binder.setBean(item);
  227. binder.bind(nameField, "firstname");
  228. nameField.setValue("Henri");
  229. assertEquals("Henri", item.getFirstname());
  230. }
  231. @Test
  232. public void readOnlyPropertyBound_setFieldValue_ignored() {
  233. binder.bind(nameField, "readOnlyProperty");
  234. binder.setBean(item);
  235. String propertyValue = item.getReadOnlyProperty();
  236. nameField.setValue("Foo");
  237. assertEquals(propertyValue, item.getReadOnlyProperty());
  238. }
  239. @Test
  240. public void bindReadOnlyPropertyShouldMarkFieldAsReadonly() {
  241. binder.bind(nameField, "readOnlyProperty");
  242. assertTrue("Name field should be readonly", nameField.isReadOnly());
  243. }
  244. @Test
  245. public void setReadonlyShouldIgnoreBindingsForReadOnlyProperties() {
  246. binder.bind(nameField, "readOnlyProperty");
  247. binder.setReadOnly(true);
  248. assertTrue("Name field should be ignored and be readonly",
  249. nameField.isReadOnly());
  250. binder.setReadOnly(false);
  251. assertTrue("Name field should be ignored and be readonly",
  252. nameField.isReadOnly());
  253. nameField.setReadOnly(false);
  254. binder.setReadOnly(true);
  255. assertFalse("Name field should be ignored and not be readonly",
  256. nameField.isReadOnly());
  257. binder.setReadOnly(false);
  258. assertFalse("Name field should be ignored and not be readonly",
  259. nameField.isReadOnly());
  260. }
  261. @Test
  262. public void beanBound_setInvalidFieldValue_validationError() {
  263. binder.setBean(item);
  264. binder.bind(nameField, "firstname");
  265. nameField.setValue("H"); // too short
  266. assertEquals("Johannes", item.getFirstname());
  267. assertInvalid(nameField, "size must be between 3 and 16");
  268. }
  269. @Test
  270. public void beanNotBound_setInvalidFieldValue_validationError() {
  271. binder.bind(nameField, "firstname");
  272. nameField.setValue("H"); // too short
  273. assertInvalid(nameField, "size must be between 3 and 16");
  274. }
  275. @Test
  276. public void explicitValidatorAdded_setInvalidFieldValue_explicitValidatorRunFirst() {
  277. binder.forField(nameField).withValidator(name -> name.startsWith("J"),
  278. "name must start with J").bind("firstname");
  279. nameField.setValue("A");
  280. assertInvalid(nameField, "name must start with J");
  281. }
  282. @Test
  283. public void explicitValidatorAdded_setInvalidFieldValue_beanValidatorRun() {
  284. binder.forField(nameField).withValidator(name -> name.startsWith("J"),
  285. "name must start with J").bind("firstname");
  286. nameField.setValue("J");
  287. assertInvalid(nameField, "size must be between 3 and 16");
  288. }
  289. @Test(expected = ClassCastException.class)
  290. public void fieldWithIncompatibleTypeBound_bindBean_throws() {
  291. binder.bind(ageField, "age");
  292. binder.setBean(item);
  293. }
  294. @Test(expected = ClassCastException.class)
  295. public void fieldWithIncompatibleTypeBound_loadBean_throws() {
  296. binder.bind(ageField, "age");
  297. binder.readBean(item);
  298. }
  299. @Test(expected = ClassCastException.class)
  300. public void fieldWithIncompatibleTypeBound_saveBean_throws()
  301. throws Throwable {
  302. try {
  303. binder.bind(ageField, "age");
  304. binder.writeBean(item);
  305. } catch (RuntimeException e) {
  306. throw e.getCause();
  307. }
  308. }
  309. @Test
  310. public void fieldWithConverterBound_bindBean_fieldValueUpdated() {
  311. binder.forField(ageField)
  312. .withConverter(Integer::valueOf, String::valueOf).bind("age");
  313. binder.setBean(item);
  314. assertEquals("32", ageField.getValue());
  315. }
  316. @Test(expected = ClassCastException.class)
  317. public void fieldWithInvalidConverterBound_bindBean_fieldValueUpdated() {
  318. binder.forField(ageField).withConverter(Float::valueOf, String::valueOf)
  319. .bind("age");
  320. binder.setBean(item);
  321. assertEquals("32", ageField.getValue());
  322. }
  323. @Test
  324. public void beanBinderWithBoxedType() {
  325. binder.forField(ageField)
  326. .withConverter(Integer::valueOf, String::valueOf).bind("age");
  327. binder.setBean(item);
  328. ageField.setValue(String.valueOf(20));
  329. assertEquals(20, item.getAge());
  330. }
  331. @Test
  332. public void firstName_isNotNullConstraint_fieldIsRequired() {
  333. BeanValidationBinder<RequiredConstraints> binder = new BeanValidationBinder<>(
  334. RequiredConstraints.class);
  335. RequiredConstraints bean = new RequiredConstraints();
  336. TextField field = new TextField();
  337. binder.bind(field, "firstname");
  338. binder.setBean(bean);
  339. assertTrue(field.isRequiredIndicatorVisible());
  340. testSerialization(binder);
  341. }
  342. @Test
  343. public void age_minSizeConstraint_fieldIsRequired() {
  344. BeanValidationBinder<RequiredConstraints> binder = new BeanValidationBinder<>(
  345. RequiredConstraints.class);
  346. RequiredConstraints bean = new RequiredConstraints();
  347. TextField field = new TextField();
  348. binder.bind(field, "age");
  349. binder.setBean(bean);
  350. assertTrue(field.isRequiredIndicatorVisible());
  351. testSerialization(binder);
  352. }
  353. @Test
  354. public void lastName_minSizeConstraint_fieldIsRequired() {
  355. BeanValidationBinder<RequiredConstraints> binder = new BeanValidationBinder<>(
  356. RequiredConstraints.class);
  357. RequiredConstraints bean = new RequiredConstraints();
  358. TextField field = new TextField();
  359. binder.bind(field, "lastname");
  360. binder.setBean(bean);
  361. assertTrue(field.isRequiredIndicatorVisible());
  362. testSerialization(binder);
  363. }
  364. @Test
  365. public void subfield_name_fieldIsRequired() {
  366. BeanValidationBinder<RequiredConstraints> binder = new BeanValidationBinder<>(
  367. RequiredConstraints.class);
  368. RequiredConstraints bean = new RequiredConstraints();
  369. bean.setSubfield(new RequiredConstraints.SubConstraint());
  370. TextField field = new TextField();
  371. binder.bind(field, "subfield.name");
  372. binder.setBean(bean);
  373. assertTrue(field.isRequiredIndicatorVisible());
  374. testSerialization(binder);
  375. }
  376. @Test
  377. public void subsubfield_name_fieldIsRequired() {
  378. BeanValidationBinder<RequiredConstraints> binder = new BeanValidationBinder<>(
  379. RequiredConstraints.class);
  380. RequiredConstraints bean = new RequiredConstraints();
  381. RequiredConstraints.SubConstraint subfield = new RequiredConstraints.SubConstraint();
  382. subfield.setSubsub(new SubSubConstraint());
  383. bean.setSubfield(subfield);
  384. TextField field = new TextField();
  385. binder.bind(field, "subfield.subsub.value");
  386. binder.setBean(bean);
  387. assertTrue(field.isRequiredIndicatorVisible());
  388. testSerialization(binder);
  389. }
  390. @Test
  391. public void subfield_name_valueCanBeValidated() {
  392. BeanValidationBinder<RequiredConstraints> binder = new BeanValidationBinder<>(
  393. RequiredConstraints.class);
  394. TextField field = new TextField();
  395. binder.bind(field, "subfield.name");
  396. RequiredConstraints bean = new RequiredConstraints();
  397. bean.setSubfield(new SubConstraint());
  398. binder.setBean(bean);
  399. assertFalse(binder.validate().isOk());
  400. field.setValue("overfive");
  401. assertTrue(binder.validate().isOk());
  402. }
  403. @Test
  404. public void subSubfield_name_valueCanBeValidated() {
  405. BeanValidationBinder<RequiredConstraints> binder = new BeanValidationBinder<>(
  406. RequiredConstraints.class);
  407. TextField field = new TextField();
  408. binder.bind(field, "subfield.subsub.value");
  409. RequiredConstraints bean = new RequiredConstraints();
  410. SubConstraint subfield = new SubConstraint();
  411. bean.setSubfield(subfield);
  412. subfield.setSubsub(new SubSubConstraint());
  413. binder.setBean(bean);
  414. assertFalse(binder.validate().isOk());
  415. field.setValue("overtencharacters");
  416. assertTrue(binder.validate().isOk());
  417. }
  418. private void assertInvalid(HasValue<?> field, String message) {
  419. BinderValidationStatus<?> status = binder.validate();
  420. List<BindingValidationStatus<?>> errors = status
  421. .getFieldValidationErrors();
  422. assertEquals(1, errors.size());
  423. assertSame(field, errors.get(0).getField());
  424. assertEquals(message, errors.get(0).getMessage().get());
  425. }
  426. }