From 4a765948a65dab18869ee6425dba3ba909fdf274 Mon Sep 17 00:00:00 2001 From: Henri Sara Date: Thu, 2 Apr 2009 07:50:52 +0000 Subject: [PATCH] #1061: merged [7281] from 5.4: BeanItemContainer no longer requires a public default constructor in the bean and supports bean subclasses (with parent properties only) svn changeset:7282/svn branch:6.0 --- .../itmill/toolkit/data/util/BeanItem.java | 125 +++++++++++------- .../toolkit/data/util/BeanItemContainer.java | 21 +-- .../containers/BeanItemContainerTest.java | 17 ++- 3 files changed, 106 insertions(+), 57 deletions(-) diff --git a/src/com/itmill/toolkit/data/util/BeanItem.java b/src/com/itmill/toolkit/data/util/BeanItem.java index b867491cdb..65bc57a1b3 100644 --- a/src/com/itmill/toolkit/data/util/BeanItem.java +++ b/src/com/itmill/toolkit/data/util/BeanItem.java @@ -10,7 +10,7 @@ import java.beans.PropertyDescriptor; import java.lang.reflect.Method; import java.util.Arrays; import java.util.Collection; -import java.util.Iterator; +import java.util.LinkedHashMap; import com.itmill.toolkit.data.Property; @@ -47,30 +47,35 @@ public class BeanItem extends PropertysetItem { * */ public BeanItem(Object bean) { + this(bean, getPropertyDescriptors(bean.getClass())); + } - this.bean = bean; + /** + *

+ * Creates a new instance of BeanItem using a pre-computed set + * of properties. The properties are identified by their respective bean + * names. + *

