/* @ITMillApache2LicenseForJavaFiles@ */ package com.vaadin.data.util; import java.beans.BeanInfo; import java.beans.IntrospectionException; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; /** * A wrapper class for adding the Item interface to any Java Bean. * * @author IT Mill Ltd. * @version * @VERSION@ * @since 3.0 */ @SuppressWarnings("serial") public class BeanItem extends PropertysetItem { /** * The bean which this Item is based on. */ private final BT bean; /** *

* Creates a new instance of BeanItem and adds all properties * of a Java Bean to it. The properties are identified by their respective * bean names. *

* *

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

* * @param bean * the Java Bean to copy properties from. * */ public BeanItem(BT bean) { this(bean, getPropertyDescriptors((Class) bean.getClass())); } /** *

* 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(BT bean, Map> propertyDescriptors) { this.bean = bean; for (VaadinPropertyDescriptor pd : propertyDescriptors.values()) { addItemProperty(pd.getName(), pd.createProperty(bean)); } } /** *

* Creates a new instance of BeanItem and adds all listed * properties of a Java Bean to it - in specified order. The properties are * identified by their respective bean names. *

* *

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

* * @param bean * the Java Bean to copy properties from. * @param propertyIds * id of the property. */ public BeanItem(BT bean, Collection propertyIds) { this.bean = bean; // Create bean information LinkedHashMap> pds = getPropertyDescriptors((Class) bean .getClass()); // Add all the bean properties as MethodProperties to this Item for (Object id : propertyIds) { VaadinPropertyDescriptor pd = pds.get(id); if (pd != null) { addItemProperty(pd.getName(), pd.createProperty(bean)); } } } /** *

* Creates a new instance of BeanItem and adds all listed * properties of a Java Bean to it - in specified order. The properties are * identified by their respective bean names. *

* *

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

* * @param bean * the Java Bean to copy properties from. * @param propertyIds * ids of the properties. */ public BeanItem(BT bean, String[] propertyIds) { 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 { List propertyDescriptors = getBeanPropertyDescriptor(beanClass); // Add all the bean properties as MethodProperties to this Item // later entries on the list overwrite earlier ones for (PropertyDescriptor pd : propertyDescriptors) { final Method getMethod = pd.getReadMethod(); if ((getMethod != null) && getMethod.getDeclaringClass() != Object.class) { VaadinPropertyDescriptor vaadinPropertyDescriptor = new MethodPropertyDescriptor( pd.getName(), pd.getPropertyType(), pd.getReadMethod(), pd.getWriteMethod()); pdMap.put(pd.getName(), vaadinPropertyDescriptor); } } } catch (final java.beans.IntrospectionException ignored) { } return pdMap; } /** * Returns the property descriptors of a class or an interface. * * For an interface, superinterfaces are also iterated as Introspector does * not take them into account (Oracle Java bug 4275879), but in that case, * both the setter and the getter for a property must be in the same * interface and should not be overridden in subinterfaces for the discovery * to work correctly. * * For interfaces, the iteration is depth first and the properties of * superinterfaces are returned before those of their subinterfaces. * * @param beanClass * @return * @throws IntrospectionException */ private static List getBeanPropertyDescriptor( final Class beanClass) throws IntrospectionException { // Oracle bug 4275879: Introspector does not consider superinterfaces of // an interface if (beanClass.isInterface()) { List propertyDescriptors = new ArrayList(); for (Class cls : beanClass.getInterfaces()) { propertyDescriptors.addAll(getBeanPropertyDescriptor(cls)); } BeanInfo info = Introspector.getBeanInfo(beanClass); propertyDescriptors.addAll(Arrays.asList(info .getPropertyDescriptors())); return propertyDescriptors; } else { BeanInfo info = Introspector.getBeanInfo(beanClass); return Arrays.asList(info.getPropertyDescriptors()); } } /** * Gets the underlying JavaBean object. * * @return the bean object. */ public BT getBean() { return bean; } }