1 16 17 package org.springframework.beans; 18 19 import java.beans.PropertyEditor ; 20 import java.io.File ; 21 import java.io.InputStream ; 22 import java.math.BigDecimal ; 23 import java.math.BigInteger ; 24 import java.net.URI ; 25 import java.net.URL ; 26 import java.util.Collection ; 27 import java.util.HashMap ; 28 import java.util.Iterator ; 29 import java.util.LinkedList ; 30 import java.util.List ; 31 import java.util.Locale ; 32 import java.util.Map ; 33 import java.util.Properties ; 34 import java.util.Set ; 35 import java.util.SortedMap ; 36 import java.util.SortedSet ; 37 import java.util.regex.Pattern ; 38 39 import org.springframework.beans.propertyeditors.ByteArrayPropertyEditor; 40 import org.springframework.beans.propertyeditors.CharArrayPropertyEditor; 41 import org.springframework.beans.propertyeditors.CharacterEditor; 42 import org.springframework.beans.propertyeditors.ClassArrayEditor; 43 import org.springframework.beans.propertyeditors.ClassEditor; 44 import org.springframework.beans.propertyeditors.CustomBooleanEditor; 45 import org.springframework.beans.propertyeditors.CustomCollectionEditor; 46 import org.springframework.beans.propertyeditors.CustomMapEditor; 47 import org.springframework.beans.propertyeditors.CustomNumberEditor; 48 import org.springframework.beans.propertyeditors.FileEditor; 49 import org.springframework.beans.propertyeditors.InputStreamEditor; 50 import org.springframework.beans.propertyeditors.LocaleEditor; 51 import org.springframework.beans.propertyeditors.PatternEditor; 52 import org.springframework.beans.propertyeditors.PropertiesEditor; 53 import org.springframework.beans.propertyeditors.URIEditor; 54 import org.springframework.beans.propertyeditors.URLEditor; 55 import org.springframework.core.CollectionFactory; 56 import org.springframework.core.JdkVersion; 57 import org.springframework.core.io.Resource; 58 import org.springframework.core.io.support.ResourceArrayPropertyEditor; 59 import org.springframework.util.ClassUtils; 60 61 74 public class PropertyEditorRegistrySupport implements PropertyEditorRegistry { 75 76 private Map defaultEditors; 77 78 private Map customEditors; 79 80 private Map customEditorCache; 81 82 83 87 112 protected void registerDefaultEditors() { 113 this.defaultEditors = new HashMap (32); 114 115 this.defaultEditors.put(Class .class, new ClassEditor()); 118 this.defaultEditors.put(Class [].class, new ClassArrayEditor()); 119 this.defaultEditors.put(File .class, new FileEditor()); 120 this.defaultEditors.put(InputStream .class, new InputStreamEditor()); 121 this.defaultEditors.put(Locale .class, new LocaleEditor()); 122 this.defaultEditors.put(Properties .class, new PropertiesEditor()); 123 this.defaultEditors.put(Resource[].class, new ResourceArrayPropertyEditor()); 124 this.defaultEditors.put(URL .class, new URLEditor()); 125 126 if (JdkVersion.isAtLeastJava14()) { 128 this.defaultEditors.put(URI .class, new URIEditor()); 129 this.defaultEditors.put(Pattern .class, new PatternEditor()); 130 } 131 132 this.defaultEditors.put(Collection .class, new CustomCollectionEditor(Collection .class)); 135 this.defaultEditors.put(Set .class, new CustomCollectionEditor(Set .class)); 136 this.defaultEditors.put(SortedSet .class, new CustomCollectionEditor(SortedSet .class)); 137 this.defaultEditors.put(List .class, new CustomCollectionEditor(List .class)); 138 this.defaultEditors.put(SortedMap .class, new CustomMapEditor(SortedMap .class)); 139 140 this.defaultEditors.put(byte[].class, new ByteArrayPropertyEditor()); 142 this.defaultEditors.put(char[].class, new CharArrayPropertyEditor()); 143 144 this.defaultEditors.put(char.class, new CharacterEditor(false)); 146 this.defaultEditors.put(Character .class, new CharacterEditor(true)); 147 148 this.defaultEditors.put(boolean.class, new CustomBooleanEditor(false)); 150 this.defaultEditors.put(Boolean .class, new CustomBooleanEditor(true)); 151 152 this.defaultEditors.put(byte.class, new CustomNumberEditor(Byte .class, false)); 155 this.defaultEditors.put(Byte .class, new CustomNumberEditor(Byte .class, true)); 156 this.defaultEditors.put(short.class, new CustomNumberEditor(Short .class, false)); 157 this.defaultEditors.put(Short .class, new CustomNumberEditor(Short .class, true)); 158 this.defaultEditors.put(int.class, new CustomNumberEditor(Integer .class, false)); 159 this.defaultEditors.put(Integer .class, new CustomNumberEditor(Integer .class, true)); 160 this.defaultEditors.put(long.class, new CustomNumberEditor(Long .class, false)); 161 this.defaultEditors.put(Long .class, new CustomNumberEditor(Long .class, true)); 162 this.defaultEditors.put(float.class, new CustomNumberEditor(Float .class, false)); 163 this.defaultEditors.put(Float .class, new CustomNumberEditor(Float .class, true)); 164 this.defaultEditors.put(double.class, new CustomNumberEditor(Double .class, false)); 165 this.defaultEditors.put(Double .class, new CustomNumberEditor(Double .class, true)); 166 this.defaultEditors.put(BigDecimal .class, new CustomNumberEditor(BigDecimal .class, true)); 167 this.defaultEditors.put(BigInteger .class, new CustomNumberEditor(BigInteger .class, true)); 168 } 169 170 175 protected PropertyEditor getDefaultEditor(Class requiredType) { 176 if (this.defaultEditors == null) { 177 return null; 178 } 179 return (PropertyEditor ) this.defaultEditors.get(requiredType); 180 } 181 182 186 protected void copyDefaultEditorsTo(PropertyEditorRegistrySupport target) { 187 target.defaultEditors = this.defaultEditors; 188 } 189 190 191 195 public void registerCustomEditor(Class requiredType, PropertyEditor propertyEditor) { 196 registerCustomEditor(requiredType, null, propertyEditor); 197 } 198 199 public void registerCustomEditor(Class requiredType, String propertyPath, PropertyEditor propertyEditor) { 200 if (requiredType == null && propertyPath == null) { 201 throw new IllegalArgumentException ("Either requiredType or propertyPath is required"); 202 } 203 if (this.customEditors == null) { 204 this.customEditors = CollectionFactory.createLinkedMapIfPossible(16); 205 } 206 if (propertyPath != null) { 207 this.customEditors.put(propertyPath, new CustomEditorHolder(propertyEditor, requiredType)); 208 } 209 else { 210 this.customEditors.put(requiredType, propertyEditor); 211 this.customEditorCache = null; 212 } 213 } 214 215 public PropertyEditor findCustomEditor(Class requiredType, String propertyPath) { 216 if (this.customEditors == null) { 217 return null; 218 } 219 Class requiredTypeToUse = requiredType; 220 if (propertyPath != null) { 221 PropertyEditor editor = getCustomEditor(propertyPath, requiredType); 223 if (editor == null) { 224 List strippedPaths = new LinkedList (); 225 addStrippedPropertyPaths(strippedPaths, "", propertyPath); 226 for (Iterator it = strippedPaths.iterator(); it.hasNext() && editor == null;) { 227 String strippedPath = (String ) it.next(); 228 editor = getCustomEditor(strippedPath, requiredType); 229 } 230 } 231 if (editor != null) { 232 return editor; 233 } 234 else if (requiredType == null) { 235 requiredTypeToUse = getPropertyType(propertyPath); 236 } 237 } 238 return getCustomEditor(requiredTypeToUse); 240 } 241 242 249 public boolean hasCustomEditorForElement(Class elementType, String propertyPath) { 250 if (this.customEditors == null) { 251 return false; 252 } 253 for (Iterator it = this.customEditors.entrySet().iterator(); it.hasNext();) { 254 Map.Entry entry = (Map.Entry ) it.next(); 255 if (entry.getKey() instanceof String ) { 256 String regPath = (String ) entry.getKey(); 257 if (PropertyAccessorUtils.matchesProperty(regPath, propertyPath)) { 258 CustomEditorHolder editorHolder = (CustomEditorHolder) entry.getValue(); 259 if (editorHolder.getPropertyEditor(elementType) != null) { 260 return true; 261 } 262 } 263 } 264 } 265 return this.customEditors.containsKey(elementType); 267 } 268 269 280 protected Class getPropertyType(String propertyPath) { 281 return null; 282 } 283 284 288 private PropertyEditor getCustomEditor(String propertyName, Class requiredType) { 289 CustomEditorHolder holder = (CustomEditorHolder) this.customEditors.get(propertyName); 290 return (holder != null ? holder.getPropertyEditor(requiredType) : null); 291 } 292 293 300 private PropertyEditor getCustomEditor(Class requiredType) { 301 if (requiredType == null) { 302 return null; 303 } 304 PropertyEditor editor = (PropertyEditor ) this.customEditors.get(requiredType); 306 if (editor == null) { 307 if (this.customEditorCache != null) { 309 editor = (PropertyEditor ) this.customEditorCache.get(requiredType); 310 } 311 if (editor == null) { 312 for (Iterator it = this.customEditors.keySet().iterator(); it.hasNext() && editor == null;) { 314 Object key = it.next(); 315 if (key instanceof Class && ((Class ) key).isAssignableFrom(requiredType)) { 316 editor = (PropertyEditor ) this.customEditors.get(key); 317 if (this.customEditorCache == null) { 320 this.customEditorCache = new HashMap (); 321 } 322 this.customEditorCache.put(requiredType, editor); 323 } 324 } 325 } 326 } 327 return editor; 328 } 329 330 336 protected Class guessPropertyTypeFromEditors(String propertyName) { 337 if (this.customEditors != null) { 338 CustomEditorHolder editorHolder = (CustomEditorHolder) this.customEditors.get(propertyName); 339 if (editorHolder == null) { 340 List strippedPaths = new LinkedList (); 341 addStrippedPropertyPaths(strippedPaths, "", propertyName); 342 for (Iterator it = strippedPaths.iterator(); it.hasNext() && editorHolder == null;) { 343 String strippedName = (String ) it.next(); 344 editorHolder = (CustomEditorHolder) this.customEditors.get(strippedName); 345 } 346 } 347 if (editorHolder != null) { 348 return editorHolder.getRegisteredType(); 349 } 350 } 351 return null; 352 } 353 354 361 protected void copyCustomEditorsTo(PropertyEditorRegistry target, String nestedProperty) { 362 String actualPropertyName = 363 (nestedProperty != null ? PropertyAccessorUtils.getPropertyName(nestedProperty) : null); 364 if (this.customEditors != null) { 365 for (Iterator it = this.customEditors.entrySet().iterator(); it.hasNext();) { 366 Map.Entry entry = (Map.Entry ) it.next(); 367 if (entry.getKey() instanceof Class ) { 368 Class requiredType = (Class ) entry.getKey(); 369 PropertyEditor editor = (PropertyEditor ) entry.getValue(); 370 target.registerCustomEditor(requiredType, editor); 371 } 372 else if (entry.getKey() instanceof String & nestedProperty != null) { 373 String editorPath = (String ) entry.getKey(); 374 int pos = PropertyAccessorUtils.getFirstNestedPropertySeparatorIndex(editorPath); 375 if (pos != -1) { 376 String editorNestedProperty = editorPath.substring(0, pos); 377 String editorNestedPath = editorPath.substring(pos + 1); 378 if (editorNestedProperty.equals(nestedProperty) || editorNestedProperty.equals(actualPropertyName)) { 379 CustomEditorHolder editorHolder = (CustomEditorHolder) entry.getValue(); 380 target.registerCustomEditor( 381 editorHolder.getRegisteredType(), editorNestedPath, editorHolder.getPropertyEditor()); 382 } 383 } 384 } 385 } 386 } 387 } 388 389 390 397 private void addStrippedPropertyPaths(List strippedPaths, String nestedPath, String propertyPath) { 398 int startIndex = propertyPath.indexOf(PropertyAccessor.PROPERTY_KEY_PREFIX_CHAR); 399 if (startIndex != -1) { 400 int endIndex = propertyPath.indexOf(PropertyAccessor.PROPERTY_KEY_SUFFIX_CHAR); 401 if (endIndex != -1) { 402 String prefix = propertyPath.substring(0, startIndex); 403 String key = propertyPath.substring(startIndex, endIndex + 1); 404 String suffix = propertyPath.substring(endIndex + 1, propertyPath.length()); 405 strippedPaths.add(nestedPath + prefix + suffix); 407 addStrippedPropertyPaths(strippedPaths, nestedPath + prefix, suffix); 409 addStrippedPropertyPaths(strippedPaths, nestedPath + prefix + key, suffix); 411 } 412 } 413 } 414 415 416 420 private static class CustomEditorHolder { 421 422 private final PropertyEditor propertyEditor; 423 424 private final Class registeredType; 425 426 private CustomEditorHolder(PropertyEditor propertyEditor, Class registeredType) { 427 this.propertyEditor = propertyEditor; 428 this.registeredType = registeredType; 429 } 430 431 private PropertyEditor getPropertyEditor() { 432 return this.propertyEditor; 433 } 434 435 private Class getRegisteredType() { 436 return this.registeredType; 437 } 438 439 private PropertyEditor getPropertyEditor(Class requiredType) { 440 if (this.registeredType == null || 447 (requiredType != null && 448 (ClassUtils.isAssignable(this.registeredType, requiredType) || 449 ClassUtils.isAssignable(requiredType, this.registeredType))) || 450 (requiredType == null && 451 (!Collection .class.isAssignableFrom(this.registeredType) && !this.registeredType.isArray()))) { 452 return this.propertyEditor; 453 } 454 else { 455 return null; 456 } 457 } 458 } 459 460 } 461 | Popular Tags |