]> source.dussan.org Git - vaadin-framework.git/commitdiff
#1061: merged [7281] from 5.4: BeanItemContainer no longer requires a public default...
authorHenri Sara <henri.sara@itmill.com>
Thu, 2 Apr 2009 07:50:52 +0000 (07:50 +0000)
committerHenri Sara <henri.sara@itmill.com>
Thu, 2 Apr 2009 07:50:52 +0000 (07:50 +0000)
svn changeset:7282/svn branch:6.0

src/com/itmill/toolkit/data/util/BeanItem.java
src/com/itmill/toolkit/data/util/BeanItemContainer.java
src/com/itmill/toolkit/tests/containers/BeanItemContainerTest.java

index b867491cdb2d194fc6d68a4828c2d75d44359232..65bc57a1b3e00c0724fe2f642c88e82f055017c3 100644 (file)
@@ -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) {
         }
 
     }
@@ -148,6 +143,44 @@ public class BeanItem extends PropertysetItem {
         this(bean, Arrays.asList(propertyIds));
     }
 
+    /**
+     * <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.
      * 
index 457526efc421847926b12afdb58027e13c7f3e04..5ba44568ada9121fadb523d677156cb91766937b 100644 (file)
@@ -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 {
index cc5b04a699994d60f59b99e20c1e9501d5c4c1a6..bbfc72fb02d3c4b9d6e93d2e27a50abf134740be 100644 (file)
@@ -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";
+        }
+
+    }
 }