001/*
002 * Copyright 2002-2018 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.validation;
018
019import java.io.Serializable;
020
021import org.springframework.beans.BeanWrapper;
022import org.springframework.beans.ConfigurablePropertyAccessor;
023import org.springframework.beans.PropertyAccessorFactory;
024
025/**
026 * Default implementation of the {@link Errors} and {@link BindingResult}
027 * interfaces, for the registration and evaluation of binding errors on
028 * JavaBean objects.
029 *
030 * <p>Performs standard JavaBean property access, also supporting nested
031 * properties. Normally, application code will work with the
032 * {@code Errors} interface or the {@code BindingResult} interface.
033 * A {@link DataBinder} returns its {@code BindingResult} via
034 * {@link DataBinder#getBindingResult()}.
035 *
036 * @author Juergen Hoeller
037 * @since 2.0
038 * @see DataBinder#getBindingResult()
039 * @see DataBinder#initBeanPropertyAccess()
040 * @see DirectFieldBindingResult
041 */
042@SuppressWarnings("serial")
043public class BeanPropertyBindingResult extends AbstractPropertyBindingResult implements Serializable {
044
045        private final Object target;
046
047        private final boolean autoGrowNestedPaths;
048
049        private final int autoGrowCollectionLimit;
050
051        private transient BeanWrapper beanWrapper;
052
053
054        /**
055         * Creates a new instance of the {@link BeanPropertyBindingResult} class.
056         * @param target the target bean to bind onto
057         * @param objectName the name of the target object
058         */
059        public BeanPropertyBindingResult(Object target, String objectName) {
060                this(target, objectName, true, Integer.MAX_VALUE);
061        }
062
063        /**
064         * Creates a new instance of the {@link BeanPropertyBindingResult} class.
065         * @param target the target bean to bind onto
066         * @param objectName the name of the target object
067         * @param autoGrowNestedPaths whether to "auto-grow" a nested path that contains a null value
068         * @param autoGrowCollectionLimit the limit for array and collection auto-growing
069         */
070        public BeanPropertyBindingResult(Object target, String objectName, boolean autoGrowNestedPaths, int autoGrowCollectionLimit) {
071                super(objectName);
072                this.target = target;
073                this.autoGrowNestedPaths = autoGrowNestedPaths;
074                this.autoGrowCollectionLimit = autoGrowCollectionLimit;
075        }
076
077
078        @Override
079        public final Object getTarget() {
080                return this.target;
081        }
082
083        /**
084         * Returns the {@link BeanWrapper} that this instance uses.
085         * Creates a new one if none existed before.
086         * @see #createBeanWrapper()
087         */
088        @Override
089        public final ConfigurablePropertyAccessor getPropertyAccessor() {
090                if (this.beanWrapper == null) {
091                        this.beanWrapper = createBeanWrapper();
092                        this.beanWrapper.setExtractOldValueForEditor(true);
093                        this.beanWrapper.setAutoGrowNestedPaths(this.autoGrowNestedPaths);
094                        this.beanWrapper.setAutoGrowCollectionLimit(this.autoGrowCollectionLimit);
095                }
096                return this.beanWrapper;
097        }
098
099        /**
100         * Create a new {@link BeanWrapper} for the underlying target object.
101         * @see #getTarget()
102         */
103        protected BeanWrapper createBeanWrapper() {
104                if (this.target == null) {
105                        throw new IllegalStateException("Cannot access properties on null bean instance '" + getObjectName() + "'");
106                }
107                return PropertyAccessorFactory.forBeanPropertyAccess(this.target);
108        }
109
110}