+ * + * @param bean + * the Java Bean to copy properties from. + * @param propertyDescriptors + * pre-computed property descriptors + */ + BeanItem(Object bean, + LinkedHashMap propertyDescriptors) { - // Try to introspect, if it fails, we just have an empty Item - try { - // Create bean information - final BeanInfo info = Introspector.getBeanInfo(bean.getClass()); - final PropertyDescriptor[] pd = info.getPropertyDescriptors(); + this.bean = bean; - // Add all the bean properties as MethodProperties to this Item - for (int i = 0; i < pd.length; i++) { - final Method getMethod = pd[i].getReadMethod(); - final Method setMethod = pd[i].getWriteMethod(); - final Class type = pd[i].getPropertyType(); - final String name = pd[i].getName(); + for (PropertyDescriptor pd : propertyDescriptors.values()) { + final Method getMethod = pd.getReadMethod(); + final Method setMethod = pd.getWriteMethod(); + final Class type = pd.getPropertyType(); + final String name = pd.getName(); + final Property p = new MethodProperty(type, bean, getMethod, + setMethod); + addItemProperty(name, p); - if ((getMethod != null) - && getMethod.getDeclaringClass() != Object.class) { - final Property p = new MethodProperty(type, bean, - getMethod, setMethod); - addItemProperty(name, p); - } - } - } catch (final java.beans.IntrospectionException ignored) { } } @@ -96,32 +101,22 @@ public class BeanItem extends PropertysetItem { this.bean = bean; - // Try to introspect, if it fails, we just have an empty Item - try { - // Create bean information - final BeanInfo info = Introspector.getBeanInfo(bean.getClass()); - final PropertyDescriptor[] pd = info.getPropertyDescriptors(); - - // Add all the bean properties as MethodProperties to this Item - final Iterator iter = propertyIds.iterator(); - while (iter.hasNext()) { - final Object id = iter.next(); - for (int i = 0; i < pd.length; i++) { - final String name = pd[i].getName(); - if (name.equals(id)) { - final Method getMethod = pd[i].getReadMethod(); - final Method setMethod = pd[i].getWriteMethod(); - final Class type = pd[i].getPropertyType(); - if ((getMethod != null)) { - final Property p = new MethodProperty(type, bean, - getMethod, setMethod); - addItemProperty(name, p); - } - } - } + // Create bean information + LinkedHashMap pds = getPropertyDescriptors(bean + .getClass()); + + // Add all the bean properties as MethodProperties to this Item + for (Object id : propertyIds) { + PropertyDescriptor pd = pds.get(id); + if (pd != null) { + final String name = pd.getName(); + final Method getMethod = pd.getReadMethod(); + final Method setMethod = pd.getWriteMethod(); + final Class type = pd.getPropertyType(); + final Property p = new MethodProperty(type, bean, getMethod, + setMethod); + addItemProperty(name, p); } - - } catch (final java.beans.IntrospectionException ignored) { } } @@ -148,6 +143,44 @@ public class BeanItem extends PropertysetItem { this(bean, Arrays.asList(propertyIds)); } + /** + *

+ * Perform introspection on a Java Bean class to find its properties. + *

+ * + *

+ * Note : This version only supports introspectable bean properties and + * their getter and setter methods. Stand-alone is and + * are methods are not supported. + *

+ * + * @param beanClass + * the Java Bean class to get properties for. + * @return an ordered map from property names to property descriptors + */ + static LinkedHashMap getPropertyDescriptors( + final Class beanClass) { + final LinkedHashMap pdMap = new LinkedHashMap(); + + // Try to introspect, if it fails, we just have an empty Item + try { + final BeanInfo info = Introspector.getBeanInfo(beanClass); + final PropertyDescriptor[] pds = info.getPropertyDescriptors(); + + // Add all the bean properties as MethodProperties to this Item + for (int i = 0; i < pds.length; i++) { + final Method getMethod = pds[i].getReadMethod(); + if ((getMethod != null) + && getMethod.getDeclaringClass() != Object.class) { + pdMap.put(pds[i].getName(), pds[i]); + } + } + } catch (final java.beans.IntrospectionException ignored) { + } + + return pdMap; + } + /** * Gets the underlying JavaBean object. * diff --git a/src/com/itmill/toolkit/data/util/BeanItemContainer.java b/src/com/itmill/toolkit/data/util/BeanItemContainer.java index 457526efc4..5ba44568ad 100644 --- a/src/com/itmill/toolkit/data/util/BeanItemContainer.java +++ b/src/com/itmill/toolkit/data/util/BeanItemContainer.java @@ -1,5 +1,6 @@ package com.itmill.toolkit.data.util; +import java.beans.PropertyDescriptor; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -7,6 +8,7 @@ import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -27,7 +29,7 @@ import com.itmill.toolkit.data.Property.ValueChangeNotifier; * An {@link ArrayList} backed container for {@link BeanItem}s. *

* Bean objects act as identifiers. For this reason, they should implement - * Object.equals(Object) and Object.hashCode() . + * Object.equals(Object) and Object.hashCode(). *

* * @param @@ -41,8 +43,9 @@ public class BeanItemContainer implements Indexed, Sortable, Filterable, private ArrayList allItems = new ArrayList(); private final Map beanToItem = new HashMap(); + // internal data model to obtain property IDs etc. private final Class type; - private final BeanItem model; + private final LinkedHashMap model; private List itemSetChangeListeners; @@ -51,8 +54,7 @@ public class BeanItemContainer implements Indexed, Sortable, Filterable, public BeanItemContainer(Class type) throws InstantiationException, IllegalAccessException { this.type = type; - BT pojomodel = type.newInstance(); - model = new BeanItem(pojomodel); + model = BeanItem.getPropertyDescriptors(type); } /** @@ -67,8 +69,7 @@ public class BeanItemContainer implements Indexed, Sortable, Filterable, public BeanItemContainer(Collection list) throws InstantiationException, IllegalAccessException { type = (Class) list.iterator().next().getClass(); - BT pojomodel = type.newInstance(); - model = new BeanItem(pojomodel); + model = BeanItem.getPropertyDescriptors(type); int i = 0; for (BT bt : list) { addItemAt(i++, bt); @@ -111,11 +112,11 @@ public class BeanItemContainer implements Indexed, Sortable, Filterable, if (allItems.contains(newItemId)) { return null; } - if (newItemId.getClass().isAssignableFrom(type)) { + if (type.isAssignableFrom(newItemId.getClass())) { BT pojo = (BT) newItemId; // "list" will be updated in filterAll() allItems.add(index, pojo); - BeanItem beanItem = new BeanItem(pojo); + BeanItem beanItem = new BeanItem(pojo, model); beanToItem.put(pojo, beanItem); // add listeners to be able to update filtering on property changes for (Filter filter : filters) { @@ -230,7 +231,7 @@ public class BeanItemContainer implements Indexed, Sortable, Filterable, @SuppressWarnings("unchecked") public Collection getContainerPropertyIds() { - return model.getItemPropertyIds(); + return model.keySet(); } public Item getItem(Object itemId) { @@ -243,7 +244,7 @@ public class BeanItemContainer implements Indexed, Sortable, Filterable, } public Class getType(Object propertyId) { - return model.getItemProperty(propertyId).getType(); + return model.get(propertyId).getPropertyType(); } public boolean removeAllItems() throws UnsupportedOperationException { diff --git a/src/com/itmill/toolkit/tests/containers/BeanItemContainerTest.java b/src/com/itmill/toolkit/tests/containers/BeanItemContainerTest.java index cc5b04a699..bbfc72fb02 100644 --- a/src/com/itmill/toolkit/tests/containers/BeanItemContainerTest.java +++ b/src/com/itmill/toolkit/tests/containers/BeanItemContainerTest.java @@ -22,10 +22,17 @@ public class BeanItemContainerTest { for (int i = 0; i < 100; i++) { col.add(new Hello()); } + col.add(new Hello2()); c = new BeanItemContainer(col); - System.out.print(c + " contains " + c.size() + " objects"); + System.out.println(c + " contains " + c.size() + " objects"); + + // test that subclass properties are handled correctly + System.out.println(c + " item 0 second = " + + c.getContainerProperty(c.getIdByIndex(0), "second")); + System.out.println(c + " item 100 second = " + + c.getContainerProperty(c.getIdByIndex(100), "second")); } @@ -57,4 +64,12 @@ public class BeanItemContainerTest { } + public static class Hello2 extends Hello { + + @Override + public String getSecond() { + return "second"; + } + + } } -- 2.39.5