001/*
002 * Copyright 2002-2020 the original author or authors.
003 *
004 * Licensed under the Apache 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 *      https://www.apache.org/licenses/LICENSE-2.0
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 */
016
017package org.springframework.beans;
018
019import java.util.Arrays;
020import java.util.LinkedList;
021import java.util.List;
022import java.util.Map;
023
024/**
025 * Abstract implementation of the {@link PropertyAccessor} interface.
026 * Provides base implementations of all convenience methods, with the
027 * implementation of actual property access left to subclasses.
028 *
029 * @author Juergen Hoeller
030 * @author Stephane Nicoll
031 * @since 2.0
032 * @see #getPropertyValue
033 * @see #setPropertyValue
034 */
035public abstract class AbstractPropertyAccessor extends TypeConverterSupport implements ConfigurablePropertyAccessor {
036
037        private boolean extractOldValueForEditor = false;
038
039        private boolean autoGrowNestedPaths = false;
040
041        boolean suppressNotWritablePropertyException = false;
042
043
044        @Override
045        public void setExtractOldValueForEditor(boolean extractOldValueForEditor) {
046                this.extractOldValueForEditor = extractOldValueForEditor;
047        }
048
049        @Override
050        public boolean isExtractOldValueForEditor() {
051                return this.extractOldValueForEditor;
052        }
053
054        @Override
055        public void setAutoGrowNestedPaths(boolean autoGrowNestedPaths) {
056                this.autoGrowNestedPaths = autoGrowNestedPaths;
057        }
058
059        @Override
060        public boolean isAutoGrowNestedPaths() {
061                return this.autoGrowNestedPaths;
062        }
063
064
065        @Override
066        public void setPropertyValue(PropertyValue pv) throws BeansException {
067                setPropertyValue(pv.getName(), pv.getValue());
068        }
069
070        @Override
071        public void setPropertyValues(Map<?, ?> map) throws BeansException {
072                setPropertyValues(new MutablePropertyValues(map));
073        }
074
075        @Override
076        public void setPropertyValues(PropertyValues pvs) throws BeansException {
077                setPropertyValues(pvs, false, false);
078        }
079
080        @Override
081        public void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown) throws BeansException {
082                setPropertyValues(pvs, ignoreUnknown, false);
083        }
084
085        @Override
086        public void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid)
087                        throws BeansException {
088
089                List<PropertyAccessException> propertyAccessExceptions = null;
090                List<PropertyValue> propertyValues = (pvs instanceof MutablePropertyValues ?
091                                ((MutablePropertyValues) pvs).getPropertyValueList() : Arrays.asList(pvs.getPropertyValues()));
092
093                if (ignoreUnknown) {
094                        this.suppressNotWritablePropertyException = true;
095                }
096                try {
097                        for (PropertyValue pv : propertyValues) {
098                                // setPropertyValue may throw any BeansException, which won't be caught
099                                // here, if there is a critical failure such as no matching field.
100                                // We can attempt to deal only with less serious exceptions.
101                                try {
102                                        setPropertyValue(pv);
103                                }
104                                catch (NotWritablePropertyException ex) {
105                                        if (!ignoreUnknown) {
106                                                throw ex;
107                                        }
108                                        // Otherwise, just ignore it and continue...
109                                }
110                                catch (NullValueInNestedPathException ex) {
111                                        if (!ignoreInvalid) {
112                                                throw ex;
113                                        }
114                                        // Otherwise, just ignore it and continue...
115                                }
116                                catch (PropertyAccessException ex) {
117                                        if (propertyAccessExceptions == null) {
118                                                propertyAccessExceptions = new LinkedList<PropertyAccessException>();
119                                        }
120                                        propertyAccessExceptions.add(ex);
121                                }
122                        }
123                }
124                finally {
125                        if (ignoreUnknown) {
126                                this.suppressNotWritablePropertyException = false;
127                        }
128                }
129
130                // If we encountered individual exceptions, throw the composite exception.
131                if (propertyAccessExceptions != null) {
132                        PropertyAccessException[] paeArray =
133                                        propertyAccessExceptions.toArray(new PropertyAccessException[propertyAccessExceptions.size()]);
134                        throw new PropertyBatchUpdateException(paeArray);
135                }
136        }
137
138
139        // Redefined with public visibility.
140        @Override
141        public Class<?> getPropertyType(String propertyPath) {
142                return null;
143        }
144
145        /**
146         * Actually get the value of a property.
147         * @param propertyName name of the property to get the value of
148         * @return the value of the property
149         * @throws InvalidPropertyException if there is no such property or
150         * if the property isn't readable
151         * @throws PropertyAccessException if the property was valid but the
152         * accessor method failed
153         */
154        @Override
155        public abstract Object getPropertyValue(String propertyName) throws BeansException;
156
157        /**
158         * Actually set a property value.
159         * @param propertyName name of the property to set value of
160         * @param value the new value
161         * @throws InvalidPropertyException if there is no such property or
162         * if the property isn't writable
163         * @throws PropertyAccessException if the property was valid but the
164         * accessor method failed or a type mismatch occurred
165         */
166        @Override
167        public abstract void setPropertyValue(String propertyName, Object value) throws BeansException;
168
169}