📄 beanwrapperimpl.java
字号:
doTypeConversionIfNecessary(propertyName, propertyName, oldValue, newValue, null);
map.put(key, convertedValue);
}
else {
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
"Property referenced in indexed property path '" + propertyName +
"' is neither an array nor a List nor a Map; returned value was [" + newValue + "]");
}
}
else {
PropertyDescriptor pd = getPropertyDescriptorInternal(propertyName);
if (pd == null || pd.getWriteMethod() == null) {
throw new NotWritablePropertyException(getRootClass(), this.nestedPath + propertyName);
}
Method readMethod = pd.getReadMethod();
Method writeMethod = pd.getWriteMethod();
Object oldValue = null;
if (this.extractOldValueForEditor && readMethod != null) {
if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
readMethod.setAccessible(true);
}
try {
oldValue = readMethod.invoke(this.object, new Object[0]);
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug("Could not read previous value of property '" + this.nestedPath + propertyName + "'", ex);
}
}
}
try {
Object convertedValue =
doTypeConversionIfNecessary(propertyName, propertyName, oldValue, newValue, pd.getPropertyType());
if (pd.getPropertyType().isPrimitive() && (convertedValue == null || "".equals(convertedValue))) {
throw new IllegalArgumentException("Invalid value [" + newValue + "] for property '" +
pd.getName() + "' of primitive type [" + pd.getPropertyType() + "]");
}
if (logger.isDebugEnabled()) {
logger.debug("About to invoke write method [" + writeMethod + "] on object of class [" +
this.object.getClass().getName() + "]");
}
if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
writeMethod.setAccessible(true);
}
writeMethod.invoke(this.object, new Object[] {convertedValue});
if (logger.isDebugEnabled()) {
logger.debug("Invoked write method [" + writeMethod + "] with value of type [" +
pd.getPropertyType().getName() + "]");
}
}
catch (InvocationTargetException ex) {
PropertyChangeEvent propertyChangeEvent =
new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, newValue);
if (ex.getTargetException() instanceof ClassCastException) {
throw new TypeMismatchException(propertyChangeEvent, pd.getPropertyType(), ex.getTargetException());
}
else {
throw new MethodInvocationException(propertyChangeEvent, ex.getTargetException());
}
}
catch (IllegalArgumentException ex) {
PropertyChangeEvent pce =
new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, newValue);
throw new TypeMismatchException(pce, pd.getPropertyType(), ex);
}
catch (IllegalAccessException ex) {
PropertyChangeEvent pce =
new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, newValue);
throw new MethodInvocationException(pce, ex);
}
}
}
public void setPropertyValue(PropertyValue pv) throws BeansException {
setPropertyValue(pv.getName(), pv.getValue());
}
/**
* Bulk update from a Map.
* Bulk updates from PropertyValues are more powerful: this method is
* provided for convenience.
* @param map map containing properties to set, as name-value pairs.
* The map may include nested properties.
* @throws BeansException if there's a fatal, low-level exception
*/
public void setPropertyValues(Map map) throws BeansException {
setPropertyValues(new MutablePropertyValues(map));
}
public void setPropertyValues(PropertyValues pvs) throws BeansException {
setPropertyValues(pvs, false);
}
public void setPropertyValues(PropertyValues propertyValues, boolean ignoreUnknown) throws BeansException {
List propertyAccessExceptions = new ArrayList();
PropertyValue[] pvs = propertyValues.getPropertyValues();
for (int i = 0; i < pvs.length; i++) {
try {
// This method may throw any BeansException, which won't be caught
// here, if there is a critical failure such as no matching field.
// We can attempt to deal only with less serious exceptions.
setPropertyValue(pvs[i]);
}
catch (NotWritablePropertyException ex) {
if (!ignoreUnknown) {
throw ex;
}
// Otherwise, just ignore it and continue...
}
catch (PropertyAccessException ex) {
propertyAccessExceptions.add(ex);
}
}
// If we encountered individual exceptions, throw the composite exception.
if (!propertyAccessExceptions.isEmpty()) {
Object[] paeArray =
propertyAccessExceptions.toArray(new PropertyAccessException[propertyAccessExceptions.size()]);
throw new PropertyAccessExceptionsException(this, (PropertyAccessException[]) paeArray);
}
}
private PropertyChangeEvent createPropertyChangeEvent(String propertyName, Object oldValue, Object newValue) {
return new PropertyChangeEvent((this.rootObject != null ? this.rootObject : "constructor"),
(propertyName != null ? this.nestedPath + propertyName : null),
oldValue, newValue);
}
/**
* Convert the value to the required type (if necessary from a String).
* <p>Conversions from String to any type use the <code>setAsText</code> method
* of the PropertyEditor class. Note that a PropertyEditor must be registered
* for the given class for this to work; this is a standard JavaBeans API.
* A number of PropertyEditors are automatically registered by BeanWrapperImpl.
* @param newValue proposed change value
* @param requiredType the type we must convert to
* @return the new value, possibly the result of type conversion
* @throws TypeMismatchException if type conversion failed
* @see java.beans.PropertyEditor#setAsText(String)
* @see java.beans.PropertyEditor#getValue()
*/
public Object doTypeConversionIfNecessary(Object newValue, Class requiredType) throws TypeMismatchException {
return doTypeConversionIfNecessary(null, null, null, newValue, requiredType);
}
/**
* Convert the value to the required type (if necessary from a String),
* for the specified property.
* @param propertyName name of the property
* @param oldValue previous value, if available (may be <code>null</code>)
* @param newValue proposed change value
* @param requiredType the type we must convert to
* (or <code>null</code> if not known, for example in case of a collection element)
* @return the new value, possibly the result of type conversion
* @throws TypeMismatchException if type conversion failed
*/
protected Object doTypeConversionIfNecessary(String propertyName, String fullPropertyName,
Object oldValue, Object newValue, Class requiredType) throws TypeMismatchException {
Object convertedValue = newValue;
// Custom editor for this type?
PropertyEditor pe = findCustomEditor(requiredType, fullPropertyName);
// Value not of required type?
if (pe != null ||
(requiredType != null &&
(requiredType.isArray() || !requiredType.isInstance(convertedValue)))) {
if (requiredType != null) {
if (pe == null) {
// No custom editor -> check BeanWrapperImpl's default editors.
pe = (PropertyEditor) getDefaultEditor(requiredType);
if (pe == null) {
// No BeanWrapper default editor -> check standard JavaBean editors.
pe = PropertyEditorManager.findEditor(requiredType);
}
}
}
if (pe != null && !(convertedValue instanceof String)) {
// Not a String -> use PropertyEditor's setValue.
// With standard PropertyEditors, this will return the very same object;
// we just want to allow special PropertyEditors to override setValue
// for type conversion from non-String values to the required type.
try {
pe.setValue(convertedValue);
Object newConvertedValue = pe.getValue();
if (newConvertedValue != convertedValue) {
convertedValue = newConvertedValue;
// Reset PropertyEditor: It already did a proper conversion.
// Don't use it again for a setAsText call.
pe = null;
}
}
catch (IllegalArgumentException ex) {
throw new TypeMismatchException(
createPropertyChangeEvent(fullPropertyName, oldValue, newValue), requiredType, ex);
}
}
if (requiredType != null && !requiredType.isArray() && convertedValue instanceof String[]) {
// Convert String array to a comma-separated String.
// Only applies if no PropertyEditor converted the String array before.
// The CSV String will be passed into a PropertyEditor's setAsText method, if any.
if (logger.isDebugEnabled()) {
logger.debug("Converting String array to comma-delimited String [" + convertedValue + "]");
}
convertedValue = StringUtils.arrayToCommaDelimitedString((String[]) convertedValue);
}
if (pe != null && convertedValue instanceof String) {
// Use PropertyEditor's setAsText in case of a String value.
if (logger.isDebugEnabled()) {
logger.debug("Converting String to [" + requiredType + "] using property editor [" + pe + "]");
}
try {
pe.setValue(oldValue);
pe.setAsText((String) convertedValue);
convertedValue = pe.getValue();
}
catch (IllegalArgumentException ex) {
throw new TypeMismatchException(
createPropertyChangeEvent(fullPropertyName, oldValue, newValue), requiredType, ex);
}
}
if (requiredType != null) {
// Array required -> apply appropriate conversion of elements.
if (requiredType.isArray()) {
Class componentType = requiredType.getComponentType();
if (convertedValue instanceof Collection) {
// Convert Collection elements to array elements.
Collection coll = (Collection) convertedValue;
Object result = Array.newInstance(componentType, coll.size());
int i = 0;
for (Iterator it = coll.iterator(); it.hasNext(); i++) {
Object value = doTypeConversionIfNecessary(
propertyName, propertyName + PROPERTY_KEY_PREFIX + i + PROPERTY_KEY_SUFFIX,
null, it.next(), componentType);
Array.set(result, i, value);
}
return result;
}
else if (convertedValue != null && convertedValue.getClass().isArray()) {
// Convert Collection elements to array elements.
int arrayLength = Array.getLength(convertedValue);
Object result = Array.newInstance(componentType, arrayLength);
for (int i = 0; i < arrayLength; i++) {
Object value = doTypeConversionIfNecessary(
propertyName, propertyName + PROPERTY_KEY_PREFIX + i + PROPERTY_KEY_SUFFIX,
null, Array.get(convertedValue, i), componentType);
Array.set(result, i, value);
}
return result;
}
else {
// A plain value: convert it to an array with a single component.
Object result = Array.newInstance(componentType, 1);
Object value = doTypeConversionIfNecessary(
propertyName, propertyName + PROPERTY_KEY_PREFIX + 0 + PROPERTY_KEY_SUFFIX,
null, convertedValue, componentType);
Array.set(result, 0, value);
return result;
}
}
// If the resulting value definitely doesn't match the required type,
// try field lookup as fallback. If no matching field found,
// throw explicit TypeMismatchException with full context information.
if (convertedValue != null && !requiredType.isPrimitive() &&
!requiredType.isInstance(convertedValue)) {
// In case of String value, try to find matching field (for JDK 1.5
// enum or custom enum with values defined as static fields).
if (convertedValue instanceof String) {
try {
Field enumField = requiredType.getField((String) convertedValue);
return enumField.get(null);
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug("Field [" + convertedValue + "] isn't an enum value", ex);
}
}
}
// Definitely doesn't match: throw TypeMismatchException.
throw new TypeMismatchException(
createPropertyChangeEvent(fullPropertyName, oldValue, newValue), requiredType);
}
}
}
return convertedValue;
}
public String toString() {
StringBuffer sb = new StringBuffer("BeanWrapperImpl: wrapping class [");
sb.append(getWrappedClass().getName()).append("]");
return sb.toString();
}
//---------------------------------------------------------------------
// Inner class for internal use
//---------------------------------------------------------------------
private static class PropertyTokenHolder {
private String canonicalName;
private String actualName;
private String[] keys;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -