|
|
|
@ -266,198 +266,212 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@SuppressWarnings("unchecked") |
|
|
|
|
|
|
|
protected void setPropertyValue(PropertyTokenHolder tokens, PropertyValue pv) throws BeansException { |
|
|
|
protected void setPropertyValue(PropertyTokenHolder tokens, PropertyValue pv) throws BeansException { |
|
|
|
String propertyName = tokens.canonicalName; |
|
|
|
|
|
|
|
String actualName = tokens.actualName; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (tokens.keys != null) { |
|
|
|
if (tokens.keys != null) { |
|
|
|
// Apply indexes and map keys: fetch value for all keys but the last one.
|
|
|
|
processKeyedProperty(tokens, pv); |
|
|
|
PropertyTokenHolder getterTokens = new PropertyTokenHolder(); |
|
|
|
} |
|
|
|
getterTokens.canonicalName = tokens.canonicalName; |
|
|
|
else { |
|
|
|
getterTokens.actualName = tokens.actualName; |
|
|
|
processLocalProperty(tokens, pv); |
|
|
|
getterTokens.keys = new String[tokens.keys.length - 1]; |
|
|
|
} |
|
|
|
System.arraycopy(tokens.keys, 0, getterTokens.keys, 0, tokens.keys.length - 1); |
|
|
|
} |
|
|
|
Object propValue; |
|
|
|
|
|
|
|
|
|
|
|
@SuppressWarnings("unchecked") |
|
|
|
|
|
|
|
private void processKeyedProperty(PropertyTokenHolder tokens, PropertyValue pv) { |
|
|
|
|
|
|
|
Object propValue = getPropertyHoldingValue(tokens); |
|
|
|
|
|
|
|
String lastKey = tokens.keys[tokens.keys.length - 1]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (propValue.getClass().isArray()) { |
|
|
|
|
|
|
|
PropertyHandler ph = getLocalPropertyHandler(tokens.actualName); |
|
|
|
|
|
|
|
Class<?> requiredType = propValue.getClass().getComponentType(); |
|
|
|
|
|
|
|
int arrayIndex = Integer.parseInt(lastKey); |
|
|
|
|
|
|
|
Object oldValue = null; |
|
|
|
try { |
|
|
|
try { |
|
|
|
propValue = getPropertyValue(getterTokens); |
|
|
|
if (isExtractOldValueForEditor() && arrayIndex < Array.getLength(propValue)) { |
|
|
|
} |
|
|
|
oldValue = Array.get(propValue, arrayIndex); |
|
|
|
catch (NotReadablePropertyException ex) { |
|
|
|
|
|
|
|
throw new NotWritablePropertyException(getRootClass(), this.nestedPath + propertyName, |
|
|
|
|
|
|
|
"Cannot access indexed value in property referenced " + |
|
|
|
|
|
|
|
"in indexed property path '" + propertyName + "'", ex); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// Set value for last key.
|
|
|
|
|
|
|
|
String key = tokens.keys[tokens.keys.length - 1]; |
|
|
|
|
|
|
|
if (propValue == null) { |
|
|
|
|
|
|
|
// null map value case
|
|
|
|
|
|
|
|
if (isAutoGrowNestedPaths()) { |
|
|
|
|
|
|
|
// TODO: cleanup, this is pretty hacky
|
|
|
|
|
|
|
|
int lastKeyIndex = tokens.canonicalName.lastIndexOf('['); |
|
|
|
|
|
|
|
getterTokens.canonicalName = tokens.canonicalName.substring(0, lastKeyIndex); |
|
|
|
|
|
|
|
propValue = setDefaultValue(getterTokens); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
Object convertedValue = convertIfNecessary(tokens.canonicalName, oldValue, pv.getValue(), |
|
|
|
throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + propertyName, |
|
|
|
requiredType, ph.nested(tokens.keys.length)); |
|
|
|
"Cannot access indexed value in property referenced " + |
|
|
|
int length = Array.getLength(propValue); |
|
|
|
"in indexed property path '" + propertyName + "': returned null"); |
|
|
|
if (arrayIndex >= length && arrayIndex < this.autoGrowCollectionLimit) { |
|
|
|
|
|
|
|
Class<?> componentType = propValue.getClass().getComponentType(); |
|
|
|
|
|
|
|
Object newArray = Array.newInstance(componentType, arrayIndex + 1); |
|
|
|
|
|
|
|
System.arraycopy(propValue, 0, newArray, 0, length); |
|
|
|
|
|
|
|
setPropertyValue(tokens.actualName, newArray); |
|
|
|
|
|
|
|
propValue = getPropertyValue(tokens.actualName); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
Array.set(propValue, arrayIndex, convertedValue); |
|
|
|
} |
|
|
|
} |
|
|
|
if (propValue.getClass().isArray()) { |
|
|
|
catch (IndexOutOfBoundsException ex) { |
|
|
|
PropertyHandler ph = getLocalPropertyHandler(actualName); |
|
|
|
throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName, |
|
|
|
Class<?> requiredType = propValue.getClass().getComponentType(); |
|
|
|
"Invalid array index in property path '" + tokens.canonicalName + "'", ex); |
|
|
|
int arrayIndex = Integer.parseInt(key); |
|
|
|
} |
|
|
|
Object oldValue = null; |
|
|
|
} |
|
|
|
try { |
|
|
|
|
|
|
|
if (isExtractOldValueForEditor() && arrayIndex < Array.getLength(propValue)) { |
|
|
|
else if (propValue instanceof List) { |
|
|
|
oldValue = Array.get(propValue, arrayIndex); |
|
|
|
PropertyHandler ph = getPropertyHandler(tokens.actualName); |
|
|
|
|
|
|
|
Class<?> requiredType = ph.getCollectionType(tokens.keys.length); |
|
|
|
|
|
|
|
List<Object> list = (List<Object>) propValue; |
|
|
|
|
|
|
|
int index = Integer.parseInt(lastKey); |
|
|
|
|
|
|
|
Object oldValue = null; |
|
|
|
|
|
|
|
if (isExtractOldValueForEditor() && index < list.size()) { |
|
|
|
|
|
|
|
oldValue = list.get(index); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
Object convertedValue = convertIfNecessary(tokens.canonicalName, oldValue, pv.getValue(), |
|
|
|
|
|
|
|
requiredType, ph.nested(tokens.keys.length)); |
|
|
|
|
|
|
|
int size = list.size(); |
|
|
|
|
|
|
|
if (index >= size && index < this.autoGrowCollectionLimit) { |
|
|
|
|
|
|
|
for (int i = size; i < index; i++) { |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
list.add(null); |
|
|
|
} |
|
|
|
} |
|
|
|
Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(), |
|
|
|
catch (NullPointerException ex) { |
|
|
|
requiredType, ph.nested(tokens.keys.length)); |
|
|
|
throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName, |
|
|
|
int length = Array.getLength(propValue); |
|
|
|
"Cannot set element with index " + index + " in List of size " + |
|
|
|
if (arrayIndex >= length && arrayIndex < this.autoGrowCollectionLimit) { |
|
|
|
size + ", accessed using property path '" + tokens.canonicalName + |
|
|
|
Class<?> componentType = propValue.getClass().getComponentType(); |
|
|
|
"': List does not support filling up gaps with null elements"); |
|
|
|
Object newArray = Array.newInstance(componentType, arrayIndex + 1); |
|
|
|
|
|
|
|
System.arraycopy(propValue, 0, newArray, 0, length); |
|
|
|
|
|
|
|
setPropertyValue(actualName, newArray); |
|
|
|
|
|
|
|
propValue = getPropertyValue(actualName); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
Array.set(propValue, arrayIndex, convertedValue); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
catch (IndexOutOfBoundsException ex) { |
|
|
|
|
|
|
|
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName, |
|
|
|
|
|
|
|
"Invalid array index in property path '" + propertyName + "'", ex); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
list.add(convertedValue); |
|
|
|
} |
|
|
|
} |
|
|
|
else if (propValue instanceof List) { |
|
|
|
else { |
|
|
|
PropertyHandler ph = getPropertyHandler(actualName); |
|
|
|
try { |
|
|
|
Class<?> requiredType = ph.getCollectionType(tokens.keys.length); |
|
|
|
list.set(index, convertedValue); |
|
|
|
List<Object> list = (List<Object>) propValue; |
|
|
|
|
|
|
|
int index = Integer.parseInt(key); |
|
|
|
|
|
|
|
Object oldValue = null; |
|
|
|
|
|
|
|
if (isExtractOldValueForEditor() && index < list.size()) { |
|
|
|
|
|
|
|
oldValue = list.get(index); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(), |
|
|
|
|
|
|
|
requiredType, ph.nested(tokens.keys.length)); |
|
|
|
|
|
|
|
int size = list.size(); |
|
|
|
|
|
|
|
if (index >= size && index < this.autoGrowCollectionLimit) { |
|
|
|
|
|
|
|
for (int i = size; i < index; i++) { |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
list.add(null); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
catch (NullPointerException ex) { |
|
|
|
|
|
|
|
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName, |
|
|
|
|
|
|
|
"Cannot set element with index " + index + " in List of size " + |
|
|
|
|
|
|
|
size + ", accessed using property path '" + propertyName + |
|
|
|
|
|
|
|
"': List does not support filling up gaps with null elements"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
list.add(convertedValue); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
catch (IndexOutOfBoundsException ex) { |
|
|
|
try { |
|
|
|
throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName, |
|
|
|
list.set(index, convertedValue); |
|
|
|
"Invalid list index in property path '" + tokens.canonicalName + "'", ex); |
|
|
|
} |
|
|
|
|
|
|
|
catch (IndexOutOfBoundsException ex) { |
|
|
|
|
|
|
|
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName, |
|
|
|
|
|
|
|
"Invalid list index in property path '" + propertyName + "'", ex); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
else if (propValue instanceof Map) { |
|
|
|
} |
|
|
|
PropertyHandler ph = getLocalPropertyHandler(actualName); |
|
|
|
|
|
|
|
Class<?> mapKeyType = ph.getMapKeyType(tokens.keys.length); |
|
|
|
else if (propValue instanceof Map) { |
|
|
|
Class<?> mapValueType = ph.getMapValueType(tokens.keys.length); |
|
|
|
PropertyHandler ph = getLocalPropertyHandler(tokens.actualName); |
|
|
|
Map<Object, Object> map = (Map<Object, Object>) propValue; |
|
|
|
Class<?> mapKeyType = ph.getMapKeyType(tokens.keys.length); |
|
|
|
// IMPORTANT: Do not pass full property name in here - property editors
|
|
|
|
Class<?> mapValueType = ph.getMapValueType(tokens.keys.length); |
|
|
|
// must not kick in for map keys but rather only for map values.
|
|
|
|
Map<Object, Object> map = (Map<Object, Object>) propValue; |
|
|
|
TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(mapKeyType); |
|
|
|
// IMPORTANT: Do not pass full property name in here - property editors
|
|
|
|
Object convertedMapKey = convertIfNecessary(null, null, key, mapKeyType, typeDescriptor); |
|
|
|
// must not kick in for map keys but rather only for map values.
|
|
|
|
Object oldValue = null; |
|
|
|
TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(mapKeyType); |
|
|
|
if (isExtractOldValueForEditor()) { |
|
|
|
Object convertedMapKey = convertIfNecessary(null, null, lastKey, mapKeyType, typeDescriptor); |
|
|
|
oldValue = map.get(convertedMapKey); |
|
|
|
Object oldValue = null; |
|
|
|
|
|
|
|
if (isExtractOldValueForEditor()) { |
|
|
|
|
|
|
|
oldValue = map.get(convertedMapKey); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// Pass full property name and old value in here, since we want full
|
|
|
|
|
|
|
|
// conversion ability for map values.
|
|
|
|
|
|
|
|
Object convertedMapValue = convertIfNecessary(tokens.canonicalName, oldValue, pv.getValue(), |
|
|
|
|
|
|
|
mapValueType, ph.nested(tokens.keys.length)); |
|
|
|
|
|
|
|
map.put(convertedMapKey, convertedMapValue); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
else { |
|
|
|
|
|
|
|
throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName, |
|
|
|
|
|
|
|
"Property referenced in indexed property path '" + tokens.canonicalName + |
|
|
|
|
|
|
|
"' is neither an array nor a List nor a Map; returned value was [" + propValue + "]"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private Object getPropertyHoldingValue(PropertyTokenHolder tokens) { |
|
|
|
|
|
|
|
// Apply indexes and map keys: fetch value for all keys but the last one.
|
|
|
|
|
|
|
|
PropertyTokenHolder getterTokens = new PropertyTokenHolder(); |
|
|
|
|
|
|
|
getterTokens.canonicalName = tokens.canonicalName; |
|
|
|
|
|
|
|
getterTokens.actualName = tokens.actualName; |
|
|
|
|
|
|
|
getterTokens.keys = new String[tokens.keys.length - 1]; |
|
|
|
|
|
|
|
System.arraycopy(tokens.keys, 0, getterTokens.keys, 0, tokens.keys.length - 1); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Object propValue; |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
propValue = getPropertyValue(getterTokens); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
catch (NotReadablePropertyException ex) { |
|
|
|
|
|
|
|
throw new NotWritablePropertyException(getRootClass(), this.nestedPath + tokens.canonicalName, |
|
|
|
|
|
|
|
"Cannot access indexed value in property referenced " + |
|
|
|
|
|
|
|
"in indexed property path '" + tokens.canonicalName + "'", ex); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (propValue == null) { |
|
|
|
|
|
|
|
// null map value case
|
|
|
|
|
|
|
|
if (isAutoGrowNestedPaths()) { |
|
|
|
|
|
|
|
int lastKeyIndex = tokens.canonicalName.lastIndexOf('['); |
|
|
|
|
|
|
|
getterTokens.canonicalName = tokens.canonicalName.substring(0, lastKeyIndex); |
|
|
|
|
|
|
|
propValue = setDefaultValue(getterTokens); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
|
|
|
|
throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + tokens.canonicalName, |
|
|
|
|
|
|
|
"Cannot access indexed value in property referenced " + |
|
|
|
|
|
|
|
"in indexed property path '" + tokens.canonicalName + "': returned null"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return propValue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void processLocalProperty(PropertyTokenHolder tokens, PropertyValue pv) { |
|
|
|
|
|
|
|
PropertyHandler ph = getLocalPropertyHandler(tokens.actualName); |
|
|
|
|
|
|
|
if (ph == null || !ph.isWritable()) { |
|
|
|
|
|
|
|
if (pv.isOptional()) { |
|
|
|
|
|
|
|
if (logger.isDebugEnabled()) { |
|
|
|
|
|
|
|
logger.debug("Ignoring optional value for property '" + tokens.actualName + |
|
|
|
|
|
|
|
"' - property not found on bean class [" + getRootClass().getName() + "]"); |
|
|
|
} |
|
|
|
} |
|
|
|
// Pass full property name and old value in here, since we want full
|
|
|
|
return; |
|
|
|
// conversion ability for map values.
|
|
|
|
|
|
|
|
Object convertedMapValue = convertIfNecessary(propertyName, oldValue, pv.getValue(), |
|
|
|
|
|
|
|
mapValueType, ph.nested(tokens.keys.length)); |
|
|
|
|
|
|
|
map.put(convertedMapKey, convertedMapValue); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
else { |
|
|
|
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName, |
|
|
|
throw createNotWritablePropertyException(tokens.canonicalName); |
|
|
|
"Property referenced in indexed property path '" + propertyName + |
|
|
|
|
|
|
|
"' is neither an array nor a List nor a Map; returned value was [" + propValue + "]"); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
else { |
|
|
|
Object oldValue = null; |
|
|
|
PropertyHandler ph = getLocalPropertyHandler(actualName); |
|
|
|
try { |
|
|
|
if (ph == null || !ph.isWritable()) { |
|
|
|
Object originalValue = pv.getValue(); |
|
|
|
if (pv.isOptional()) { |
|
|
|
Object valueToApply = originalValue; |
|
|
|
if (logger.isDebugEnabled()) { |
|
|
|
if (!Boolean.FALSE.equals(pv.conversionNecessary)) { |
|
|
|
logger.debug("Ignoring optional value for property '" + actualName + |
|
|
|
if (pv.isConverted()) { |
|
|
|
"' - property not found on bean class [" + getRootClass().getName() + "]"); |
|
|
|
valueToApply = pv.getConvertedValue(); |
|
|
|
} |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
else { |
|
|
|
throw createNotWritablePropertyException(propertyName); |
|
|
|
if (isExtractOldValueForEditor() && ph.isReadable()) { |
|
|
|
} |
|
|
|
try { |
|
|
|
} |
|
|
|
oldValue = ph.getValue(); |
|
|
|
Object oldValue = null; |
|
|
|
} |
|
|
|
try { |
|
|
|
catch (Exception ex) { |
|
|
|
Object originalValue = pv.getValue(); |
|
|
|
if (ex instanceof PrivilegedActionException) { |
|
|
|
Object valueToApply = originalValue; |
|
|
|
ex = ((PrivilegedActionException) ex).getException(); |
|
|
|
if (!Boolean.FALSE.equals(pv.conversionNecessary)) { |
|
|
|
|
|
|
|
if (pv.isConverted()) { |
|
|
|
|
|
|
|
valueToApply = pv.getConvertedValue(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
|
|
|
|
if (isExtractOldValueForEditor() && ph.isReadable()) { |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
oldValue = ph.getValue(); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
catch (Exception ex) { |
|
|
|
if (logger.isDebugEnabled()) { |
|
|
|
if (ex instanceof PrivilegedActionException) { |
|
|
|
logger.debug("Could not read previous value of property '" + |
|
|
|
ex = ((PrivilegedActionException) ex).getException(); |
|
|
|
this.nestedPath + tokens.canonicalName + "'", ex); |
|
|
|
} |
|
|
|
|
|
|
|
if (logger.isDebugEnabled()) { |
|
|
|
|
|
|
|
logger.debug("Could not read previous value of property '" + |
|
|
|
|
|
|
|
this.nestedPath + propertyName + "'", ex); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
valueToApply = convertForProperty( |
|
|
|
|
|
|
|
propertyName, oldValue, originalValue, ph.toTypeDescriptor()); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue); |
|
|
|
valueToApply = convertForProperty( |
|
|
|
|
|
|
|
tokens.canonicalName, oldValue, originalValue, ph.toTypeDescriptor()); |
|
|
|
} |
|
|
|
} |
|
|
|
ph.setValue(this.wrappedObject, valueToApply); |
|
|
|
pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue); |
|
|
|
} |
|
|
|
} |
|
|
|
catch (TypeMismatchException ex) { |
|
|
|
ph.setValue(this.wrappedObject, valueToApply); |
|
|
|
throw ex; |
|
|
|
} |
|
|
|
|
|
|
|
catch (TypeMismatchException ex) { |
|
|
|
|
|
|
|
throw ex; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
catch (InvocationTargetException ex) { |
|
|
|
|
|
|
|
PropertyChangeEvent propertyChangeEvent = new PropertyChangeEvent( |
|
|
|
|
|
|
|
this.rootObject, this.nestedPath + tokens.canonicalName, oldValue, pv.getValue()); |
|
|
|
|
|
|
|
if (ex.getTargetException() instanceof ClassCastException) { |
|
|
|
|
|
|
|
throw new TypeMismatchException(propertyChangeEvent, ph.getPropertyType(), ex.getTargetException()); |
|
|
|
} |
|
|
|
} |
|
|
|
catch (InvocationTargetException ex) { |
|
|
|
else { |
|
|
|
PropertyChangeEvent propertyChangeEvent = |
|
|
|
Throwable cause = ex.getTargetException(); |
|
|
|
new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, pv.getValue()); |
|
|
|
if (cause instanceof UndeclaredThrowableException) { |
|
|
|
if (ex.getTargetException() instanceof ClassCastException) { |
|
|
|
// May happen e.g. with Groovy-generated methods
|
|
|
|
throw new TypeMismatchException(propertyChangeEvent, ph.getPropertyType(), ex.getTargetException()); |
|
|
|
cause = cause.getCause(); |
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
|
|
|
|
Throwable cause = ex.getTargetException(); |
|
|
|
|
|
|
|
if (cause instanceof UndeclaredThrowableException) { |
|
|
|
|
|
|
|
// May happen e.g. with Groovy-generated methods
|
|
|
|
|
|
|
|
cause = cause.getCause(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
throw new MethodInvocationException(propertyChangeEvent, cause); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
throw new MethodInvocationException(propertyChangeEvent, cause); |
|
|
|
} |
|
|
|
} |
|
|
|
catch (Exception ex) { |
|
|
|
} |
|
|
|
PropertyChangeEvent pce = |
|
|
|
catch (Exception ex) { |
|
|
|
new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, pv.getValue()); |
|
|
|
PropertyChangeEvent pce = new PropertyChangeEvent( |
|
|
|
throw new MethodInvocationException(pce, ex); |
|
|
|
this.rootObject, this.nestedPath + tokens.canonicalName, oldValue, pv.getValue()); |
|
|
|
} |
|
|
|
throw new MethodInvocationException(pce, ex); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -958,9 +972,6 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Handle a given property. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
protected abstract static class PropertyHandler { |
|
|
|
protected abstract static class PropertyHandler { |
|
|
|
|
|
|
|
|
|
|
|
private final Class<?> propertyType; |
|
|
|
private final Class<?> propertyType; |
|
|
|
|