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 org.springframework.beans.ConfigurablePropertyAccessor; 020import org.springframework.beans.PropertyAccessorFactory; 021import org.springframework.lang.Nullable; 022 023/** 024 * Special implementation of the Errors and BindingResult interfaces, 025 * supporting registration and evaluation of binding errors on value objects. 026 * Performs direct field access instead of going through JavaBean getters. 027 * 028 * <p>Since Spring 4.1 this implementation is able to traverse nested fields. 029 * 030 * @author Juergen Hoeller 031 * @since 2.0 032 * @see DataBinder#getBindingResult() 033 * @see DataBinder#initDirectFieldAccess() 034 * @see BeanPropertyBindingResult 035 */ 036@SuppressWarnings("serial") 037public class DirectFieldBindingResult extends AbstractPropertyBindingResult { 038 039 @Nullable 040 private final Object target; 041 042 private final boolean autoGrowNestedPaths; 043 044 @Nullable 045 private transient ConfigurablePropertyAccessor directFieldAccessor; 046 047 048 /** 049 * Create a new DirectFieldBindingResult instance. 050 * @param target the target object to bind onto 051 * @param objectName the name of the target object 052 */ 053 public DirectFieldBindingResult(@Nullable Object target, String objectName) { 054 this(target, objectName, true); 055 } 056 057 /** 058 * Create a new DirectFieldBindingResult instance. 059 * @param target the target object to bind onto 060 * @param objectName the name of the target object 061 * @param autoGrowNestedPaths whether to "auto-grow" a nested path that contains a null value 062 */ 063 public DirectFieldBindingResult(@Nullable Object target, String objectName, boolean autoGrowNestedPaths) { 064 super(objectName); 065 this.target = target; 066 this.autoGrowNestedPaths = autoGrowNestedPaths; 067 } 068 069 070 @Override 071 @Nullable 072 public final Object getTarget() { 073 return this.target; 074 } 075 076 /** 077 * Returns the DirectFieldAccessor that this instance uses. 078 * Creates a new one if none existed before. 079 * @see #createDirectFieldAccessor() 080 */ 081 @Override 082 public final ConfigurablePropertyAccessor getPropertyAccessor() { 083 if (this.directFieldAccessor == null) { 084 this.directFieldAccessor = createDirectFieldAccessor(); 085 this.directFieldAccessor.setExtractOldValueForEditor(true); 086 this.directFieldAccessor.setAutoGrowNestedPaths(this.autoGrowNestedPaths); 087 } 088 return this.directFieldAccessor; 089 } 090 091 /** 092 * Create a new DirectFieldAccessor for the underlying target object. 093 * @see #getTarget() 094 */ 095 protected ConfigurablePropertyAccessor createDirectFieldAccessor() { 096 if (this.target == null) { 097 throw new IllegalStateException("Cannot access fields on null target instance '" + getObjectName() + "'"); 098 } 099 return PropertyAccessorFactory.forDirectFieldAccess(this.target); 100 } 101 102}