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