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.

BeanItem.java 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. /*
  2. * Copyright 2000-2016 Vaadin Ltd.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.vaadin.v7.data.util;
  17. import java.beans.IntrospectionException;
  18. import java.beans.PropertyDescriptor;
  19. import java.lang.reflect.Method;
  20. import java.util.Arrays;
  21. import java.util.Collection;
  22. import java.util.HashSet;
  23. import java.util.LinkedHashMap;
  24. import java.util.List;
  25. import java.util.Map;
  26. import java.util.Set;
  27. import com.vaadin.data.Binder;
  28. import com.vaadin.data.provider.DataProvider;
  29. import com.vaadin.data.util.BeanUtil;
  30. import com.vaadin.v7.data.Property;
  31. /**
  32. * A wrapper class for adding the Item interface to any Java Bean.
  33. *
  34. * @author Vaadin Ltd.
  35. * @since 3.0
  36. *
  37. * @deprecated As of 8.0, no direct replacement available. You can use any bean directly as an item for {@link Binder}
  38. * or {@link DataProvider} and access the item properties with lambdas like {@code binder.forField(component).bind(...)} or
  39. * {@code new Grid<Bean>(dataProvider).addColumn(bean->bean.getSomething())}.
  40. */
  41. @SuppressWarnings("serial")
  42. @Deprecated
  43. public class BeanItem<BT> extends PropertysetItem {
  44. /**
  45. * The bean which this Item is based on.
  46. */
  47. private BT bean;
  48. /**
  49. * <p>
  50. * Creates a new instance of <code>BeanItem</code> and adds all properties
  51. * of a Java Bean to it. The properties are identified by their respective
  52. * bean names.
  53. * </p>
  54. *
  55. * <p>
  56. * Note : This version only supports introspectable bean properties and
  57. * their getter and setter methods. Stand-alone <code>is</code> and
  58. * <code>are</code> methods are not supported.
  59. * </p>
  60. *
  61. * @param bean
  62. * the Java Bean to copy properties from.
  63. *
  64. */
  65. public BeanItem(BT bean) {
  66. this(bean, (Class<BT>) bean.getClass());
  67. }
  68. /**
  69. * <p>
  70. * Creates a new instance of <code>BeanItem</code> and adds all properties
  71. * of a Java Bean to it. The properties are identified by their respective
  72. * bean names.
  73. * </p>
  74. *
  75. * <p>
  76. * Note : This version only supports introspectable bean properties and
  77. * their getter and setter methods. Stand-alone <code>is</code> and
  78. * <code>are</code> methods are not supported.
  79. * </p>
  80. *
  81. * @since 7.4
  82. *
  83. * @param bean
  84. * the Java Bean to copy properties from.
  85. * @param beanClass
  86. * class of the {@code bean}
  87. *
  88. */
  89. public BeanItem(BT bean, Class<BT> beanClass) {
  90. this(bean, getPropertyDescriptors(beanClass));
  91. }
  92. /**
  93. * <p>
  94. * Creates a new instance of <code>BeanItem</code> using a pre-computed set
  95. * of properties. The properties are identified by their respective bean
  96. * names.
  97. * </p>
  98. *
  99. * @param bean
  100. * the Java Bean to copy properties from.
  101. * @param propertyDescriptors
  102. * pre-computed property descriptors
  103. */
  104. BeanItem(BT bean,
  105. Map<String, VaadinPropertyDescriptor<BT>> propertyDescriptors) {
  106. this.bean = bean;
  107. for (VaadinPropertyDescriptor<BT> pd : propertyDescriptors.values()) {
  108. addItemProperty(pd.getName(), pd.createProperty(bean));
  109. }
  110. }
  111. /**
  112. * <p>
  113. * Creates a new instance of <code>BeanItem</code> and adds all listed
  114. * properties of a Java Bean to it - in specified order. The properties are
  115. * identified by their respective bean names.
  116. * </p>
  117. *
  118. * <p>
  119. * Note : This version only supports introspectable bean properties and
  120. * their getter and setter methods. Stand-alone <code>is</code> and
  121. * <code>are</code> methods are not supported.
  122. * </p>
  123. *
  124. * @param bean
  125. * the Java Bean to copy properties from.
  126. * @param propertyIds
  127. * id of the property.
  128. */
  129. public BeanItem(BT bean, Collection<?> propertyIds) {
  130. this.bean = bean;
  131. // Create bean information
  132. LinkedHashMap<String, VaadinPropertyDescriptor<BT>> pds = getPropertyDescriptors(
  133. (Class<BT>) bean.getClass());
  134. // Add all the bean properties as MethodProperties to this Item
  135. for (Object id : propertyIds) {
  136. VaadinPropertyDescriptor<BT> pd = pds.get(id);
  137. if (pd != null) {
  138. addItemProperty(pd.getName(), pd.createProperty(bean));
  139. }
  140. }
  141. }
  142. /**
  143. * <p>
  144. * Creates a new instance of <code>BeanItem</code> and adds all listed
  145. * properties of a Java Bean to it - in specified order. The properties are
  146. * identified by their respective bean names.
  147. * </p>
  148. *
  149. * <p>
  150. * Note : This version only supports introspectable bean properties and
  151. * their getter and setter methods. Stand-alone <code>is</code> and
  152. * <code>are</code> methods are not supported.
  153. * </p>
  154. *
  155. * @param bean
  156. * the Java Bean to copy properties from.
  157. * @param propertyIds
  158. * ids of the properties.
  159. */
  160. public BeanItem(BT bean, String... propertyIds) {
  161. this(bean, Arrays.asList(propertyIds));
  162. }
  163. /**
  164. * <p>
  165. * Perform introspection on a Java Bean class to find its properties.
  166. * </p>
  167. *
  168. * <p>
  169. * Note : This version only supports introspectable bean properties and
  170. * their getter and setter methods. Stand-alone <code>is</code> and
  171. * <code>are</code> methods are not supported.
  172. * </p>
  173. *
  174. * @param beanClass
  175. * the Java Bean class to get properties for.
  176. * @return an ordered map from property names to property descriptors
  177. */
  178. static <BT> LinkedHashMap<String, VaadinPropertyDescriptor<BT>> getPropertyDescriptors(
  179. final Class<BT> beanClass) {
  180. final LinkedHashMap<String, VaadinPropertyDescriptor<BT>> pdMap = new LinkedHashMap<String, VaadinPropertyDescriptor<BT>>();
  181. // Try to introspect, if it fails, we just have an empty Item
  182. try {
  183. List<PropertyDescriptor> propertyDescriptors = BeanUtil
  184. .getBeanPropertyDescriptors(beanClass);
  185. // Add all the bean properties as MethodProperties to this Item
  186. // later entries on the list overwrite earlier ones
  187. for (PropertyDescriptor pd : propertyDescriptors) {
  188. final Method getMethod = pd.getReadMethod();
  189. if ((getMethod != null)
  190. && getMethod.getDeclaringClass() != Object.class) {
  191. VaadinPropertyDescriptor<BT> vaadinPropertyDescriptor = new MethodPropertyDescriptor<BT>(
  192. pd.getName(), pd.getPropertyType(),
  193. pd.getReadMethod(), pd.getWriteMethod());
  194. pdMap.put(pd.getName(), vaadinPropertyDescriptor);
  195. }
  196. }
  197. } catch (final IntrospectionException ignored) {
  198. }
  199. return pdMap;
  200. }
  201. /**
  202. * Expands nested bean properties by replacing a top-level property with
  203. * some or all of its sub-properties. The expansion is not recursive.
  204. *
  205. * @param propertyId
  206. * property id for the property whose sub-properties are to be
  207. * expanded,
  208. * @param subPropertyIds
  209. * sub-properties to expand, all sub-properties are expanded if
  210. * not specified
  211. */
  212. public void expandProperty(String propertyId, String... subPropertyIds) {
  213. Set<String> subPropertySet = new HashSet<String>(
  214. Arrays.asList(subPropertyIds));
  215. if (0 == subPropertyIds.length) {
  216. // Enumerate all sub-properties
  217. Class<?> propertyType = getItemProperty(propertyId).getType();
  218. Map<String, ?> pds = getPropertyDescriptors(propertyType);
  219. subPropertySet.addAll(pds.keySet());
  220. }
  221. for (String subproperty : subPropertySet) {
  222. String qualifiedPropertyId = propertyId + "." + subproperty;
  223. addNestedProperty(qualifiedPropertyId);
  224. }
  225. removeItemProperty(propertyId);
  226. }
  227. /**
  228. * Adds a nested property to the item. The property must not exist in the
  229. * item already and must of form "field1.field2" where field2 is a field in
  230. * the object referenced to by field1. If an intermediate property returns
  231. * null, the property will return a null value
  232. *
  233. * @param nestedPropertyId
  234. * property id to add.
  235. */
  236. public void addNestedProperty(String nestedPropertyId) {
  237. addItemProperty(nestedPropertyId,
  238. new NestedMethodProperty<Object>(getBean(), nestedPropertyId));
  239. }
  240. /**
  241. * Gets the underlying JavaBean object.
  242. *
  243. * @return the bean object.
  244. */
  245. public BT getBean() {
  246. return bean;
  247. }
  248. /**
  249. * Changes the Java Bean this item is based on.
  250. * <p>
  251. * This will cause any existing properties to be re-mapped to the new bean.
  252. * Any added custom properties which are not of type {@link MethodProperty}
  253. * or {@link NestedMethodProperty} will not be updated to reflect the change
  254. * of bean.
  255. * <p>
  256. * Changing the bean will fire value change events for all properties of
  257. * type {@link MethodProperty} or {@link NestedMethodProperty}.
  258. *
  259. * @param bean
  260. * The new bean to use for this item, not <code>null</code>
  261. * @since 7.7.7
  262. */
  263. public void setBean(BT bean) {
  264. if (bean == null) {
  265. throw new IllegalArgumentException("Bean cannot be null");
  266. }
  267. if (getBean().getClass() != bean.getClass()) {
  268. throw new IllegalArgumentException(
  269. "The new bean class " + bean.getClass().getName()
  270. + " does not match the old bean class "
  271. + getBean().getClass());
  272. }
  273. // Remap properties
  274. for (Object propertyId : getItemPropertyIds()) {
  275. Property p = getItemProperty(propertyId);
  276. if (p instanceof MethodProperty) {
  277. MethodProperty mp = (MethodProperty) p;
  278. assert (mp.getInstance() == getBean());
  279. mp.setInstance(bean);
  280. } else if (p instanceof NestedMethodProperty) {
  281. NestedMethodProperty nmp = (NestedMethodProperty) p;
  282. assert (nmp.getInstance() == getBean());
  283. nmp.setInstance(bean);
  284. }
  285. }
  286. this.bean = bean;
  287. }
  288. }