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