📄 propertyeditorregistrysupport.java
字号:
}
if (propertyPath != null) {
// Check property-specific editor first.
PropertyEditor editor = getCustomEditor(propertyPath, requiredType);
if (editor == null) {
List strippedPaths = new LinkedList();
addStrippedPropertyPaths(strippedPaths, "", propertyPath);
for (Iterator it = strippedPaths.iterator(); it.hasNext() && editor == null;) {
String strippedPath = (String) it.next();
editor = getCustomEditor(strippedPath, requiredType);
}
}
if (editor != null) {
return editor;
}
else if (requiredType == null) {
requiredType = getPropertyType(propertyPath);
}
}
// No property-specific editor -> check type-specific editor.
return getCustomEditor(requiredType);
}
/**
* Determine the property type for the given property path.
* Called by <code>findCustomEditor</code> if no required type has been specified,
* to be able to find a type-specific editor even if just given a property path.
* <p>Default implementation always returns <code>null</code>.
* BeanWrapperImpl overrides this with the standard <code>getPropertyType</code>
* method as defined by the BeanWrapper interface.
* @param propertyPath the property path to determine the type for
* @return the type of the property, or <code>null</code> if not determinable
* @see BeanWrapper#getPropertyType(String)
*/
protected Class getPropertyType(String propertyPath) {
return null;
}
/**
* Get custom editor that has been registered for the given property.
* @return the custom editor, or <code>null</code> if none specific for this property
*/
private PropertyEditor getCustomEditor(String propertyName, Class requiredType) {
CustomEditorHolder holder = (CustomEditorHolder) this.customEditors.get(propertyName);
return (holder != null ? holder.getPropertyEditor(requiredType) : null);
}
/**
* Get custom editor for the given type. If no direct match found,
* try custom editor for superclass (which will in any case be able
* to render a value as String via <code>getAsText</code>).
* @return the custom editor, or <code>null</code> if none found for this type
* @see java.beans.PropertyEditor#getAsText
*/
private PropertyEditor getCustomEditor(Class requiredType) {
if (requiredType == null) {
return null;
}
// Check directly registered editor for type.
PropertyEditor editor = (PropertyEditor) this.customEditors.get(requiredType);
if (editor == null) {
// Check cached editor for type, registered for superclass or interface.
if (this.customEditorCache != null) {
editor = (PropertyEditor) this.customEditorCache.get(requiredType);
}
if (editor == null) {
// Find editor for superclass or interface.
for (Iterator it = this.customEditors.keySet().iterator(); it.hasNext() && editor == null;) {
Object key = it.next();
if (key instanceof Class && ((Class) key).isAssignableFrom(requiredType)) {
editor = (PropertyEditor) this.customEditors.get(key);
// Cache editor for search type, to avoid the overhead
// of repeated assignable-from checks.
if (this.customEditorCache == null) {
this.customEditorCache = new HashMap();
}
this.customEditorCache.put(requiredType, editor);
}
}
}
}
return editor;
}
/**
* Guess the property type of the specified property from the registered
* custom editors (provided that they were registered for a specific type).
* @param propertyName the name of the property
* @return the property type, or <code>null</code> if not determinable
*/
protected Class guessPropertyTypeFromEditors(String propertyName) {
if (this.customEditors != null) {
CustomEditorHolder editorHolder = (CustomEditorHolder) this.customEditors.get(propertyName);
if (editorHolder == null) {
List strippedPaths = new LinkedList();
addStrippedPropertyPaths(strippedPaths, "", propertyName);
for (Iterator it = strippedPaths.iterator(); it.hasNext() && editorHolder == null;) {
String strippedName = (String) it.next();
editorHolder = (CustomEditorHolder) this.customEditors.get(strippedName);
}
}
if (editorHolder != null) {
return editorHolder.getRegisteredType();
}
}
return null;
}
/**
* Copy the custom editors registered in this instance to the given target registry.
* @param target the target registry to copy to
* @param nestedProperty the nested property path of the target registry, if any.
* If this is non-null, only editors registered for a path below this nested property
* will be copied.
*/
protected void copyCustomEditorsTo(PropertyEditorRegistry target, String nestedProperty) {
String actualPropertyName =
(nestedProperty != null ? PropertyAccessorUtils.getPropertyName(nestedProperty) : null);
if (this.customEditors != null) {
for (Iterator it = this.customEditors.entrySet().iterator(); it.hasNext();) {
Map.Entry entry = (Map.Entry) it.next();
if (entry.getKey() instanceof Class) {
Class requiredType = (Class) entry.getKey();
PropertyEditor editor = (PropertyEditor) entry.getValue();
target.registerCustomEditor(requiredType, editor);
}
else if (entry.getKey() instanceof String & nestedProperty != null) {
String editorPath = (String) entry.getKey();
int pos = PropertyAccessorUtils.getFirstNestedPropertySeparatorIndex(editorPath);
if (pos != -1) {
String editorNestedProperty = editorPath.substring(0, pos);
String editorNestedPath = editorPath.substring(pos + 1);
if (editorNestedProperty.equals(nestedProperty) || editorNestedProperty.equals(actualPropertyName)) {
CustomEditorHolder editorHolder = (CustomEditorHolder) entry.getValue();
target.registerCustomEditor(
editorHolder.getRegisteredType(), editorNestedPath, editorHolder.getPropertyEditor());
}
}
}
}
}
}
/**
* Add property paths with all variations of stripped keys and/or indexes.
* Invokes itself recursively with nested paths
* @param strippedPaths the result list to add to
* @param nestedPath the current nested path
* @param propertyPath the property path to check for keys/indexes to strip
*/
private void addStrippedPropertyPaths(List strippedPaths, String nestedPath, String propertyPath) {
int startIndex = propertyPath.indexOf(PropertyAccessor.PROPERTY_KEY_PREFIX_CHAR);
if (startIndex != -1) {
int endIndex = propertyPath.indexOf(PropertyAccessor.PROPERTY_KEY_SUFFIX_CHAR);
if (endIndex != -1) {
String prefix = propertyPath.substring(0, startIndex);
String key = propertyPath.substring(startIndex, endIndex + 1);
String suffix = propertyPath.substring(endIndex + 1, propertyPath.length());
// Strip the first key.
strippedPaths.add(nestedPath + prefix + suffix);
// Search for further keys to strip, with the first key stripped.
addStrippedPropertyPaths(strippedPaths, nestedPath + prefix, suffix);
// Search for further keys to strip, with the first key not stripped.
addStrippedPropertyPaths(strippedPaths, nestedPath + prefix + key, suffix);
}
}
}
/**
* Holder for a registered custom editor with property name.
* Keeps the PropertyEditor itself plus the type it was registered for.
*/
private static class CustomEditorHolder {
private final PropertyEditor propertyEditor;
private final Class registeredType;
private CustomEditorHolder(PropertyEditor propertyEditor, Class registeredType) {
this.propertyEditor = propertyEditor;
this.registeredType = registeredType;
}
private PropertyEditor getPropertyEditor() {
return propertyEditor;
}
private Class getRegisteredType() {
return registeredType;
}
private PropertyEditor getPropertyEditor(Class requiredType) {
// Special case: If no required type specified, which usually only happens for
// Collection elements, or required type is not assignable to registered type,
// which usually only happens for generic properties of type Object -
// then return PropertyEditor if not registered for Collection or array type.
// (If not registered for Collection or array, it is assumed to be intended
// for elements.)
if (this.registeredType == null ||
(requiredType != null &&
(BeanUtils.isAssignable(this.registeredType, requiredType) ||
BeanUtils.isAssignable(requiredType, this.registeredType))) ||
(requiredType == null &&
(!Collection.class.isAssignableFrom(this.registeredType) && !this.registeredType.isArray()))) {
return this.propertyEditor;
}
else {
return null;
}
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -