simplified TypeDescriptor usage and updated use of the API across BeanWrapper and SpEL; collapsed PropertyTypeDescriptor into TypeDescriptor for simplicity and ease of use; improved docs

This commit is contained in:
Keith Donald
2011-06-02 23:37:19 +00:00
parent 9d2ee7061c
commit 6f146737f4
12 changed files with 930 additions and 449 deletions

View File

@@ -43,7 +43,6 @@ import org.springframework.core.MethodParameter;
import org.springframework.core.convert.ConversionException;
import org.springframework.core.convert.ConverterNotFoundException;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.support.PropertyTypeDescriptor;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
@@ -369,23 +368,13 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
PropertyDescriptor pd = nestedBw.getCachedIntrospectionResults().getPropertyDescriptor(tokens.actualName);
if (pd != null) {
if (tokens.keys != null) {
if (pd.getReadMethod() != null) {
return PropertyTypeDescriptor.forNestedType(new MethodParameter(pd.getReadMethod(), -1, tokens.keys.length), pd);
if (pd.getReadMethod() != null || pd.getWriteMethod() != null) {
return TypeDescriptor.nested(nestedBw.getWrappedClass(), pd, tokens.keys.length);
}
else if (pd.getWriteMethod() != null) {
MethodParameter methodParameter = new MethodParameter(BeanUtils.getWriteMethodParameter(pd));
for (int i = 0; i < tokens.keys.length; i++) {
methodParameter.increaseNestingLevel();
}
return PropertyTypeDescriptor.forNestedType(methodParameter, pd);
}
} else {
if (pd.getReadMethod() != null) {
return new PropertyTypeDescriptor(new MethodParameter(pd.getReadMethod(), -1), pd);
if (pd.getReadMethod() != null || pd.getWriteMethod() != null) {
return new TypeDescriptor(nestedBw.getWrappedClass(), pd);
}
else if (pd.getWriteMethod() != null) {
return new PropertyTypeDescriptor(BeanUtils.getWriteMethodParameter(pd), pd);
}
}
}
}
@@ -502,9 +491,9 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
private Object convertForProperty(String propertyName, Object oldValue, Object newValue, PropertyDescriptor pd)
throws TypeMismatchException {
return convertIfNecessary(propertyName, oldValue, newValue, pd.getPropertyType(),
new PropertyTypeDescriptor(BeanUtils.getWriteMethodParameter(pd), pd));
GenericTypeAwarePropertyDescriptor gpd = (GenericTypeAwarePropertyDescriptor) pd;
Class<?> beanClass = gpd.getBeanClass();
return convertIfNecessary(propertyName, oldValue, newValue, pd.getPropertyType(), new TypeDescriptor(beanClass, pd));
}
@@ -959,8 +948,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
if (isExtractOldValueForEditor() && arrayIndex < Array.getLength(propValue)) {
oldValue = Array.get(propValue, arrayIndex);
}
Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(), requiredType,
PropertyTypeDescriptor.forNestedType(requiredType, new MethodParameter(pd.getReadMethod(), -1, tokens.keys.length), pd));
Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(), requiredType, TypeDescriptor.nested(getWrappedClass(), pd, tokens.keys.length));
// TODO review this grow algorithm along side the null gap algorithm for setting lists below ... the two are inconsistent
propValue = growArrayIfNecessary(propValue, arrayIndex, actualName);
Array.set(propValue, arrayIndex, convertedValue);
@@ -980,8 +968,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
if (isExtractOldValueForEditor() && index < list.size()) {
oldValue = list.get(index);
}
Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(), requiredType,
PropertyTypeDescriptor.forNestedType(requiredType, new MethodParameter(pd.getReadMethod(), -1, tokens.keys.length), pd));
Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(), requiredType, TypeDescriptor.nested(getWrappedClass(), pd, tokens.keys.length));
if (index < list.size()) {
list.set(index, convertedValue);
}
@@ -1018,8 +1005,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
// Pass full property name and old value in here, since we want full
// conversion ability for map values.
Object convertedMapValue = convertIfNecessary(
propertyName, oldValue, pv.getValue(), mapValueType,
PropertyTypeDescriptor.forNestedType(mapValueType, new MethodParameter(pd.getReadMethod(), -1, tokens.keys.length), pd));
propertyName, oldValue, pv.getValue(), mapValueType, TypeDescriptor.nested(getWrappedClass(), pd, tokens.keys.length));
map.put(convertedMapKey, convertedMapValue);
}
else {

View File

@@ -92,7 +92,10 @@ class GenericTypeAwarePropertyDescriptor extends PropertyDescriptor {
}
}
public Class<?> getBeanClass() {
return beanClass;
}
@Override
public Method getReadMethod() {
return this.readMethod;

View File

@@ -16,7 +16,6 @@
package org.springframework.beans;
import java.beans.PropertyDescriptor;
import java.beans.PropertyEditor;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
@@ -27,13 +26,10 @@ import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.CollectionFactory;
import org.springframework.core.GenericCollectionTypeResolver;
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.support.PropertyTypeDescriptor;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
@@ -144,9 +140,8 @@ class TypeConverterDelegate {
// Value not of required type?
if (editor != null || (requiredType != null && !ClassUtils.isAssignableValue(requiredType, convertedValue))) {
if (requiredType != null && Collection.class.isAssignableFrom(requiredType) &&
convertedValue instanceof String && typeDescriptor.getMethodParameter() != null) {
Class elemType = GenericCollectionTypeResolver.getCollectionParameterType(typeDescriptor.getMethodParameter());
if (requiredType != null && Collection.class.isAssignableFrom(requiredType) && convertedValue instanceof String) {
Class elemType = typeDescriptor.getElementType();
if (elemType != null && Enum.class.isAssignableFrom(elemType)) {
convertedValue = StringUtils.commaDelimitedListToStringArray((String) convertedValue);
}
@@ -290,10 +285,10 @@ class TypeConverterDelegate {
*/
protected PropertyEditor findDefaultEditor(Class requiredType, TypeDescriptor typeDescriptor) {
PropertyEditor editor = null;
if (typeDescriptor instanceof PropertyTypeDescriptor) {
PropertyDescriptor pd = ((PropertyTypeDescriptor) typeDescriptor).getPropertyDescriptor();
editor = pd.createPropertyEditor(this.targetObject);
}
//if (typeDescriptor instanceof PropertyTypeDescriptor) {
//PropertyDescriptor pd = ((PropertyTypeDescriptor) typeDescriptor).getPropertyDescriptor();
//editor = pd.createPropertyEditor(this.targetObject);
//}
if (editor == null && requiredType != null) {
// No custom editor -> check BeanWrapperImpl's default editors.
editor = this.propertyEditorRegistry.getDefaultEditor(requiredType);
@@ -464,12 +459,8 @@ class TypeConverterDelegate {
return original;
}
MethodParameter methodParam = typeDescriptor.getMethodParameter();
Class elementType = null;
if (methodParam != null) {
elementType = GenericCollectionTypeResolver.getCollectionParameterType(methodParam);
}
if (elementType == null && originalAllowed &&
Class elementType = typeDescriptor.getElementType();
if (elementType == Object.class && originalAllowed &&
!this.propertyEditorRegistry.hasCustomEditorForElement(null, propertyName)) {
return original;
}
@@ -514,14 +505,8 @@ class TypeConverterDelegate {
for (; it.hasNext(); i++) {
Object element = it.next();
String indexedPropertyName = buildIndexedPropertyName(propertyName, i);
if (methodParam != null) {
methodParam.increaseNestingLevel();
}
Object convertedElement = convertIfNecessary(
indexedPropertyName, null, element, elementType, typeDescriptor);
if (methodParam != null) {
methodParam.decreaseNestingLevel();
}
indexedPropertyName, null, element, elementType, typeDescriptor.getElementTypeDescriptor());
try {
convertedCopy.add(convertedElement);
}
@@ -546,14 +531,9 @@ class TypeConverterDelegate {
return original;
}
Class keyType = null;
Class valueType = null;
MethodParameter methodParam = typeDescriptor.getMethodParameter();
if (methodParam != null) {
keyType = GenericCollectionTypeResolver.getMapKeyParameterType(methodParam);
valueType = GenericCollectionTypeResolver.getMapValueParameterType(methodParam);
}
if (keyType == null && valueType == null && originalAllowed &&
Class keyType = typeDescriptor.getMapKeyType();
Class valueType = typeDescriptor.getMapValueType();
if (keyType == Object.class && valueType == Object.class && originalAllowed &&
!this.propertyEditorRegistry.hasCustomEditorForElement(null, propertyName)) {
return original;
}
@@ -599,18 +579,8 @@ class TypeConverterDelegate {
Object key = entry.getKey();
Object value = entry.getValue();
String keyedPropertyName = buildKeyedPropertyName(propertyName, key);
if (methodParam != null) {
methodParam.increaseNestingLevel();
methodParam.setTypeIndexForCurrentLevel(0);
}
Object convertedKey = convertIfNecessary(keyedPropertyName, null, key, keyType, typeDescriptor);
if (methodParam != null) {
methodParam.setTypeIndexForCurrentLevel(1);
}
Object convertedValue = convertIfNecessary(keyedPropertyName, null, value, valueType, typeDescriptor);
if (methodParam != null) {
methodParam.decreaseNestingLevel();
}
Object convertedKey = convertIfNecessary(keyedPropertyName, null, key, keyType, typeDescriptor.getMapKeyTypeDescriptor());
Object convertedValue = convertIfNecessary(keyedPropertyName, null, value, valueType, typeDescriptor.getMapValueTypeDescriptor());
try {
convertedCopy.put(convertedKey, convertedValue);
}