001/**
002 * Copyright 2005-2016 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.rice.krad.web.bind;
017
018import org.springframework.beans.BeanWrapperImpl;
019import org.springframework.beans.BeansException;
020import org.springframework.beans.InvalidPropertyException;
021import org.springframework.beans.NullValueInNestedPathException;
022import org.springframework.beans.PropertyValue;
023
024/**
025 * Bean wrapper that will auto grow paths for setting the value but not grow paths for getting
026 * a value.
027 *
028 * @author Kuali Rice Team (rice.collab@kuali.org)
029 */
030public class UifBeanWrapper extends BeanWrapperImpl {
031
032    private BeanWrapperImpl rootBeanWrapper;
033
034    public UifBeanWrapper(Object object) {
035        super(object);
036    }
037
038    public UifBeanWrapper(Object object, String nestedPath, UifBeanWrapper superBw) {
039        super(object, nestedPath, superBw);
040
041        setRootBeanWrapper(superBw.getRootBeanWrapper());
042    }
043
044    /**
045     * Overridden to set auto grow nested paths to false for getting the value.
046     *
047     * {@inheritDoc}
048     */
049    @Override
050    public Object getPropertyValue(String propertyName) throws BeansException {
051        return getPropertyValue(propertyName, false);
052    }
053
054    /**
055     * Returns the value for the given property growing nested paths depending on the parameter.
056     *
057     * @param propertyName name of the property to get value for
058     * @param autoGrowNestedPaths whether nested paths should be grown (initialized if null)
059     * @return value for property
060     */
061    protected Object getPropertyValue(String propertyName, boolean autoGrowNestedPaths) {
062        setAutoGrowNestedPaths(autoGrowNestedPaths);
063
064        Object value = null;
065        try {
066            value = super.getPropertyValue(propertyName);
067        } catch (NullValueInNestedPathException e) {
068            // swallow null values in path and return null as the value
069        } catch (InvalidPropertyException e1) {
070            if (!(e1.getRootCause() instanceof NullValueInNestedPathException)) {
071                throw e1;
072            }
073        }
074
075        return value;
076    }
077
078    /**
079     * Override to set auto grow to true for setting property values.
080     *
081     * {@inheritDoc}
082     */
083    @Override
084    public void setPropertyValue(PropertyValue pv) throws BeansException {
085        setAutoGrowNestedPaths(true);
086
087        super.setPropertyValue(pv);
088    }
089
090    /**
091     * Override to set auto grow to true for setting property values.
092     *
093     * {@inheritDoc}
094     */
095    @Override
096    public void setPropertyValue(String propertyName, Object value) throws BeansException {
097        setAutoGrowNestedPaths(true);
098
099        super.setPropertyValue(propertyName, value);
100    }
101
102    /**
103     * Override to instantiate a UIF bean wrapper for nested bean wrappers.
104     *
105     * {@inheritDoc}
106     */
107    @Override
108    protected BeanWrapperImpl newNestedBeanWrapper(Object object, String nestedPath) {
109        return new UifBeanWrapper(object, nestedPath, this);
110    }
111
112    /**
113     * Override to set auto grown on the nested bean wrapper to the setting of the root bean wrapper.
114     *
115     * <p>This is necessary because the nested bean wrapper could have been cached, and its auto-grow
116     * setting reflect an earler get or set call</p>
117     *
118     * {@inheritDoc}
119     */
120    @Override
121    protected BeanWrapperImpl getBeanWrapperForPropertyPath(String propertyPath) {
122        if (this.rootBeanWrapper != null) {
123            setAutoGrowNestedPaths(this.rootBeanWrapper.isAutoGrowNestedPaths());
124        }
125
126        return super.getBeanWrapperForPropertyPath(propertyPath);
127    }
128
129    /**
130     * Bean wrapper for the root data object, used for setting auto grows on nested bean wrappers.
131     *
132     * @return bean wrapper impl for root data object
133     */
134    public BeanWrapperImpl getRootBeanWrapper() {
135        if (rootBeanWrapper == null) {
136            return this;
137        }
138
139        return rootBeanWrapper;
140    }
141
142    /**
143     * @see UifBeanWrapper#getRootBeanWrapper()
144     */
145    public void setRootBeanWrapper(BeanWrapperImpl rootBeanWrapper) {
146        this.rootBeanWrapper = rootBeanWrapper;
147    }
148}