提交 470e0861 编写于 作者: A Andy Clement

map access tests added

上级 769e706b
...@@ -25,9 +25,9 @@ import org.springframework.expression.EvaluationContext; ...@@ -25,9 +25,9 @@ import org.springframework.expression.EvaluationContext;
import org.springframework.expression.PropertyAccessor; import org.springframework.expression.PropertyAccessor;
import org.springframework.expression.PropertyReaderExecutor; import org.springframework.expression.PropertyReaderExecutor;
import org.springframework.expression.PropertyWriterExecutor; import org.springframework.expression.PropertyWriterExecutor;
import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.SpelException; import org.springframework.expression.spel.SpelException;
import org.springframework.expression.spel.SpelMessages; import org.springframework.expression.spel.SpelMessages;
import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.internal.Utils; import org.springframework.expression.spel.internal.Utils;
/** /**
...@@ -68,9 +68,9 @@ public class PropertyOrFieldReference extends SpelNode { ...@@ -68,9 +68,9 @@ public class PropertyOrFieldReference extends SpelNode {
return name.toString(); return name.toString();
} }
/** /**
* Attempt to read the named property from the current context object. * Attempt to read the named property from the current context object.
* *
* @param state the evaluation state * @param state the evaluation state
* @param name the name of the property * @param name the name of the property
* @return the value of the property * @return the value of the property
...@@ -88,19 +88,20 @@ public class PropertyOrFieldReference extends SpelNode { ...@@ -88,19 +88,20 @@ public class PropertyOrFieldReference extends SpelNode {
// let's try to get a new one and call it before giving up // let's try to get a new one and call it before giving up
} }
} }
Class<?> contextObjectClass = getObjectClass(contextObject); Class<?> contextObjectClass = getObjectClass(contextObject);
List<PropertyAccessor> accessorsToTry = getPropertyAccessorsToTry(contextObjectClass, state); List<PropertyAccessor> accessorsToTry = getPropertyAccessorsToTry(contextObjectClass, state);
// 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
if (accessorsToTry != null) { if (accessorsToTry != null) {
try { try {
for (PropertyAccessor accessor : accessorsToTry) { for (PropertyAccessor accessor : accessorsToTry) {
if (accessor instanceof CacheablePropertyAccessor) { if (accessor instanceof CacheablePropertyAccessor) {
cachedReaderExecutor = ((CacheablePropertyAccessor)accessor).getReaderAccessor(eContext, contextObject, name); cachedReaderExecutor = ((CacheablePropertyAccessor) accessor).getReaderAccessor(eContext,
contextObject, name);
if (cachedReaderExecutor != null) { if (cachedReaderExecutor != null) {
try { try {
return cachedReaderExecutor.execute(state.getEvaluationContext(), contextObject); return cachedReaderExecutor.execute(state.getEvaluationContext(), contextObject);
...@@ -124,14 +125,14 @@ public class PropertyOrFieldReference extends SpelNode { ...@@ -124,14 +125,14 @@ public class PropertyOrFieldReference extends SpelNode {
throw new SpelException(ae, SpelMessages.EXCEPTION_DURING_PROPERTY_READ, name, ae.getMessage()); throw new SpelException(ae, SpelMessages.EXCEPTION_DURING_PROPERTY_READ, name, ae.getMessage());
} }
} }
throw new SpelException(SpelMessages.PROPERTY_OR_FIELD_NOT_FOUND, name, Utils.formatClassnameForMessage(contextObjectClass)); throw new SpelException(SpelMessages.PROPERTY_OR_FIELD_NOT_FOUND, name, Utils
.formatClassnameForMessage(contextObjectClass));
} }
private void writeProperty(ExpressionState state, Object name, Object newValue) throws SpelException { private void writeProperty(ExpressionState state, Object name, Object newValue) throws SpelException {
Object contextObject = state.getActiveContextObject(); Object contextObject = state.getActiveContextObject();
EvaluationContext eContext = state.getEvaluationContext(); EvaluationContext eContext = state.getEvaluationContext();
if (cachedWriterExecutor != null) { if (cachedWriterExecutor != null) {
try { try {
cachedWriterExecutor.execute(state.getEvaluationContext(), contextObject, newValue); cachedWriterExecutor.execute(state.getEvaluationContext(), contextObject, newValue);
...@@ -149,7 +150,8 @@ public class PropertyOrFieldReference extends SpelNode { ...@@ -149,7 +150,8 @@ public class PropertyOrFieldReference extends SpelNode {
try { try {
for (PropertyAccessor accessor : accessorsToTry) { for (PropertyAccessor accessor : accessorsToTry) {
if (accessor instanceof CacheablePropertyAccessor) { if (accessor instanceof CacheablePropertyAccessor) {
cachedWriterExecutor = ((CacheablePropertyAccessor)accessor).getWriterAccessor(eContext, contextObject, name); cachedWriterExecutor = ((CacheablePropertyAccessor) accessor).getWriterAccessor(eContext,
contextObject, name);
if (cachedWriterExecutor != null) { if (cachedWriterExecutor != null) {
try { try {
cachedWriterExecutor.execute(state.getEvaluationContext(), contextObject, newValue); cachedWriterExecutor.execute(state.getEvaluationContext(), contextObject, newValue);
...@@ -171,7 +173,8 @@ public class PropertyOrFieldReference extends SpelNode { ...@@ -171,7 +173,8 @@ public class PropertyOrFieldReference extends SpelNode {
} }
} }
} catch (AccessException ae) { } catch (AccessException ae) {
throw new SpelException(getCharPositionInLine(), ae, SpelMessages.EXCEPTION_DURING_PROPERTY_WRITE, name, ae.getMessage()); throw new SpelException(getCharPositionInLine(), ae, SpelMessages.EXCEPTION_DURING_PROPERTY_WRITE,
name, ae.getMessage());
} }
} }
throw new SpelException(SpelMessages.PROPERTY_OR_FIELD_SETTER_NOT_FOUND, name, Utils throw new SpelException(SpelMessages.PROPERTY_OR_FIELD_SETTER_NOT_FOUND, name, Utils
...@@ -204,8 +207,8 @@ public class PropertyOrFieldReference extends SpelNode { ...@@ -204,8 +207,8 @@ public class PropertyOrFieldReference extends SpelNode {
* Determines the set of property resolvers that should be used to try and access a property on the specified target * Determines the set of property resolvers that should be used to try and access a property on the specified target
* type. The resolvers are considered to be in an ordered list, however in the returned list any that are exact * type. The resolvers are considered to be in an ordered list, however in the returned list any that are exact
* matches for the input target type (as opposed to 'general' resolvers that could work for any type) are placed at * matches for the input target type (as opposed to 'general' resolvers that could work for any type) are placed at
* the start of the list. In addition, there are specific resolvers that exactly name the class in question and * the start of the list. In addition, there are specific resolvers that exactly name the class in question and
* resolvers that name a specific class but it is a supertype of the class we have. These are put at the end of the * resolvers that name a specific class but it is a supertype of the class we have. These are put at the end of the
* specific resolvers set and will be tried after exactly matching accessors but before generic accessors. * specific resolvers set and will be tried after exactly matching accessors but before generic accessors.
* *
* @param targetType the type upon which property access is being attempted * @param targetType the type upon which property access is being attempted
...@@ -219,13 +222,16 @@ public class PropertyOrFieldReference extends SpelNode { ...@@ -219,13 +222,16 @@ public class PropertyOrFieldReference extends SpelNode {
if (targets == null) { // generic resolver that says it can be used for any type if (targets == null) { // generic resolver that says it can be used for any type
generalAccessors.add(resolver); generalAccessors.add(resolver);
} else { } else {
int pos = 0; if (targetType != null) {
for (int i = 0; i < targets.length; i++) { int pos = 0;
Class<?> clazz = targets[i]; for (int i = 0; i < targets.length; i++) {
if (clazz == targetType) { // put exact matches on the front to be tried first? Class<?> clazz = targets[i];
specificAccessors.add(pos++, resolver); if (clazz == targetType) { // put exact matches on the front to be tried first?
} else if (clazz.isAssignableFrom(targetType)) { // put supertype matches at the end of the specificAccessor list specificAccessors.add(pos++, resolver);
generalAccessors.add(resolver); } else if (clazz.isAssignableFrom(targetType)) { // put supertype matches at the end of the
// specificAccessor list
generalAccessors.add(resolver);
}
} }
} }
} }
......
...@@ -48,6 +48,7 @@ public class AllTests { ...@@ -48,6 +48,7 @@ public class AllTests {
suite.addTestSuite(TemplateExpressionParsingTests.class); suite.addTestSuite(TemplateExpressionParsingTests.class);
suite.addTestSuite(ExpressionLanguageScenarioTests.class); suite.addTestSuite(ExpressionLanguageScenarioTests.class);
suite.addTestSuite(ScenariosForSpringSecurity.class); suite.addTestSuite(ScenariosForSpringSecurity.class);
suite.addTestSuite(MapAccessTests.class);
suite.addTestSuite(SpelUtilitiesTests.class); suite.addTestSuite(SpelUtilitiesTests.class);
suite.addTestSuite(LiteralExpressionTests.class); suite.addTestSuite(LiteralExpressionTests.class);
suite.addTestSuite(CompositeStringExpressionTests.class); suite.addTestSuite(CompositeStringExpressionTests.class);
......
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
*/ */
package org.springframework.expression.spel; package org.springframework.expression.spel;
/** /**
* Tests the evaluation of real expressions in a real context. * Tests the evaluation of real expressions in a real context.
* *
...@@ -457,4 +456,5 @@ public class EvaluationTests extends ExpressionTestCase { ...@@ -457,4 +456,5 @@ public class EvaluationTests extends ExpressionTestCase {
evaluateAndAskForReturnType("3*4+5", (short) 17, Short.class); evaluateAndAskForReturnType("3*4+5", (short) 17, Short.class);
evaluateAndAskForReturnType("3*4+5", "17", String.class); evaluateAndAskForReturnType("3*4+5", "17", String.class);
} }
} }
/*
* Copyright 2004-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.spel;
import java.util.Map;
import org.springframework.expression.AccessException;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.PropertyAccessor;
import org.springframework.expression.spel.standard.StandardEvaluationContext;
/**
* Testing variations on map access.
*
* @author Andy Clement
*/
public class MapAccessTests extends ExpressionTestCase {
static class MapAccessor implements PropertyAccessor {
public boolean canRead(EvaluationContext context, Object target, Object name) throws AccessException {
return (((Map) target).containsKey(name));
}
public Object read(EvaluationContext context, Object target, Object name) throws AccessException {
return ((Map) target).get(name);
}
public boolean canWrite(EvaluationContext context, Object target, Object name) throws AccessException {
return true;
}
public void write(EvaluationContext context, Object target, Object name, Object newValue)
throws AccessException {
((Map) target).put(name, newValue);
}
public Class<?>[] getSpecificTargetClasses() {
return new Class[] { Map.class };
}
}
public void testSimpleMapAccess01() {
evaluate("testMap.get('monday')", "montag", String.class);
}
public void testMapAccessThroughIndexer() {
evaluate("testMap['monday']", "montag", String.class);
}
public void testCustomMapAccessor() throws Exception {
SpelExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext ctx = TestScenarioCreator.getTestEvaluationContext();
ctx.addPropertyAccessor(new MapAccessor());
Expression expr = parser.parseExpression("testMap.monday");
Object value = expr.getValue(ctx, String.class);
assertEquals("montag", value);
}
public void testVariableMapAccess() throws Exception {
SpelExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext ctx = TestScenarioCreator.getTestEvaluationContext();
ctx.setVariable("day", "saturday");
Expression expr = parser.parseExpression("testMap[#day]");
Object value = expr.getValue(ctx, String.class);
assertEquals("samstag", value);
}
// public void testMapAccess04() {
// evaluate("testMap[monday]", "montag", String.class);
// }
}
package org.springframework.expression.spel.testresources; package org.springframework.expression.spel.testresources;
import java.util.Date; import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class Inventor { public class Inventor {
...@@ -11,15 +13,24 @@ public class Inventor { ...@@ -11,15 +13,24 @@ public class Inventor {
private String nationality; private String nationality;
private String[] inventions; private String[] inventions;
public String randomField; public String randomField;
public Map testMap;
public Inventor(String name, Date birthdate, String nationality) { public Inventor(String name, Date birthdate, String nationality) {
this.name = name; this.name = name;
this.birthdate = birthdate; this.birthdate = birthdate;
this.nationality = nationality; this.nationality = nationality;
testMap = new HashMap();
testMap.put("monday", "montag");
testMap.put("tuesday", "dienstag");
testMap.put("wednesday", "mittwoch");
testMap.put("thursday", "donnerstag");
testMap.put("friday", "freitag");
testMap.put("saturday", "samstag");
testMap.put("sunday", "sonntag");
} }
public void setPlaceOfBirth(PlaceOfBirth placeOfBirth2) { public void setPlaceOfBirth(PlaceOfBirth placeOfBirth2) {
this.placeOfBirth = placeOfBirth2; placeOfBirth = placeOfBirth2;
} }
public void setInventions(String[] inventions) { public void setInventions(String[] inventions) {
...@@ -45,17 +56,20 @@ public class Inventor { ...@@ -45,17 +56,20 @@ public class Inventor {
public String joinThreeStrings(String a, String b, String c) { public String joinThreeStrings(String a, String b, String c) {
return a + b + c; return a + b + c;
} }
public int aVarargsMethod(String...strings ) { public int aVarargsMethod(String... strings) {
if (strings==null) return 0; if (strings == null)
return 0;
return strings.length; return strings.length;
} }
public int aVarargsMethod2(int i, String...strings ) {
if (strings==null) return i; public int aVarargsMethod2(int i, String... strings) {
return strings.length+i; if (strings == null)
return i;
return strings.length + i;
} }
public Inventor(String...strings ) { public Inventor(String... strings) {
} }
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册