|
|
|
@ -190,7 +190,7 @@ public class PropertyOrFieldReference extends SpelNodeImpl { |
|
|
|
if (accessorToUse != null) { |
|
|
|
if (accessorToUse != null) { |
|
|
|
if (evalContext.getPropertyAccessors().contains(accessorToUse)) { |
|
|
|
if (evalContext.getPropertyAccessors().contains(accessorToUse)) { |
|
|
|
try { |
|
|
|
try { |
|
|
|
return accessorToUse.read(evalContext, contextObject.getValue(), name); |
|
|
|
return accessorToUse.read(evalContext, targetObject, name); |
|
|
|
} |
|
|
|
} |
|
|
|
catch (Exception ex) { |
|
|
|
catch (Exception ex) { |
|
|
|
// This is OK - it may have gone stale due to a class change,
|
|
|
|
// This is OK - it may have gone stale due to a class change,
|
|
|
|
@ -201,19 +201,19 @@ public class PropertyOrFieldReference extends SpelNodeImpl { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
List<PropertyAccessor> accessorsToTry = |
|
|
|
List<PropertyAccessor> accessorsToTry = |
|
|
|
getPropertyAccessorsToTry(contextObject.getValue(), evalContext.getPropertyAccessors()); |
|
|
|
getPropertyAccessorsToTry(targetObject, evalContext.getPropertyAccessors()); |
|
|
|
// Go through the accessors that may be able to resolve it. If they are a cacheable accessor then
|
|
|
|
// Go through the accessors that may be able to resolve it. If they are a cacheable accessor then
|
|
|
|
// get the accessor and use it. If they are not cacheable but report they can read the property
|
|
|
|
// get the accessor and use it. If they are not cacheable but report they can read the property
|
|
|
|
// then ask them to read it
|
|
|
|
// then ask them to read it
|
|
|
|
try { |
|
|
|
try { |
|
|
|
for (PropertyAccessor accessor : accessorsToTry) { |
|
|
|
for (PropertyAccessor accessor : accessorsToTry) { |
|
|
|
if (accessor.canRead(evalContext, contextObject.getValue(), name)) { |
|
|
|
if (accessor.canRead(evalContext, targetObject, name)) { |
|
|
|
if (accessor instanceof ReflectivePropertyAccessor reflectivePropertyAccessor) { |
|
|
|
if (accessor instanceof ReflectivePropertyAccessor reflectivePropertyAccessor) { |
|
|
|
accessor = reflectivePropertyAccessor.createOptimalAccessor( |
|
|
|
accessor = reflectivePropertyAccessor.createOptimalAccessor( |
|
|
|
evalContext, contextObject.getValue(), name); |
|
|
|
evalContext, targetObject, name); |
|
|
|
} |
|
|
|
} |
|
|
|
this.cachedReadAccessor = accessor; |
|
|
|
this.cachedReadAccessor = accessor; |
|
|
|
return accessor.read(evalContext, contextObject.getValue(), name); |
|
|
|
return accessor.read(evalContext, targetObject, name); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -234,18 +234,20 @@ public class PropertyOrFieldReference extends SpelNodeImpl { |
|
|
|
TypedValue contextObject, EvaluationContext evalContext, String name, @Nullable Object newValue) |
|
|
|
TypedValue contextObject, EvaluationContext evalContext, String name, @Nullable Object newValue) |
|
|
|
throws EvaluationException { |
|
|
|
throws EvaluationException { |
|
|
|
|
|
|
|
|
|
|
|
if (contextObject.getValue() == null && isNullSafe()) { |
|
|
|
Object targetObject = contextObject.getValue(); |
|
|
|
return; |
|
|
|
if (targetObject == null) { |
|
|
|
} |
|
|
|
if (isNullSafe()) { |
|
|
|
if (contextObject.getValue() == null) { |
|
|
|
return; |
|
|
|
throw new SpelEvaluationException(getStartPosition(), SpelMessage.PROPERTY_OR_FIELD_NOT_WRITABLE_ON_NULL, name); |
|
|
|
} |
|
|
|
|
|
|
|
throw new SpelEvaluationException( |
|
|
|
|
|
|
|
getStartPosition(), SpelMessage.PROPERTY_OR_FIELD_NOT_WRITABLE_ON_NULL, name); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
PropertyAccessor accessorToUse = this.cachedWriteAccessor; |
|
|
|
PropertyAccessor accessorToUse = this.cachedWriteAccessor; |
|
|
|
if (accessorToUse != null) { |
|
|
|
if (accessorToUse != null) { |
|
|
|
if (evalContext.getPropertyAccessors().contains(accessorToUse)) { |
|
|
|
if (evalContext.getPropertyAccessors().contains(accessorToUse)) { |
|
|
|
try { |
|
|
|
try { |
|
|
|
accessorToUse.write(evalContext, contextObject.getValue(), name, newValue); |
|
|
|
accessorToUse.write(evalContext, targetObject, name, newValue); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
catch (Exception ex) { |
|
|
|
catch (Exception ex) { |
|
|
|
@ -257,12 +259,12 @@ public class PropertyOrFieldReference extends SpelNodeImpl { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
List<PropertyAccessor> accessorsToTry = |
|
|
|
List<PropertyAccessor> accessorsToTry = |
|
|
|
getPropertyAccessorsToTry(contextObject.getValue(), evalContext.getPropertyAccessors()); |
|
|
|
getPropertyAccessorsToTry(targetObject, evalContext.getPropertyAccessors()); |
|
|
|
try { |
|
|
|
try { |
|
|
|
for (PropertyAccessor accessor : accessorsToTry) { |
|
|
|
for (PropertyAccessor accessor : accessorsToTry) { |
|
|
|
if (accessor.canWrite(evalContext, contextObject.getValue(), name)) { |
|
|
|
if (accessor.canWrite(evalContext, targetObject, name)) { |
|
|
|
this.cachedWriteAccessor = accessor; |
|
|
|
this.cachedWriteAccessor = accessor; |
|
|
|
accessor.write(evalContext, contextObject.getValue(), name, newValue); |
|
|
|
accessor.write(evalContext, targetObject, name, newValue); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -273,19 +275,19 @@ public class PropertyOrFieldReference extends SpelNodeImpl { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
throw new SpelEvaluationException(getStartPosition(), SpelMessage.PROPERTY_OR_FIELD_NOT_WRITABLE, name, |
|
|
|
throw new SpelEvaluationException(getStartPosition(), SpelMessage.PROPERTY_OR_FIELD_NOT_WRITABLE, name, |
|
|
|
FormatHelper.formatClassNameForMessage(getObjectClass(contextObject.getValue()))); |
|
|
|
FormatHelper.formatClassNameForMessage(getObjectClass(targetObject))); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public boolean isWritableProperty(String name, TypedValue contextObject, EvaluationContext evalContext) |
|
|
|
public boolean isWritableProperty(String name, TypedValue contextObject, EvaluationContext evalContext) |
|
|
|
throws EvaluationException { |
|
|
|
throws EvaluationException { |
|
|
|
|
|
|
|
|
|
|
|
Object value = contextObject.getValue(); |
|
|
|
Object targetObject = contextObject.getValue(); |
|
|
|
if (value != null) { |
|
|
|
if (targetObject != null) { |
|
|
|
List<PropertyAccessor> accessorsToTry = |
|
|
|
List<PropertyAccessor> accessorsToTry = |
|
|
|
getPropertyAccessorsToTry(contextObject.getValue(), evalContext.getPropertyAccessors()); |
|
|
|
getPropertyAccessorsToTry(targetObject, evalContext.getPropertyAccessors()); |
|
|
|
for (PropertyAccessor accessor : accessorsToTry) { |
|
|
|
for (PropertyAccessor accessor : accessorsToTry) { |
|
|
|
try { |
|
|
|
try { |
|
|
|
if (accessor.canWrite(evalContext, value, name)) { |
|
|
|
if (accessor.canWrite(evalContext, targetObject, name)) { |
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -301,13 +303,14 @@ public class PropertyOrFieldReference extends SpelNodeImpl { |
|
|
|
* Determine the set of property accessors that should be used to try to |
|
|
|
* Determine the set of property accessors that should be used to try to |
|
|
|
* access a property on the specified context object. |
|
|
|
* access a property on the specified context object. |
|
|
|
* <p>Delegates to {@link AstUtils#getPropertyAccessorsToTry(Class, List)}. |
|
|
|
* <p>Delegates to {@link AstUtils#getPropertyAccessorsToTry(Class, List)}. |
|
|
|
* @param contextObject the object upon which property access is being attempted |
|
|
|
* @param targetObject the object upon which property access is being attempted |
|
|
|
* @return a list of accessors that should be tried in order to access the property |
|
|
|
* @return a list of accessors that should be tried in order to access the |
|
|
|
|
|
|
|
* property, or an empty list if no suitable accessor could be found |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
private List<PropertyAccessor> getPropertyAccessorsToTry( |
|
|
|
private List<PropertyAccessor> getPropertyAccessorsToTry( |
|
|
|
@Nullable Object contextObject, List<PropertyAccessor> propertyAccessors) { |
|
|
|
@Nullable Object targetObject, List<PropertyAccessor> propertyAccessors) { |
|
|
|
|
|
|
|
|
|
|
|
Class<?> targetType = (contextObject != null ? contextObject.getClass() : null); |
|
|
|
Class<?> targetType = (targetObject != null ? targetObject.getClass() : null); |
|
|
|
return AstUtils.getPropertyAccessorsToTry(targetType, propertyAccessors); |
|
|
|
return AstUtils.getPropertyAccessorsToTry(targetType, propertyAccessors); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|