|
|
|
@ -25,25 +25,39 @@ import org.springframework.expression.PropertyWriterExecutor; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Simple PropertyResolver that uses reflection to access properties for reading and writing. A property can be accessed |
|
|
|
* Simple PropertyResolver that uses reflection to access properties for reading and writing. A property can be accessed |
|
|
|
* if it is accessible as a field on the object or through a getter (if being read) or a setter (if being written). |
|
|
|
* if it is accessible as a field on the object or through a getter (if being read) or a setter (if being written). This |
|
|
|
|
|
|
|
* implementation currently follows the Resolver/Executor model (it extends CacheablePropertyAccessor) - the code that |
|
|
|
|
|
|
|
* would be used if it were a simple property accessor is shown at the end. |
|
|
|
* |
|
|
|
* |
|
|
|
* @author Andy Clement |
|
|
|
* @author Andy Clement |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public class ReflectionPropertyResolver extends CacheablePropertyAccessor { |
|
|
|
public class ReflectionPropertyResolver extends CacheablePropertyAccessor { |
|
|
|
|
|
|
|
|
|
|
|
public static boolean useResolverExecutorModel = true; |
|
|
|
/** |
|
|
|
|
|
|
|
* @return null which means this is a general purpose accessor |
|
|
|
public boolean supportsResolverExecutorModel() { |
|
|
|
*/ |
|
|
|
return useResolverExecutorModel; |
|
|
|
public Class<?>[] getSpecificTargetClasses() { |
|
|
|
|
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public PropertyReaderExecutor getReaderAccessor(EvaluationContext relatedContext, Object target, Object name) { |
|
|
|
/** |
|
|
|
if (target==null) { |
|
|
|
* Use reflection to discover if a named property is accessible on an target type and if it is return an executor |
|
|
|
|
|
|
|
* object that can be called repeatedly to retrieve that property. A property is accessible either as a field or |
|
|
|
|
|
|
|
* through a getter. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param context the context in which the access is being attempted |
|
|
|
|
|
|
|
* @param target the target object on which the property is being accessed |
|
|
|
|
|
|
|
* @param name the name of the property |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
public PropertyReaderExecutor getReaderAccessor(EvaluationContext context, Object target, Object name) { |
|
|
|
|
|
|
|
if (target == null) { |
|
|
|
return null; |
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
Class<?> relevantClass = (target instanceof Class ? (Class<?>) target : target.getClass()); |
|
|
|
Class<?> relevantClass = (target instanceof Class ? (Class<?>) target : target.getClass()); |
|
|
|
if (!(name instanceof String)) { |
|
|
|
if (!(name instanceof String)) { |
|
|
|
return null; // TODO should raise an exception when the property-name is not a String?
|
|
|
|
// A property not found exception will occur if the reflection finder was supposed to find it
|
|
|
|
|
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
String propertyName = (String) name; |
|
|
|
String propertyName = (String) name; |
|
|
|
if (relevantClass.isArray() && propertyName.equals("length")) { |
|
|
|
if (relevantClass.isArray() && propertyName.equals("length")) { |
|
|
|
@ -60,12 +74,23 @@ public class ReflectionPropertyResolver extends CacheablePropertyAccessor { |
|
|
|
return null; |
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Use reflection to discover if a named property is accessible on an target type and if it is return an executor |
|
|
|
|
|
|
|
* object that can be called repeatedly to set that property. A property is writable either as a field or through a |
|
|
|
|
|
|
|
* setter. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param context the context in which the set is being attempted |
|
|
|
|
|
|
|
* @param target the target object on which the property is being set |
|
|
|
|
|
|
|
* @param name the name of the property |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
@Override |
|
|
|
public PropertyWriterExecutor getWriterAccessor(EvaluationContext context, Object target, Object name) { |
|
|
|
public PropertyWriterExecutor getWriterAccessor(EvaluationContext context, Object target, Object name) { |
|
|
|
if (target==null) { |
|
|
|
if (target == null) { |
|
|
|
return null; |
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
Class<?> relevantClass = (target instanceof Class ? (Class<?>) target : target.getClass()); |
|
|
|
Class<?> relevantClass = (target instanceof Class ? (Class<?>) target : target.getClass()); |
|
|
|
if (!(name instanceof String)) { |
|
|
|
if (!(name instanceof String)) { |
|
|
|
|
|
|
|
// A property not found exception will occur if the reflection finder was supposed to find it
|
|
|
|
return null; |
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
Field field = ReflectionUtils.findField((String) name, relevantClass); |
|
|
|
Field field = ReflectionUtils.findField((String) name, relevantClass); |
|
|
|
@ -79,124 +104,120 @@ public class ReflectionPropertyResolver extends CacheablePropertyAccessor { |
|
|
|
return null; |
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
// /**
|
|
|
|
* Return true if the resolver is able to read the specified property from the specified target. |
|
|
|
// * Return true if the resolver is able to read the specified property from the specified target.
|
|
|
|
*/ |
|
|
|
// */
|
|
|
|
// public boolean canRead(EvaluationContext relatedContext, Object target, Object name) throws AccessException {
|
|
|
|
// public boolean canRead(EvaluationContext relatedContext, Object target, Object name) throws AccessException {
|
|
|
|
// if (target==null) {
|
|
|
|
// if (target==null) {
|
|
|
|
// return false;
|
|
|
|
// return false;
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// Class<?> relevantClass = (target instanceof Class ? (Class<?>) target : target.getClass());
|
|
|
|
// Class<?> relevantClass = (target instanceof Class ? (Class<?>) target : target.getClass());
|
|
|
|
// if (!(name instanceof String)) {
|
|
|
|
// if (!(name instanceof String)) {
|
|
|
|
// return false; // TODO should raise an exception when the property-name is not a String?
|
|
|
|
// return false;
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// String propertyName = (String) name;
|
|
|
|
// String propertyName = (String) name;
|
|
|
|
// Field field = ReflectionUtils.findField(propertyName, relevantClass);
|
|
|
|
// Field field = ReflectionUtils.findField(propertyName, relevantClass);
|
|
|
|
// if (field != null) {
|
|
|
|
// if (field != null) {
|
|
|
|
// return true;
|
|
|
|
// return true;
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// Method m = ReflectionUtils.findGetterForProperty(propertyName, relevantClass);
|
|
|
|
// Method m = ReflectionUtils.findGetterForProperty(propertyName, relevantClass);
|
|
|
|
// if (m != null) {
|
|
|
|
// if (m != null) {
|
|
|
|
// return true;
|
|
|
|
// return true;
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// return false;
|
|
|
|
// return false;
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
|
|
|
|
//
|
|
|
|
/** |
|
|
|
// /**
|
|
|
|
* Read the specified property from the specified target. |
|
|
|
// * Read the specified property from the specified target. //
|
|
|
|
// */
|
|
|
|
// */
|
|
|
|
// public Object read(EvaluationContext context, Object target, Object name) throws AccessException {
|
|
|
|
// public Object read(EvaluationContext context, Object target, Object name) throws AccessException {
|
|
|
|
// if (target==null) {
|
|
|
|
// if (target==null) {
|
|
|
|
// return null;
|
|
|
|
// return null;
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// Class<?> relevantClass = (target instanceof Class ? (Class<?>) target : target.getClass());
|
|
|
|
// Class<?> relevantClass = (target instanceof Class ? (Class<?>) target : target.getClass());
|
|
|
|
// if (!(name instanceof String)) {
|
|
|
|
// if (!(name instanceof String)) {
|
|
|
|
// return null; // TODO should raise an exception if the property cannot be found?
|
|
|
|
// return null;
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// String propertyName = (String) name;
|
|
|
|
// String propertyName = (String) name;
|
|
|
|
// Field field = ReflectionUtils.findField(propertyName, relevantClass);
|
|
|
|
// Field field = ReflectionUtils.findField(propertyName, relevantClass);
|
|
|
|
// if (field != null) {
|
|
|
|
// if (field != null) {
|
|
|
|
// try {
|
|
|
|
// try {
|
|
|
|
// if (!field.isAccessible()) {
|
|
|
|
// if (!field.isAccessible()) {
|
|
|
|
// field.setAccessible(true);
|
|
|
|
// field.setAccessible(true);
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// return field.get(target);
|
|
|
|
// return field.get(target);
|
|
|
|
// } catch (IllegalArgumentException e) {
|
|
|
|
// } catch (IllegalArgumentException e) {
|
|
|
|
// throw new AccessException("Unable to access field: " + name, e);
|
|
|
|
// throw new AccessException("Unable to access field: " + name, e);
|
|
|
|
// } catch (IllegalAccessException e) {
|
|
|
|
// } catch (IllegalAccessException e) {
|
|
|
|
// throw new AccessException("Unable to access field: " + name, e);
|
|
|
|
// throw new AccessException("Unable to access field: " + name, e);
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// Method m = ReflectionUtils.findGetterForProperty(propertyName, relevantClass);
|
|
|
|
// Method m = ReflectionUtils.findGetterForProperty(propertyName, relevantClass);
|
|
|
|
// if (m != null) {
|
|
|
|
// if (m != null) {
|
|
|
|
// try {
|
|
|
|
// try {
|
|
|
|
// if (!m.isAccessible())
|
|
|
|
// if (!m.isAccessible())
|
|
|
|
// m.setAccessible(true);
|
|
|
|
// m.setAccessible(true);
|
|
|
|
// return m.invoke(target);
|
|
|
|
// return m.invoke(target);
|
|
|
|
// } catch (IllegalArgumentException e) {
|
|
|
|
// } catch (IllegalArgumentException e) {
|
|
|
|
// throw new AccessException("Unable to access property '" + name + "' through getter", e);
|
|
|
|
// throw new AccessException("Unable to access property '" + name + "' through getter", e);
|
|
|
|
// } catch (IllegalAccessException e) {
|
|
|
|
// } catch (IllegalAccessException e) {
|
|
|
|
// throw new AccessException("Unable to access property '" + name + "' through getter", e);
|
|
|
|
// throw new AccessException("Unable to access property '" + name + "' through getter", e);
|
|
|
|
// } catch (InvocationTargetException e) {
|
|
|
|
// } catch (InvocationTargetException e) {
|
|
|
|
// throw new AccessException("Unable to access property '" + name + "' through getter", e);
|
|
|
|
// throw new AccessException("Unable to access property '" + name + "' through getter", e);
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// return null;
|
|
|
|
// return null;
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
|
|
|
|
// public void write(EvaluationContext context, Object target, Object name, Object newValue) throws AccessException
|
|
|
|
// public void write(EvaluationContext context, Object target, Object name, Object newValue) throws AccessException {
|
|
|
|
// {
|
|
|
|
// if (target==null) {
|
|
|
|
// if (target==null) {
|
|
|
|
// return;
|
|
|
|
// return;
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// Class<?> relevantClass = (target instanceof Class ? (Class<?>) target : target.getClass());
|
|
|
|
// Class<?> relevantClass = (target instanceof Class ? (Class<?>) target : target.getClass());
|
|
|
|
// if (!(name instanceof String))
|
|
|
|
// if (!(name instanceof String))
|
|
|
|
// return;
|
|
|
|
// return;
|
|
|
|
// Field field = ReflectionUtils.findField((String) name, relevantClass);
|
|
|
|
// Field field = ReflectionUtils.findField((String) name, relevantClass);
|
|
|
|
// if (field != null) {
|
|
|
|
// if (field != null) {
|
|
|
|
// try {
|
|
|
|
// try {
|
|
|
|
// if (!field.isAccessible())
|
|
|
|
// if (!field.isAccessible())
|
|
|
|
// field.setAccessible(true);
|
|
|
|
// field.setAccessible(true);
|
|
|
|
// field.set(target, newValue);
|
|
|
|
// field.set(target, newValue);
|
|
|
|
// } catch (IllegalArgumentException e) {
|
|
|
|
// } catch (IllegalArgumentException e) {
|
|
|
|
// throw new AccessException("Unable to write to property '" + name + "'", e);
|
|
|
|
// throw new AccessException("Unable to write to property '" + name + "'", e);
|
|
|
|
// } catch (IllegalAccessException e) {
|
|
|
|
// } catch (IllegalAccessException e) {
|
|
|
|
// throw new AccessException("Unable to write to property '" + name + "'", e);
|
|
|
|
// throw new AccessException("Unable to write to property '" + name + "'", e);
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// Method m = ReflectionUtils.findSetterForProperty((String) name, relevantClass);
|
|
|
|
// Method m = ReflectionUtils.findSetterForProperty((String) name, relevantClass);
|
|
|
|
// if (m != null) {
|
|
|
|
// if (m != null) {
|
|
|
|
// try {
|
|
|
|
// try {
|
|
|
|
// if (!m.isAccessible())
|
|
|
|
// if (!m.isAccessible())
|
|
|
|
// m.setAccessible(true);
|
|
|
|
// m.setAccessible(true);
|
|
|
|
// m.invoke(target, newValue);
|
|
|
|
// m.invoke(target, newValue);
|
|
|
|
// } catch (IllegalArgumentException e) {
|
|
|
|
// } catch (IllegalArgumentException e) {
|
|
|
|
// throw new AccessException("Unable to access property '" + name + "' through setter", e);
|
|
|
|
// throw new AccessException("Unable to access property '" + name + "' through setter", e);
|
|
|
|
// } catch (IllegalAccessException e) {
|
|
|
|
// } catch (IllegalAccessException e) {
|
|
|
|
// throw new AccessException("Unable to access property '" + name + "' through setter", e);
|
|
|
|
// throw new AccessException("Unable to access property '" + name + "' through setter", e);
|
|
|
|
// } catch (InvocationTargetException e) {
|
|
|
|
// } catch (InvocationTargetException e) {
|
|
|
|
// throw new AccessException("Unable to access property '" + name + "' through setter", e);
|
|
|
|
// throw new AccessException("Unable to access property '" + name + "' through setter", e);
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
|
|
|
|
//
|
|
|
|
public Class<?>[] getSpecificTargetClasses() { |
|
|
|
//
|
|
|
|
return null; // this is a general purpose resolver that will try to access properties on any type!
|
|
|
|
// public boolean canWrite(EvaluationContext context, Object target, Object name) throws AccessException {
|
|
|
|
} |
|
|
|
// if (target==null) {
|
|
|
|
|
|
|
|
// return false;
|
|
|
|
// public boolean canWrite(EvaluationContext context, Object target, Object name) throws AccessException {
|
|
|
|
// }
|
|
|
|
// if (target==null) {
|
|
|
|
// Class<?> relevantClass = (target instanceof Class ? (Class<?>) target : target.getClass());
|
|
|
|
// return false;
|
|
|
|
// if (!(name instanceof String))
|
|
|
|
// }
|
|
|
|
// return false;
|
|
|
|
// Class<?> relevantClass = (target instanceof Class ? (Class<?>) target : target.getClass());
|
|
|
|
// Field field = ReflectionUtils.findField((String) name, relevantClass);
|
|
|
|
// if (!(name instanceof String))
|
|
|
|
// if (field != null)
|
|
|
|
// return false;
|
|
|
|
// return true;
|
|
|
|
// Field field = ReflectionUtils.findField((String) name, relevantClass);
|
|
|
|
// Method m = ReflectionUtils.findSetterForProperty((String) name, relevantClass);
|
|
|
|
// if (field != null)
|
|
|
|
// if (m != null)
|
|
|
|
// return true;
|
|
|
|
// return true;
|
|
|
|
// Method m = ReflectionUtils.findSetterForProperty((String) name, relevantClass);
|
|
|
|
// return false;
|
|
|
|
// if (m != null)
|
|
|
|
// }
|
|
|
|
// return true;
|
|
|
|
|
|
|
|
// return false;
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|