1 16 17 package org.springframework.beans; 18 19 import java.beans.PropertyDescriptor ; 20 import java.beans.PropertyEditor ; 21 import java.beans.PropertyEditorManager ; 22 import java.lang.reflect.Array ; 23 import java.lang.reflect.Field ; 24 import java.util.Collection ; 25 import java.util.Iterator ; 26 import java.util.Map ; 27 28 import org.apache.commons.logging.Log; 29 import org.apache.commons.logging.LogFactory; 30 31 import org.springframework.core.CollectionFactory; 32 import org.springframework.core.GenericCollectionTypeResolver; 33 import org.springframework.core.JdkVersion; 34 import org.springframework.core.MethodParameter; 35 import org.springframework.util.Assert; 36 import org.springframework.util.ClassUtils; 37 import org.springframework.util.StringUtils; 38 39 50 class TypeConverterDelegate { 51 52 55 private static final Log logger = LogFactory.getLog(TypeConverterDelegate.class); 56 57 private final PropertyEditorRegistrySupport propertyEditorRegistry; 58 59 private final Object targetObject; 60 61 62 66 public TypeConverterDelegate(PropertyEditorRegistrySupport propertyEditorRegistry) { 67 this(propertyEditorRegistry, null); 68 } 69 70 75 public TypeConverterDelegate(PropertyEditorRegistrySupport propertyEditorRegistry, Object targetObject) { 76 Assert.notNull(propertyEditorRegistry, "Property editor registry must not be null"); 77 this.propertyEditorRegistry = propertyEditorRegistry; 78 this.targetObject = targetObject; 79 } 80 81 82 90 public Object convertIfNecessary(Object newValue, Class requiredType) throws IllegalArgumentException { 91 return convertIfNecessary(null, null, newValue, requiredType, null, null); 92 } 93 94 104 public Object convertIfNecessary(Object newValue, Class requiredType, MethodParameter methodParam) 105 throws IllegalArgumentException { 106 107 return convertIfNecessary(null, null, newValue, requiredType, null, methodParam); 108 } 109 110 120 public Object convertIfNecessary( 121 String propertyName, Object oldValue, Object newValue, Class requiredType) 122 throws IllegalArgumentException { 123 124 return convertIfNecessary(propertyName, oldValue, newValue, requiredType, null, null); 125 } 126 127 135 public Object convertIfNecessary(Object oldValue, Object newValue, PropertyDescriptor descriptor) 136 throws IllegalArgumentException { 137 138 Assert.notNull(descriptor, "PropertyDescriptor must not be null"); 139 return convertIfNecessary( 140 descriptor.getName(), oldValue, newValue, descriptor.getPropertyType(), descriptor, 141 new MethodParameter(descriptor.getWriteMethod(), 0)); 142 } 143 144 145 159 protected Object convertIfNecessary( 160 String propertyName, Object oldValue, Object newValue, Class requiredType, 161 PropertyDescriptor descriptor, MethodParameter methodParam) 162 throws IllegalArgumentException { 163 164 Object convertedValue = newValue; 165 166 PropertyEditor pe = this.propertyEditorRegistry.findCustomEditor(requiredType, propertyName); 168 169 if (pe != null || (requiredType != null && !ClassUtils.isAssignableValue(requiredType, convertedValue))) { 171 if (pe == null && descriptor != null) { 172 if (JdkVersion.isAtLeastJava15()) { 173 pe = descriptor.createPropertyEditor(this.targetObject); 174 } 175 else { 176 Class editorClass = descriptor.getPropertyEditorClass(); 177 if (editorClass != null) { 178 pe = (PropertyEditor ) BeanUtils.instantiateClass(editorClass); 179 } 180 } 181 } 182 if (pe == null && requiredType != null) { 183 pe = (PropertyEditor ) this.propertyEditorRegistry.getDefaultEditor(requiredType); 185 if (pe == null) { 186 pe = PropertyEditorManager.findEditor(requiredType); 188 } 189 } 190 convertedValue = convertValue(convertedValue, requiredType, pe, oldValue); 191 } 192 193 if (requiredType != null) { 194 196 if (convertedValue != null && requiredType.isArray()) { 197 return convertToTypedArray(convertedValue, propertyName, requiredType.getComponentType()); 199 } 200 else if (convertedValue instanceof Collection && Collection .class.isAssignableFrom(requiredType)) { 201 return convertToTypedCollection((Collection ) convertedValue, propertyName, methodParam); 203 } 204 else if (convertedValue instanceof Map && Map .class.isAssignableFrom(requiredType)) { 205 return convertToTypedMap((Map ) convertedValue, propertyName, methodParam); 207 } 208 else if (convertedValue instanceof String && !requiredType.isInstance(convertedValue)) { 209 try { 213 Field enumField = requiredType.getField((String ) convertedValue); 214 convertedValue = enumField.get(null); 215 } 216 catch (Throwable ex) { 217 if (logger.isTraceEnabled()) { 218 logger.trace("Field [" + convertedValue + "] isn't an enum value", ex); 219 } 220 } 221 } 222 223 if (!ClassUtils.isAssignableValue(requiredType, convertedValue)) { 224 throw new IllegalArgumentException ("Cannot convert value of type [" + 226 (newValue != null ? ClassUtils.getQualifiedName(newValue.getClass()) : null) + 227 "] to required type [" + ClassUtils.getQualifiedName(requiredType) + "] for property '" + 228 propertyName + "': no matching editors or conversion strategy found"); 229 } 230 } 231 232 return convertedValue; 233 } 234 235 protected Object convertValue(Object newValue, Class requiredType, PropertyEditor pe, Object oldValue) { 236 Object convertedValue = newValue; 237 238 if (pe != null && !(convertedValue instanceof String )) { 239 pe.setValue(convertedValue); 244 Object newConvertedValue = pe.getValue(); 245 if (newConvertedValue != convertedValue) { 246 convertedValue = newConvertedValue; 247 pe = null; 250 } 251 } 252 253 if (requiredType != null && !requiredType.isArray() && convertedValue instanceof String []) { 254 if (logger.isTraceEnabled()) { 258 logger.trace("Converting String array to comma-delimited String [" + convertedValue + "]"); 259 } 260 convertedValue = StringUtils.arrayToCommaDelimitedString((String []) convertedValue); 261 } 262 263 if (pe != null && convertedValue instanceof String ) { 264 if (logger.isTraceEnabled()) { 266 logger.trace("Converting String to [" + requiredType + "] using property editor [" + pe + "]"); 267 } 268 pe.setValue(oldValue); 269 pe.setAsText((String ) convertedValue); 270 convertedValue = pe.getValue(); 271 } 272 273 return convertedValue; 274 } 275 276 protected Object convertToTypedArray(Object input, String propertyName, Class componentType) { 277 if (input instanceof Collection ) { 278 Collection coll = (Collection ) input; 280 Object result = Array.newInstance(componentType, coll.size()); 281 int i = 0; 282 for (Iterator it = coll.iterator(); it.hasNext(); i++) { 283 Object value = convertIfNecessary( 284 buildIndexedPropertyName(propertyName, i), null, it.next(), componentType); 285 Array.set(result, i, value); 286 } 287 return result; 288 } 289 else if (input.getClass().isArray()) { 290 if (componentType.equals(input.getClass().getComponentType()) && 292 !this.propertyEditorRegistry.hasCustomEditorForElement(componentType, propertyName)) { 293 return input; 294 } 295 int arrayLength = Array.getLength(input); 296 Object result = Array.newInstance(componentType, arrayLength); 297 for (int i = 0; i < arrayLength; i++) { 298 Object value = convertIfNecessary( 299 buildIndexedPropertyName(propertyName, i), null, Array.get(input, i), componentType); 300 Array.set(result, i, value); 301 } 302 return result; 303 } 304 else { 305 Object result = Array.newInstance(componentType, 1); 307 Object value = convertIfNecessary( 308 buildIndexedPropertyName(propertyName, 0), null, input, componentType); 309 Array.set(result, 0, value); 310 return result; 311 } 312 } 313 314 protected Collection convertToTypedCollection( 315 Collection original, String propertyName, MethodParameter methodParam) { 316 317 Class elementType = null; 318 if (methodParam != null && JdkVersion.isAtLeastJava15()) { 319 elementType = GenericCollectionTypeResolver.getCollectionParameterType(methodParam); 320 } 321 Collection convertedCopy = null; 322 Iterator it = null; 323 try { 324 convertedCopy = CollectionFactory.createApproximateCollection(original, original.size()); 325 it = original.iterator(); 326 } 327 catch (Throwable ex) { 328 if (logger.isDebugEnabled()) { 329 logger.debug("Cannot access Collection of type [" + original.getClass().getName() + 330 "] - injecting original Collection as-is", ex); 331 } 332 return original; 333 } 334 boolean actuallyConverted = false; 335 int i = 0; 336 for (; it.hasNext(); i++) { 337 Object element = it.next(); 338 String indexedPropertyName = buildIndexedPropertyName(propertyName, i); 339 if (methodParam != null) { 340 methodParam.increaseNestingLevel(); 341 } 342 Object convertedElement = 343 convertIfNecessary(indexedPropertyName, null, element, elementType, null, methodParam); 344 if (methodParam != null) { 345 methodParam.decreaseNestingLevel(); 346 } 347 convertedCopy.add(convertedElement); 348 actuallyConverted = actuallyConverted || (element != convertedElement); 349 } 350 return (actuallyConverted ? convertedCopy : original); 351 } 352 353 protected Map convertToTypedMap(Map original, String propertyName, MethodParameter methodParam) { 354 Class keyType = null; 355 Class valueType = null; 356 if (methodParam != null && JdkVersion.isAtLeastJava15()) { 357 keyType = GenericCollectionTypeResolver.getMapKeyParameterType(methodParam); 358 valueType = GenericCollectionTypeResolver.getMapValueParameterType(methodParam); 359 } 360 Map convertedCopy = null; 361 Iterator it = null; 362 try { 363 convertedCopy = CollectionFactory.createApproximateMap(original, original.size()); 364 it = original.entrySet().iterator(); 365 } 366 catch (Throwable ex) { 367 if (logger.isDebugEnabled()) { 368 logger.debug("Cannot access Map of type [" + original.getClass().getName() + 369 "] - injecting original Map as-is", ex); 370 } 371 return original; 372 } 373 boolean actuallyConverted = false; 374 while (it.hasNext()) { 375 Map.Entry entry = (Map.Entry ) it.next(); 376 Object key = entry.getKey(); 377 Object value = entry.getValue(); 378 String keyedPropertyName = buildKeyedPropertyName(propertyName, key); 379 if (methodParam != null) { 380 methodParam.increaseNestingLevel(); 381 methodParam.setTypeIndexForCurrentLevel(0); 382 } 383 Object convertedKey = convertIfNecessary(keyedPropertyName, null, key, keyType, null, methodParam); 384 if (methodParam != null) { 385 methodParam.setTypeIndexForCurrentLevel(1); 386 } 387 Object convertedValue = convertIfNecessary(keyedPropertyName, null, value, valueType, null, methodParam); 388 if (methodParam != null) { 389 methodParam.decreaseNestingLevel(); 390 } 391 convertedCopy.put(convertedKey, convertedValue); 392 actuallyConverted = actuallyConverted || (key != convertedKey) || (value != convertedValue); 393 } 394 return (actuallyConverted ? convertedCopy : original); 395 } 396 397 private String buildIndexedPropertyName(String propertyName, int index) { 398 return (propertyName != null ? 399 propertyName + PropertyAccessor.PROPERTY_KEY_PREFIX + index + PropertyAccessor.PROPERTY_KEY_SUFFIX : 400 null); 401 } 402 403 private String buildKeyedPropertyName(String propertyName, Object key) { 404 return (propertyName != null ? 405 propertyName + PropertyAccessor.PROPERTY_KEY_PREFIX + key + PropertyAccessor.PROPERTY_KEY_SUFFIX : 406 null); 407 } 408 409 } 410 | Popular Tags |