diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/support/SimplePropertyAccessor.java b/spring-expression/src/main/java/org/springframework/expression/spel/support/DataBindingPropertyAccessor.java similarity index 56% rename from spring-expression/src/main/java/org/springframework/expression/spel/support/SimplePropertyAccessor.java rename to spring-expression/src/main/java/org/springframework/expression/spel/support/DataBindingPropertyAccessor.java index bf8bc70019..2deb173993 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/support/SimplePropertyAccessor.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/support/DataBindingPropertyAccessor.java @@ -18,13 +18,9 @@ package org.springframework.expression.spel.support; import java.lang.reflect.Method; -import org.springframework.expression.AccessException; -import org.springframework.expression.EvaluationContext; -import org.springframework.lang.Nullable; - /** - * A simple {@link org.springframework.expression.PropertyAccessor} variant that - * uses reflection to access properties for reading and possibly also writing. + * A {@link org.springframework.expression.PropertyAccessor} variant for data binding + * purposes, using reflection to access properties for reading and possibly writing. * *
A property can be accessed through a public getter method (when being read) * or a public setter method (when being written), and also as a public field. @@ -35,47 +31,21 @@ import org.springframework.lang.Nullable; * * @author Juergen Hoeller * @since 4.3.15 + * @see #forReadOnlyAccess() + * @see #forReadWriteAccess() * @see SimpleEvaluationContext * @see StandardEvaluationContext * @see ReflectivePropertyAccessor */ -public class SimplePropertyAccessor extends ReflectivePropertyAccessor { - - private final boolean allowWrite; - - - /** - * Create a new property accessor for reading as well writing. - * @see #SimplePropertyAccessor(boolean) - */ - public SimplePropertyAccessor() { - this.allowWrite = true; - } +public class DataBindingPropertyAccessor extends ReflectivePropertyAccessor { /** * Create a new property accessor for reading and possibly also writing. * @param allowWrite whether to also allow for write operations * @see #canWrite */ - public SimplePropertyAccessor(boolean allowWrite) { - this.allowWrite = allowWrite; - } - - - @Override - public boolean canWrite(EvaluationContext context, @Nullable Object target, String name) throws AccessException { - return (this.allowWrite && super.canWrite(context, target, name)); - } - - @Override - public void write(EvaluationContext context, @Nullable Object target, String name, @Nullable Object newValue) - throws AccessException { - - if (!this.allowWrite) { - throw new AccessException("PropertyAccessor for property '" + name + - "' on target [" + target + "] does not allow write operations"); - } - super.write(context, target, name, newValue); + private DataBindingPropertyAccessor(boolean allowWrite) { + super(allowWrite); } @Override @@ -83,4 +53,19 @@ public class SimplePropertyAccessor extends ReflectivePropertyAccessor { return (method.getDeclaringClass() != Object.class); } + + /** + * Create a new data-binding property accessor for read-only access. + */ + public static DataBindingPropertyAccessor forReadOnlyAccess() { + return new DataBindingPropertyAccessor(false); + } + + /** + * Create a new data-binding property accessor for read-write access. + */ + public static DataBindingPropertyAccessor forReadWriteAccess() { + return new DataBindingPropertyAccessor(true); + } + } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java index 3bf6cdf135..c8ad58abdc 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java @@ -46,7 +46,7 @@ import org.springframework.util.StringUtils; /** * A powerful {@link PropertyAccessor} that uses reflection to access properties - * for reading and writing. + * for reading and possibly also for writing. * *
A property can be accessed through a public getter method (when being read)
* or a public setter method (when being written), and also as a public field.
@@ -57,7 +57,7 @@ import org.springframework.util.StringUtils;
* @since 3.0
* @see StandardEvaluationContext
* @see SimpleEvaluationContext
- * @see SimplePropertyAccessor
+ * @see DataBindingPropertyAccessor
*/
public class ReflectivePropertyAccessor implements PropertyAccessor {
@@ -73,6 +73,8 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
}
+ private final boolean allowWrite;
+
private final Map Note: An optimal accessor is currently only usable for read attempts.
+ * Do not call this method if you need a read-write accessor.
+ * @see OptimalPropertyAccessor
*/
public PropertyAccessor createOptimalAccessor(EvaluationContext context, @Nullable Object target, String name) {
- // Don't be clever for arrays or null target
+ // Don't be clever for arrays or a null target...
if (target == null) {
return this;
}
@@ -506,7 +536,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
this.readerCache.put(cacheKey, invocationTarget);
}
}
- if (method != null) {
+ if (method != null && isCandidateForProperty(method)) {
return new OptimalPropertyAccessor(invocationTarget);
}
}
diff --git a/spring-expression/src/test/java/org/springframework/expression/spel/PropertyAccessTests.java b/spring-expression/src/test/java/org/springframework/expression/spel/PropertyAccessTests.java
index 84e74f831a..e8bf01cd41 100644
--- a/spring-expression/src/test/java/org/springframework/expression/spel/PropertyAccessTests.java
+++ b/spring-expression/src/test/java/org/springframework/expression/spel/PropertyAccessTests.java
@@ -32,7 +32,7 @@ import org.springframework.expression.PropertyAccessor;
import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.standard.SpelExpression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
-import org.springframework.expression.spel.support.SimplePropertyAccessor;
+import org.springframework.expression.spel.support.DataBindingPropertyAccessor;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.expression.spel.testresources.Person;
@@ -194,14 +194,14 @@ public class PropertyAccessTests extends AbstractExpressionTests {
public void noGetClassAccess() {
Expression expr = parser.parseExpression("'a'.class.getName()");
StandardEvaluationContext context = new StandardEvaluationContext();
- context.setPropertyAccessors(Collections.singletonList(new SimplePropertyAccessor()));
+ context.setPropertyAccessors(Collections.singletonList(DataBindingPropertyAccessor.forReadWriteAccess()));
expr.getValue(context);
}
@Test
public void propertyReadWrite() {
StandardEvaluationContext context = new StandardEvaluationContext();
- context.setPropertyAccessors(Collections.singletonList(new SimplePropertyAccessor()));
+ context.setPropertyAccessors(Collections.singletonList(DataBindingPropertyAccessor.forReadWriteAccess()));
Expression expr = parser.parseExpression("name");
Person target = new Person("p1");
@@ -216,7 +216,7 @@ public class PropertyAccessTests extends AbstractExpressionTests {
@Test(expected = SpelEvaluationException.class)
public void propertyReadOnly() {
StandardEvaluationContext context = new StandardEvaluationContext();
- context.setPropertyAccessors(Collections.singletonList(new SimplePropertyAccessor(false)));
+ context.setPropertyAccessors(Collections.singletonList(DataBindingPropertyAccessor.forReadOnlyAccess()));
Expression expr = parser.parseExpression("name");
Person target = new Person("p1");