Merge pull request #21 from aclement/spr9038

This commit is contained in:
Chris Beams
2012-02-01 22:47:36 +01:00
2 changed files with 327 additions and 329 deletions

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2010 the original author or authors. * Copyright 2002-2011 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -38,11 +38,14 @@ import org.springframework.expression.spel.SpelMessage;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
/** /**
* A method resolver that uses reflection to locate the method that should be invoked. * Reflection-based {@link MethodResolver} used by default in
* {@link StandardEvaluationContext} unless explicit method resolvers have been specified.
* *
* @author Andy Clement * @author Andy Clement
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Chris Beams
* @since 3.0 * @since 3.0
* @see StandardEvaluationContext#addMethodResolver(MethodResolver)
*/ */
public class ReflectiveMethodResolver implements MethodResolver { public class ReflectiveMethodResolver implements MethodResolver {
@@ -87,15 +90,15 @@ public class ReflectiveMethodResolver implements MethodResolver {
try { try {
TypeConverter typeConverter = context.getTypeConverter(); TypeConverter typeConverter = context.getTypeConverter();
Class<?> type = (targetObject instanceof Class ? (Class<?>) targetObject : targetObject.getClass()); Class<?> type = (targetObject instanceof Class ? (Class<?>) targetObject : targetObject.getClass());
Method[] methods = type.getMethods(); Method[] methods = getMethods(type);
// If a filter is registered for this type, call it // If a filter is registered for this type, call it
MethodFilter filter = (this.filters != null ? this.filters.get(type) : null); MethodFilter filter = (this.filters != null ? this.filters.get(type) : null);
if (filter != null) { if (filter != null) {
List<Method> methodsForFiltering = new ArrayList<Method>(); List<Method> methodsForFiltering = new ArrayList<Method>();
for (Method method: methods) { for (Method method: methods) {
methodsForFiltering.add(method); methodsForFiltering.add(method);
} }
List<Method> methodsFiltered = filter.filter(methodsForFiltering); List<Method> methodsFiltered = filter.filter(methodsForFiltering);
if (CollectionUtils.isEmpty(methodsFiltered)) { if (CollectionUtils.isEmpty(methodsFiltered)) {
methods = NO_METHODS; methods = NO_METHODS;
@@ -124,7 +127,7 @@ public class ReflectiveMethodResolver implements MethodResolver {
continue; continue;
} }
if (method.getName().equals(name)) { if (method.getName().equals(name)) {
Class[] paramTypes = method.getParameterTypes(); Class<?>[] paramTypes = method.getParameterTypes();
List<TypeDescriptor> paramDescriptors = new ArrayList<TypeDescriptor>(paramTypes.length); List<TypeDescriptor> paramDescriptors = new ArrayList<TypeDescriptor>(paramTypes.length);
for (int i = 0; i < paramTypes.length; i++) { for (int i = 0; i < paramTypes.length; i++) {
paramDescriptors.add(new TypeDescriptor(new MethodParameter(method, i))); paramDescriptors.add(new TypeDescriptor(new MethodParameter(method, i)));
@@ -194,4 +197,16 @@ public class ReflectiveMethodResolver implements MethodResolver {
} }
} }
/**
* Return the set of methods for this type. The default implementation returns the
* result of Class#getMethods for the given {@code type}, but subclasses may override
* in order to alter the results, e.g. specifying static methods declared elsewhere.
*
* @param type the class for which to return the methods
* @since 3.1.1
*/
protected Method[] getMethods(Class<?> type) {
return type.getMethods();
}
} }

View File

@@ -17,8 +17,10 @@
package org.springframework.expression.spel; package org.springframework.expression.spel;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
@@ -38,6 +40,7 @@ import org.springframework.expression.EvaluationException;
import org.springframework.expression.Expression; import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser; import org.springframework.expression.ExpressionParser;
import org.springframework.expression.MethodExecutor; import org.springframework.expression.MethodExecutor;
import org.springframework.expression.MethodResolver;
import org.springframework.expression.ParserContext; import org.springframework.expression.ParserContext;
import org.springframework.expression.PropertyAccessor; import org.springframework.expression.PropertyAccessor;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
@@ -132,8 +135,8 @@ public class SpringEL300Tests extends ExpressionTestCase {
static class Spr5899Class { static class Spr5899Class {
public Spr5899Class() {} public Spr5899Class() {}
public Spr5899Class(Integer i) { } public Spr5899Class(Integer i) { }
public Spr5899Class(Integer i, String... s) { } public Spr5899Class(Integer i, String... s) { }
public Integer tryToInvokeWithNull(Integer value) { return value; } public Integer tryToInvokeWithNull(Integer value) { return value; }
public Integer tryToInvokeWithNull2(int i) { return new Integer(i); } public Integer tryToInvokeWithNull2(int i) { return new Integer(i); }
@@ -179,10 +182,9 @@ public class SpringEL300Tests extends ExpressionTestCase {
} }
} }
@SuppressWarnings("unchecked")
@Test @Test
public void testSPR5804() throws Exception { public void testSPR5804() throws Exception {
Map m = new HashMap(); Map<String,String> m = new HashMap<String,String>();
m.put("foo", "bar"); m.put("foo", "bar");
StandardEvaluationContext eContext = new StandardEvaluationContext(m); // root is a map instance StandardEvaluationContext eContext = new StandardEvaluationContext(m); // root is a map instance
eContext.addPropertyAccessor(new MapAccessor()); eContext.addPropertyAccessor(new MapAccessor());
@@ -239,11 +241,11 @@ public class SpringEL300Tests extends ExpressionTestCase {
static class MapAccessor implements PropertyAccessor { static class MapAccessor implements PropertyAccessor {
public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException { public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException {
return (((Map) target).containsKey(name)); return (((Map<?,?>) target).containsKey(name));
} }
public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException { public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
return new TypedValue(((Map) target).get(name)); return new TypedValue(((Map<?,?>) target).get(name));
} }
public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException { public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException {
@@ -252,10 +254,10 @@ public class SpringEL300Tests extends ExpressionTestCase {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException { public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException {
((Map) target).put(name, newValue); ((Map<String, Object>) target).put(name, newValue);
} }
public Class[] getSpecificTargetClasses() { public Class<?>[] getSpecificTargetClasses() {
return new Class[] {Map.class}; return new Class[] {Map.class};
} }
@@ -338,8 +340,8 @@ public class SpringEL300Tests extends ExpressionTestCase {
} }
private final Resource resource; private final Resource resource;
public Resource getResource() { public Resource getResource() {
return resource; return resource;
} }
} }
static class Resource { static class Resource {
@@ -376,7 +378,6 @@ public class SpringEL300Tests extends ExpressionTestCase {
} }
/** $ related identifiers */ /** $ related identifiers */
@SuppressWarnings("unchecked")
@Test @Test
public void testDollarPrefixedIdentifier_SPR7100() { public void testDollarPrefixedIdentifier_SPR7100() {
Holder h = new Holder(); Holder h = new Holder();
@@ -431,7 +432,10 @@ public class SpringEL300Tests extends ExpressionTestCase {
Assert.assertEquals("wobble",name); Assert.assertEquals("wobble",name);
} }
/** Should be accessing (setting) Goo.wibble field because 'bar' variable evaluates to "wibble" */ /**
* Should be accessing (setting) Goo.wibble field because 'bar' variable evaluates to
* "wibble"
*/
@Test @Test
public void testIndexingAsAPropertyAccess_SPR6968_4() { public void testIndexingAsAPropertyAccess_SPR6968_4() {
Goo g = Goo.instance; Goo g = Goo.instance;
@@ -509,7 +513,7 @@ public class SpringEL300Tests extends ExpressionTestCase {
static class Holder { static class Holder {
public Map map = new HashMap(); public Map<String,String> map = new HashMap<String,String>();
} }
// --- // ---
@@ -553,21 +557,6 @@ public class SpringEL300Tests extends ExpressionTestCase {
} }
}; };
// @Test
// public void testFails() {
//
// StandardEvaluationContext evaluationContext = new StandardEvaluationContext();
// evaluationContext.setVariable("target", new Foo2());
// for (int i = 0; i < 300000; i++) {
// evaluationContext.addPropertyAccessor(new MapAccessor());
// ExpressionParser parser = new SpelExpressionParser();
// Expression expression = parser.parseExpression("#target.execute(payload)");
// Message message = new Message();
// message.setPayload(i+"");
// expression.getValue(evaluationContext, message);
// }
// }
static class Foo2 { static class Foo2 {
public void execute(String str){ public void execute(String str){
System.out.println("Value: " + str); System.out.println("Value: " + str);
@@ -698,64 +687,63 @@ public class SpringEL300Tests extends ExpressionTestCase {
} }
@Test @Test
@SuppressWarnings("unchecked")
public void testMapOfMap_SPR7244() throws Exception { public void testMapOfMap_SPR7244() throws Exception {
Map<String,Object> map = new LinkedHashMap(); Map<String,Object> map = new LinkedHashMap<String,Object>();
map.put("uri", "http:"); map.put("uri", "http:");
Map nameMap = new LinkedHashMap(); Map<String,String> nameMap = new LinkedHashMap<String,String>();
nameMap.put("givenName", "Arthur"); nameMap.put("givenName", "Arthur");
map.put("value", nameMap); map.put("value", nameMap);
StandardEvaluationContext ctx = new StandardEvaluationContext(map); StandardEvaluationContext ctx = new StandardEvaluationContext(map);
ExpressionParser parser = new SpelExpressionParser(); ExpressionParser parser = new SpelExpressionParser();
String el1 = "#root['value'].get('givenName')"; String el1 = "#root['value'].get('givenName')";
Expression exp = parser.parseExpression(el1); Expression exp = parser.parseExpression(el1);
Object evaluated = exp.getValue(ctx); Object evaluated = exp.getValue(ctx);
Assert.assertEquals("Arthur", evaluated); Assert.assertEquals("Arthur", evaluated);
String el2 = "#root['value']['givenName']"; String el2 = "#root['value']['givenName']";
exp = parser.parseExpression(el2); exp = parser.parseExpression(el2);
evaluated = exp.getValue(ctx); evaluated = exp.getValue(ctx);
Assert.assertEquals("Arthur",evaluated); Assert.assertEquals("Arthur",evaluated);
} }
@Test @Test
public void testProjectionTypeDescriptors_1() throws Exception { public void testProjectionTypeDescriptors_1() throws Exception {
StandardEvaluationContext ctx = new StandardEvaluationContext(new C()); StandardEvaluationContext ctx = new StandardEvaluationContext(new C());
SpelExpressionParser parser = new SpelExpressionParser(); SpelExpressionParser parser = new SpelExpressionParser();
String el1 = "ls.![#this.equals('abc')]"; String el1 = "ls.![#this.equals('abc')]";
SpelExpression exp = parser.parseRaw(el1); SpelExpression exp = parser.parseRaw(el1);
List value = (List)exp.getValue(ctx); List<?> value = (List<?>)exp.getValue(ctx);
// value is list containing [true,false] // value is list containing [true,false]
Assert.assertEquals(Boolean.class,value.get(0).getClass()); Assert.assertEquals(Boolean.class,value.get(0).getClass());
TypeDescriptor evaluated = exp.getValueTypeDescriptor(ctx); TypeDescriptor evaluated = exp.getValueTypeDescriptor(ctx);
Assert.assertEquals(null, evaluated.getElementTypeDescriptor()); Assert.assertEquals(null, evaluated.getElementTypeDescriptor());
} }
@Test @Test
public void testProjectionTypeDescriptors_2() throws Exception { public void testProjectionTypeDescriptors_2() throws Exception {
StandardEvaluationContext ctx = new StandardEvaluationContext(new C()); StandardEvaluationContext ctx = new StandardEvaluationContext(new C());
SpelExpressionParser parser = new SpelExpressionParser(); SpelExpressionParser parser = new SpelExpressionParser();
String el1 = "as.![#this.equals('abc')]"; String el1 = "as.![#this.equals('abc')]";
SpelExpression exp = parser.parseRaw(el1); SpelExpression exp = parser.parseRaw(el1);
Object[] value = (Object[])exp.getValue(ctx); Object[] value = (Object[])exp.getValue(ctx);
// value is array containing [true,false] // value is array containing [true,false]
Assert.assertEquals(Boolean.class,value[0].getClass()); Assert.assertEquals(Boolean.class,value[0].getClass());
TypeDescriptor evaluated = exp.getValueTypeDescriptor(ctx); TypeDescriptor evaluated = exp.getValueTypeDescriptor(ctx);
Assert.assertEquals(Boolean.class, evaluated.getElementTypeDescriptor().getType()); Assert.assertEquals(Boolean.class, evaluated.getElementTypeDescriptor().getType());
} }
@Test @Test
public void testProjectionTypeDescriptors_3() throws Exception { public void testProjectionTypeDescriptors_3() throws Exception {
StandardEvaluationContext ctx = new StandardEvaluationContext(new C()); StandardEvaluationContext ctx = new StandardEvaluationContext(new C());
SpelExpressionParser parser = new SpelExpressionParser(); SpelExpressionParser parser = new SpelExpressionParser();
String el1 = "ms.![key.equals('abc')]"; String el1 = "ms.![key.equals('abc')]";
SpelExpression exp = parser.parseRaw(el1); SpelExpression exp = parser.parseRaw(el1);
List value = (List)exp.getValue(ctx); List<?> value = (List<?>)exp.getValue(ctx);
// value is list containing [true,false] // value is list containing [true,false]
Assert.assertEquals(Boolean.class,value.get(0).getClass()); Assert.assertEquals(Boolean.class,value.get(0).getClass());
TypeDescriptor evaluated = exp.getValueTypeDescriptor(ctx); TypeDescriptor evaluated = exp.getValueTypeDescriptor(ctx);
Assert.assertEquals(null, evaluated.getElementTypeDescriptor()); Assert.assertEquals(null, evaluated.getElementTypeDescriptor());
} }
static class C { static class C {
@@ -795,29 +783,30 @@ public class SpringEL300Tests extends ExpressionTestCase {
list.add(new D(null)); list.add(new D(null));
list.add(new D("zzz")); list.add(new D("zzz"));
StandardEvaluationContext ctx = new StandardEvaluationContext(list); StandardEvaluationContext ctx = new StandardEvaluationContext(list);
SpelExpressionParser parser = new SpelExpressionParser(); SpelExpressionParser parser = new SpelExpressionParser();
String el1 = "#root.?[a < 'hhh']"; String el1 = "#root.?[a < 'hhh']";
SpelExpression exp = parser.parseRaw(el1); SpelExpression exp = parser.parseRaw(el1);
Object value = exp.getValue(ctx); Object value = exp.getValue(ctx);
assertEquals("[D(aaa), D(bbb), D(null), D(ccc), D(null)]",value.toString()); assertEquals("[D(aaa), D(bbb), D(null), D(ccc), D(null)]",value.toString());
String el2 = "#root.?[a > 'hhh']"; String el2 = "#root.?[a > 'hhh']";
SpelExpression exp2 = parser.parseRaw(el2); SpelExpression exp2 = parser.parseRaw(el2);
Object value2 = exp2.getValue(ctx); Object value2 = exp2.getValue(ctx);
assertEquals("[D(zzz)]",value2.toString()); assertEquals("[D(zzz)]",value2.toString());
// trim out the nulls first // trim out the nulls first
String el3 = "#root.?[a!=null].?[a < 'hhh']"; String el3 = "#root.?[a!=null].?[a < 'hhh']";
SpelExpression exp3 = parser.parseRaw(el3); SpelExpression exp3 = parser.parseRaw(el3);
Object value3 = exp3.getValue(ctx); Object value3 = exp3.getValue(ctx);
assertEquals("[D(aaa), D(bbb), D(ccc)]",value3.toString()); assertEquals("[D(aaa), D(bbb), D(ccc)]",value3.toString());
} }
/** /**
* Test whether {@link ReflectiveMethodResolver} follows Java Method Invocation Conversion order. And more precisely * Test whether {@link ReflectiveMethodResolver} follows Java Method Invocation
* that widening reference conversion is 'higher' than a unboxing conversion. * Conversion order. And more precisely that widening reference conversion is 'higher'
* than a unboxing conversion.
*/ */
@Test @Test
public void testConversionPriority_8224() throws Exception { public void testConversionPriority_8224() throws Exception {
@@ -957,109 +946,108 @@ public class SpringEL300Tests extends ExpressionTestCase {
public class ReflectionUtil<T extends Number> { public class ReflectionUtil<T extends Number> {
public Object methodToCall(T param) { public Object methodToCall(T param) {
System.out.println(param+" "+param.getClass()); System.out.println(param+" "+param.getClass());
return "Object methodToCall(T param)"; return "Object methodToCall(T param)";
} }
public void foo(int... array) { public void foo(int... array) {
if (array.length==0) { if (array.length==0) {
throw new RuntimeException(); throw new RuntimeException();
} }
} }
public void foo(float...array) { public void foo(float...array) {
if (array.length==0) { if (array.length==0) {
throw new RuntimeException(); throw new RuntimeException();
} }
} }
public void foo(double...array) { public void foo(double...array) {
if (array.length==0) { if (array.length==0) {
throw new RuntimeException(); throw new RuntimeException();
} }
} }
public void foo(short...array) { public void foo(short...array) {
if (array.length==0) { if (array.length==0) {
throw new RuntimeException(); throw new RuntimeException();
} }
} }
public void foo(long...array) { public void foo(long...array) {
if (array.length==0) { if (array.length==0) {
throw new RuntimeException(); throw new RuntimeException();
} }
} }
public void foo(boolean...array) { public void foo(boolean...array) {
if (array.length==0) { if (array.length==0) {
throw new RuntimeException(); throw new RuntimeException();
} }
} }
public void foo(char...array) { public void foo(char...array) {
if (array.length==0) { if (array.length==0) {
throw new RuntimeException(); throw new RuntimeException();
} }
} }
public void foo(byte...array) { public void foo(byte...array) {
if (array.length==0) { if (array.length==0) {
throw new RuntimeException(); throw new RuntimeException();
} }
} }
public void bar(int... array) { public void bar(int... array) {
if (array.length==0) { if (array.length==0) {
throw new RuntimeException(); throw new RuntimeException();
} }
} }
} }
@Test @Test
public void testReservedWords_8228() throws Exception { public void testReservedWords_8228() throws Exception {
// "DIV","EQ","GE","GT","LE","LT","MOD","NE","NOT" // "DIV","EQ","GE","GT","LE","LT","MOD","NE","NOT"
@SuppressWarnings("unused") @SuppressWarnings("unused")
class Reserver { class Reserver {
public Reserver getReserver() { public Reserver getReserver() {
return this; return this;
} }
public String NE = "abc"; public String NE = "abc";
public String ne = "def"; public String ne = "def";
public int DIV = 1; public int DIV = 1;
public int div = 3; public int div = 3;
public Map m = new HashMap(); public Map<String,String> m = new HashMap<String,String>();
@SuppressWarnings("unchecked")
Reserver() { Reserver() {
m.put("NE","xyz"); m.put("NE","xyz");
} }
} }
StandardEvaluationContext ctx = new StandardEvaluationContext(new Reserver()); StandardEvaluationContext ctx = new StandardEvaluationContext(new Reserver());
SpelExpressionParser parser = new SpelExpressionParser(); SpelExpressionParser parser = new SpelExpressionParser();
String ex = "getReserver().NE"; String ex = "getReserver().NE";
SpelExpression exp = null; SpelExpression exp = null;
exp = parser.parseRaw(ex); exp = parser.parseRaw(ex);
String value = (String)exp.getValue(ctx); String value = (String)exp.getValue(ctx);
Assert.assertEquals("abc",value); Assert.assertEquals("abc",value);
ex = "getReserver().ne"; ex = "getReserver().ne";
exp = parser.parseRaw(ex); exp = parser.parseRaw(ex);
value = (String)exp.getValue(ctx); value = (String)exp.getValue(ctx);
Assert.assertEquals("def",value); Assert.assertEquals("def",value);
ex = "getReserver().m[NE]"; ex = "getReserver().m[NE]";
exp = parser.parseRaw(ex); exp = parser.parseRaw(ex);
value = (String)exp.getValue(ctx); value = (String)exp.getValue(ctx);
Assert.assertEquals("xyz",value); Assert.assertEquals("xyz",value);
ex = "getReserver().DIV"; ex = "getReserver().DIV";
exp = parser.parseRaw(ex); exp = parser.parseRaw(ex);
Assert.assertEquals(1,exp.getValue(ctx)); Assert.assertEquals(1,exp.getValue(ctx));
ex = "getReserver().div"; ex = "getReserver().div";
exp = parser.parseRaw(ex); exp = parser.parseRaw(ex);
Assert.assertEquals(3,exp.getValue(ctx)); Assert.assertEquals(3,exp.getValue(ctx));
exp = parser.parseRaw("NE"); exp = parser.parseRaw("NE");
Assert.assertEquals("abc",exp.getValue(ctx)); Assert.assertEquals("abc",exp.getValue(ctx));
} }
/** /**
@@ -1089,21 +1077,6 @@ public class SpringEL300Tests extends ExpressionTestCase {
expressionParser.parseExpression("shouldBeFourth").getValue(evaluationContext)); expressionParser.parseExpression("shouldBeFourth").getValue(evaluationContext));
} }
// test not quite complete, it doesn't check that the list of resolvers at the end of
// PropertyOrFieldReference.getPropertyAccessorsToTry() doesn't contain duplicates, which
// is what it is trying to test by having a property accessor that returns specific
// classes Integer and Number
// @Test
// public void testPropertyAccessorOrder_8211_2() {
// ExpressionParser expressionParser = new SpelExpressionParser();
// StandardEvaluationContext evaluationContext =
// new StandardEvaluationContext(new Integer(42));
//
// evaluationContext.addPropertyAccessor(new TestPropertyAccessor2());
//
// assertEquals("42", expressionParser.parseExpression("x").getValue(evaluationContext));
// }
class TestPropertyAccessor implements PropertyAccessor { class TestPropertyAccessor implements PropertyAccessor {
private String mapName; private String mapName;
public TestPropertyAccessor(String mapName) { public TestPropertyAccessor(String mapName) {
@@ -1140,31 +1113,6 @@ public class SpringEL300Tests extends ExpressionTestCase {
} }
// class TestPropertyAccessor2 implements PropertyAccessor {
//
// public Class[] getSpecificTargetClasses() {
// return new Class[]{Integer.class,Number.class};
// }
//
// public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException {
// return true;
// }
//
// public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
// return new TypedValue(target.toString(),TypeDescriptor.valueOf(String.class));
// }
//
// public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException {
// return false;
// }
//
// public void write(EvaluationContext context, Object target, String name, Object newValue)
// throws AccessException {
// throw new UnsupportedOperationException();
// }
//
// }
class ContextObject { class ContextObject {
public Map<String, String> firstContext = new HashMap<String, String>(); public Map<String, String> firstContext = new HashMap<String, String>();
public Map<String, String> secondContext = new HashMap<String, String>(); public Map<String, String> secondContext = new HashMap<String, String>();
@@ -1192,6 +1140,41 @@ public class SpringEL300Tests extends ExpressionTestCase {
public Map<String, String> getFourthContext() {return fourthContext;} public Map<String, String> getFourthContext() {return fourthContext;}
} }
/**
* Test the ability to subclass the ReflectiveMethodResolver and change how it
* determines the set of methods for a type.
*/
@Test
public void testCustomStaticFunctions_SPR9038() {
try {
ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext context = new StandardEvaluationContext();
List<MethodResolver> methodResolvers = new ArrayList<MethodResolver>();
methodResolvers.add(new ReflectiveMethodResolver() {
@Override
protected Method[] getMethods(Class<?> type) {
try {
return new Method[] {
Integer.class.getDeclaredMethod("parseInt", new Class[] {
String.class, Integer.TYPE }) };
} catch (NoSuchMethodException e1) {
return new Method[0];
}
}
});
context.setMethodResolvers(methodResolvers);
org.springframework.expression.Expression expression =
parser.parseExpression("parseInt('-FF', 16)");
Integer result = expression.getValue(context, "", Integer.class);
assertEquals("Equal assertion failed: ", -255, result.intValue());
} catch (Exception e) {
e.printStackTrace();
fail("Unexpected exception: "+e.toString());
}
}
} }