com.vaadin.v7.data.util.BeanItem.java Source code

Java tutorial

Introduction

Here is the source code for com.vaadin.v7.data.util.BeanItem.java

Source

/*
 * Copyright 2000-2018 Vaadin Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package com.vaadin.v7.data.util;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.vaadin.data.Binder;
import com.vaadin.data.provider.DataProvider;
import com.vaadin.data.util.BeanUtil;
import com.vaadin.v7.data.Property;

/**
 * A wrapper class for adding the Item interface to any Java Bean.
 *
 * @author Vaadin Ltd.
 * @since 3.0
 *
 * @deprecated As of 8.0, no direct replacement available. You can use any bean directly as an item for {@link Binder}
 * or {@link DataProvider} and access the item properties with lambdas like {@code binder.forField(component).bind(...)} or
 * {@code new Grid<Bean>(dataProvider).addColumn(bean->bean.getSomething())}.
 */
@SuppressWarnings("serial")
@Deprecated
public class BeanItem<BT> extends PropertysetItem {

    /**
     * The bean which this Item is based on.
     */
    private BT bean;

    /**
     * <p>
     * Creates a new instance of <code>BeanItem</code> and adds all properties
     * of a Java Bean to it. The properties are identified by their respective
     * bean names.
     * </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 bean
     *            the Java Bean to copy properties from.
     *
     */
    public BeanItem(BT bean) {
        this(bean, (Class<BT>) bean.getClass());
    }

    /**
     * <p>
     * Creates a new instance of <code>BeanItem</code> and adds all properties
     * of a Java Bean to it. The properties are identified by their respective
     * bean names.
     * </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>
     *
     * @since 7.4
     *
     * @param bean
     *            the Java Bean to copy properties from.
     * @param beanClass
     *            class of the {@code bean}
     *
     */
    public BeanItem(BT bean, Class<BT> beanClass) {
        this(bean, getPropertyDescriptors(beanClass));
    }

    /**
     * <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(BT bean, Map<String, VaadinPropertyDescriptor<BT>> propertyDescriptors) {

        this.bean = bean;

        for (VaadinPropertyDescriptor<BT> pd : propertyDescriptors.values()) {
            addItemProperty(pd.getName(), pd.createProperty(bean));
        }
    }

    /**
     * <p>
     * Creates a new instance of <code>BeanItem</code> and adds all listed
     * properties of a Java Bean to it - in specified order. The properties are
     * identified by their respective bean names.
     * </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 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<String, VaadinPropertyDescriptor<BT>> pds = getPropertyDescriptors(
                (Class<BT>) bean.getClass());

        // Add all the bean properties as MethodProperties to this Item
        for (Object id : propertyIds) {
            VaadinPropertyDescriptor<BT> pd = pds.get(id);
            if (pd != null) {
                addItemProperty(pd.getName(), pd.createProperty(bean));
            }
        }

    }

    /**
     * <p>
     * Creates a new instance of <code>BeanItem</code> and adds all listed
     * properties of a Java Bean to it - in specified order. The properties are
     * identified by their respective bean names.
     * </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 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));
    }

    /**
     * <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 <BT> LinkedHashMap<String, VaadinPropertyDescriptor<BT>> getPropertyDescriptors(
            final Class<BT> beanClass) {
        final LinkedHashMap<String, VaadinPropertyDescriptor<BT>> pdMap = new LinkedHashMap<String, VaadinPropertyDescriptor<BT>>();

        // Try to introspect, if it fails, we just have an empty Item
        try {
            List<PropertyDescriptor> propertyDescriptors = BeanUtil.getBeanPropertyDescriptors(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<BT> vaadinPropertyDescriptor = new MethodPropertyDescriptor<BT>(
                            pd.getName(), pd.getPropertyType(), pd.getReadMethod(), pd.getWriteMethod());
                    pdMap.put(pd.getName(), vaadinPropertyDescriptor);
                }
            }
        } catch (final IntrospectionException ignored) {
        }

        return pdMap;
    }

    /**
     * Expands nested bean properties by replacing a top-level property with
     * some or all of its sub-properties. The expansion is not recursive.
     *
     * @param propertyId
     *            property id for the property whose sub-properties are to be
     *            expanded,
     * @param subPropertyIds
     *            sub-properties to expand, all sub-properties are expanded if
     *            not specified
     */
    public void expandProperty(String propertyId, String... subPropertyIds) {
        Set<String> subPropertySet = new HashSet<String>(Arrays.asList(subPropertyIds));

        if (0 == subPropertyIds.length) {
            // Enumerate all sub-properties
            Class<?> propertyType = getItemProperty(propertyId).getType();
            Map<String, ?> pds = getPropertyDescriptors(propertyType);
            subPropertySet.addAll(pds.keySet());
        }

        for (String subproperty : subPropertySet) {
            String qualifiedPropertyId = propertyId + "." + subproperty;
            addNestedProperty(qualifiedPropertyId);
        }

        removeItemProperty(propertyId);
    }

    /**
     * Adds a nested property to the item. The property must not exist in the
     * item already and must of form "field1.field2" where field2 is a field in
     * the object referenced to by field1. If an intermediate property returns
     * null, the property will return a null value
     *
     * @param nestedPropertyId
     *            property id to add.
     */
    public void addNestedProperty(String nestedPropertyId) {
        addItemProperty(nestedPropertyId, new NestedMethodProperty<Object>(getBean(), nestedPropertyId));
    }

    /**
     * Gets the underlying JavaBean object.
     *
     * @return the bean object.
     */
    public BT getBean() {
        return bean;
    }

    /**
     * Changes the Java Bean this item is based on.
     * <p>
     * This will cause any existing properties to be re-mapped to the new bean.
     * Any added custom properties which are not of type {@link MethodProperty}
     * or {@link NestedMethodProperty} will not be updated to reflect the change
     * of bean.
     * <p>
     * Changing the bean will fire value change events for all properties of
     * type {@link MethodProperty} or {@link NestedMethodProperty}.
     *
     * @param bean
     *            The new bean to use for this item, not <code>null</code>
     * @since 7.7.7
     */
    public void setBean(BT bean) {
        if (bean == null) {
            throw new IllegalArgumentException("Bean cannot be null");
        }

        if (getBean().getClass() != bean.getClass()) {
            throw new IllegalArgumentException("The new bean class " + bean.getClass().getName()
                    + " does not match the old bean class " + getBean().getClass());
        }

        // Remap properties
        for (Object propertyId : getItemPropertyIds()) {
            Property p = getItemProperty(propertyId);
            if (p instanceof MethodProperty) {
                MethodProperty mp = (MethodProperty) p;
                assert (mp.getInstance() == getBean());
                mp.setInstance(bean);
            } else if (p instanceof NestedMethodProperty) {
                NestedMethodProperty nmp = (NestedMethodProperty) p;
                assert (nmp.getInstance() == getBean());
                nmp.setInstance(bean);
            }
        }

        this.bean = bean;
    }
}