fixed up FunctionReference a bit - so it can call varargs methods
This commit is contained in:
parent
2f05d70067
commit
f79e2643a3
|
@ -17,16 +17,19 @@ package org.springframework.expression.spel.ast;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.antlr.runtime.Token;
|
import org.antlr.runtime.Token;
|
||||||
|
import org.springframework.expression.EvaluationContext;
|
||||||
import org.springframework.expression.EvaluationException;
|
import org.springframework.expression.EvaluationException;
|
||||||
import org.springframework.expression.TypeConverter;
|
import org.springframework.expression.TypeConverter;
|
||||||
|
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.reflection.ReflectionUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A function reference is of the form "#someFunction(a,b,c)". Functions may be defined in the context prior to the
|
* A function reference is of the form "#someFunction(a,b,c)". Functions may be defined in the context prior to the
|
||||||
|
@ -54,11 +57,12 @@ public class FunctionReference extends SpelNode {
|
||||||
if (o == null) {
|
if (o == null) {
|
||||||
throw new SpelException(SpelMessages.FUNCTION_NOT_DEFINED, name);
|
throw new SpelException(SpelMessages.FUNCTION_NOT_DEFINED, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Two possibilities: a lambda function or a Java static method registered as a function
|
||||||
if (!(o instanceof Lambda || o instanceof Method)) {
|
if (!(o instanceof Lambda || o instanceof Method)) {
|
||||||
throw new SpelException(SpelMessages.FUNCTION_REFERENCE_CANNOT_BE_INVOKED, name, o.getClass());
|
throw new SpelException(SpelMessages.FUNCTION_REFERENCE_CANNOT_BE_INVOKED, name, o.getClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
// FUNCTION REF NEEDS TO DO ARG CONVERSION??
|
|
||||||
if (o instanceof Lambda) {
|
if (o instanceof Lambda) {
|
||||||
return executeLambdaFunction(state, (Lambda) o);
|
return executeLambdaFunction(state, (Lambda) o);
|
||||||
} else { // o instanceof Method
|
} else { // o instanceof Method
|
||||||
|
@ -66,28 +70,36 @@ public class FunctionReference extends SpelNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Execute a function represented as a java.lang.reflect.Method */
|
/**
|
||||||
|
* Execute a function represented as a java.lang.reflect.Method.
|
||||||
|
*
|
||||||
|
* @param state the expression evaluation state
|
||||||
|
* @param the java method to invoke
|
||||||
|
* @return the return value of the invoked Java method
|
||||||
|
* @throws EvaluationException if there is any problem invoking the method
|
||||||
|
*/
|
||||||
private Object executeFunctionJLRMethod(ExpressionState state, Method m) throws EvaluationException {
|
private Object executeFunctionJLRMethod(ExpressionState state, Method m) throws EvaluationException {
|
||||||
Object[] functionArgs = getArguments(state);
|
Object[] functionArgs = getArguments(state);
|
||||||
if (m.getParameterTypes().length != functionArgs.length) {
|
|
||||||
throw new SpelException(SpelMessages.INCORRECT_NUMBER_OF_ARGUMENTS_TO_FUNCTION, functionArgs.length, m
|
// Only static methods can be called in this way
|
||||||
.getParameterTypes().length);
|
if (!Modifier.isStatic(m.getModifiers())) {
|
||||||
|
throw new SpelException(getCharPositionInLine(),SpelMessages.FUNCTION_MUST_BE_STATIC,m.getDeclaringClass().getName()+"."+m.getName(),name);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if arguments need converting
|
if (functionArgs != null) {
|
||||||
Class<?>[] expectedParams = m.getParameterTypes();
|
EvaluationContext ctx = state.getEvaluationContext();
|
||||||
Object[] argsToPass = new Object[functionArgs.length];
|
TypeConverter converter = null;
|
||||||
TypeConverter converter = state.getEvaluationContext().getTypeUtils().getTypeConverter();
|
if (ctx.getTypeUtils()!=null) {
|
||||||
for (int arg=0; arg<argsToPass.length; arg++) {
|
converter = ctx.getTypeUtils().getTypeConverter();
|
||||||
if (functionArgs[arg]==null || functionArgs[arg].getClass()==expectedParams[arg]) {
|
|
||||||
argsToPass[arg]=functionArgs[arg];
|
|
||||||
} else {
|
|
||||||
argsToPass[arg]=converter.convertValue(functionArgs[arg], expectedParams[arg]);
|
|
||||||
}
|
}
|
||||||
|
ReflectionUtils.convertArguments(m.getParameterTypes(), m.isVarArgs(), converter, functionArgs);
|
||||||
|
}
|
||||||
|
if (m.isVarArgs()) {
|
||||||
|
functionArgs = ReflectionUtils.setupArgumentsForVarargsInvocation(m.getParameterTypes(), functionArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return m.invoke(m.getClass(), argsToPass);
|
return m.invoke(m.getClass(), functionArgs);
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
throw new SpelException(getCharPositionInLine(), e, SpelMessages.EXCEPTION_DURING_FUNCTION_CALL, name, e
|
throw new SpelException(getCharPositionInLine(), e, SpelMessages.EXCEPTION_DURING_FUNCTION_CALL, name, e
|
||||||
.getMessage());
|
.getMessage());
|
||||||
|
|
|
@ -323,16 +323,25 @@ public class StandardTypeConverter implements TypeConverter {
|
||||||
|
|
||||||
private static class ToIntegerConverter implements StandardIndividualTypeConverter {
|
private static class ToIntegerConverter implements StandardIndividualTypeConverter {
|
||||||
public Object convert(Object value) throws SpelException {
|
public Object convert(Object value) throws SpelException {
|
||||||
try {
|
if (value instanceof String) {
|
||||||
return Integer.parseInt(((Long) value).toString());
|
try {
|
||||||
} catch (NumberFormatException nfe) {
|
return Integer.parseInt((String)value);
|
||||||
throw new SpelException(SpelMessages.PROBLEM_DURING_TYPE_CONVERSION, "long value '" + value
|
} catch (NumberFormatException nfe) {
|
||||||
+ "' cannot be represented as an int");
|
throw new SpelException(SpelMessages.PROBLEM_DURING_TYPE_CONVERSION, "cannot parse string '" + value
|
||||||
|
+ "' as an integer");
|
||||||
|
}
|
||||||
|
} else { // Long
|
||||||
|
try {
|
||||||
|
return Integer.parseInt(((Long) value).toString());
|
||||||
|
} catch (NumberFormatException nfe) {
|
||||||
|
throw new SpelException(SpelMessages.PROBLEM_DURING_TYPE_CONVERSION, "long value '" + value
|
||||||
|
+ "' cannot be represented as an int");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Class<?>[] getFrom() {
|
public Class<?>[] getFrom() {
|
||||||
return new Class<?>[] { Long.class };
|
return new Class<?>[] { Long.class, String.class };
|
||||||
}
|
}
|
||||||
|
|
||||||
public Class<?> getTo() {
|
public Class<?> getTo() {
|
||||||
|
|
Loading…
Reference in New Issue