diff options
author | Henri Sara <henri.sara@itmill.com> | 2009-04-02 07:50:52 +0000 |
---|---|---|
committer | Henri Sara <henri.sara@itmill.com> | 2009-04-02 07:50:52 +0000 |
commit | 4a765948a65dab18869ee6425dba3ba909fdf274 (patch) | |
tree | 5eb2ec949b6dd3a8460272b66f1d84029b934dee | |
parent | 5218e96b2838388e2c9b77cf3aad7aecbb43a3c1 (diff) | |
download | vaadin-framework-4a765948a65dab18869ee6425dba3ba909fdf274.tar.gz vaadin-framework-4a765948a65dab18869ee6425dba3ba909fdf274.zip |
#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
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; + /** + * <p> + * Creates a new instance of <code>BeanItem</code> using a pre-computed set + * of properties. The properties are identified by their respective bean + * names. + * </p> + * + * @param bean + * the Java Bean to copy properties from. + * @param propertyDescriptors + * pre-computed property descriptors + */ + BeanItem(Object bean, + LinkedHashMap<String, PropertyDescriptor> 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<String, PropertyDescriptor> 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) { } } @@ -149,6 +144,44 @@ public class BeanItem extends PropertysetItem { } /** + * <p> + * Perform introspection on a Java Bean class to find its properties. + * </p> + * + * <p> + * Note : This version only supports introspectable bean properties and + * their getter and setter methods. Stand-alone <code>is</code> and + * <code>are</code> methods are not supported. + * </p> + * + * @param beanClass + * the Java Bean class to get properties for. + * @return an ordered map from property names to property descriptors + */ + static LinkedHashMap<String, PropertyDescriptor> getPropertyDescriptors( + final Class<?> beanClass) { + final LinkedHashMap<String, PropertyDescriptor> pdMap = new LinkedHashMap<String, PropertyDescriptor>(); + + // 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. * * @return the bean 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. * <p> * Bean objects act as identifiers. For this reason, they should implement - * Object.equals(Object) and Object.hashCode() . + * Object.equals(Object) and Object.hashCode(). * </p> * * @param <BT> @@ -41,8 +43,9 @@ public class BeanItemContainer<BT> implements Indexed, Sortable, Filterable, private ArrayList<BT> allItems = new ArrayList<BT>(); private final Map<BT, BeanItem> beanToItem = new HashMap<BT, BeanItem>(); + // internal data model to obtain property IDs etc. private final Class<BT> type; - private final BeanItem model; + private final LinkedHashMap<String, PropertyDescriptor> model; private List<ItemSetChangeListener> itemSetChangeListeners; @@ -51,8 +54,7 @@ public class BeanItemContainer<BT> implements Indexed, Sortable, Filterable, public BeanItemContainer(Class<BT> 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<BT> implements Indexed, Sortable, Filterable, public BeanItemContainer(Collection<BT> list) throws InstantiationException, IllegalAccessException { type = (Class<BT>) 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<BT> 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<BT> 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<BT> 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<Hello>(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"; + } + + } } |