SpEL method invocations prefer method with fewest parameters (e.g. no-arg over vararg; SPR-7633)
This commit is contained in:
parent
d78eda8aeb
commit
7553b76f15
|
|
@ -17,17 +17,19 @@
|
||||||
package org.springframework.expression.spel.support;
|
package org.springframework.expression.spel.support;
|
||||||
|
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.util.List;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.core.MethodParameter;
|
||||||
|
import org.springframework.core.convert.TypeDescriptor;
|
||||||
import org.springframework.expression.AccessException;
|
import org.springframework.expression.AccessException;
|
||||||
import org.springframework.expression.ConstructorExecutor;
|
import org.springframework.expression.ConstructorExecutor;
|
||||||
import org.springframework.expression.ConstructorResolver;
|
import org.springframework.expression.ConstructorResolver;
|
||||||
import org.springframework.expression.EvaluationContext;
|
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.core.convert.TypeDescriptor;
|
|
||||||
import org.springframework.core.MethodParameter;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A constructor resolver that uses reflection to locate the constructor that should be invoked
|
* A constructor resolver that uses reflection to locate the constructor that should be invoked
|
||||||
|
|
@ -49,13 +51,24 @@ public class ReflectiveConstructorResolver implements ConstructorResolver {
|
||||||
*/
|
*/
|
||||||
public ConstructorExecutor resolve(EvaluationContext context, String typename, List<TypeDescriptor> argumentTypes)
|
public ConstructorExecutor resolve(EvaluationContext context, String typename, List<TypeDescriptor> argumentTypes)
|
||||||
throws AccessException {
|
throws AccessException {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
TypeConverter typeConverter = context.getTypeConverter();
|
TypeConverter typeConverter = context.getTypeConverter();
|
||||||
Class<?> type = context.getTypeLocator().findType(typename);
|
Class<?> type = context.getTypeLocator().findType(typename);
|
||||||
Constructor[] ctors = type.getConstructors();
|
Constructor[] ctors = type.getConstructors();
|
||||||
|
|
||||||
|
Arrays.sort(ctors, new Comparator<Constructor>() {
|
||||||
|
public int compare(Constructor c1, Constructor c2) {
|
||||||
|
int c1pl = c1.getParameterTypes().length;
|
||||||
|
int c2pl = c2.getParameterTypes().length;
|
||||||
|
return (new Integer(c1pl)).compareTo(c2pl);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Constructor closeMatch = null;
|
Constructor closeMatch = null;
|
||||||
int[] argsToConvert = null;
|
int[] argsToConvert = null;
|
||||||
Constructor matchRequiringConversion = null;
|
Constructor matchRequiringConversion = null;
|
||||||
|
|
||||||
for (Constructor ctor : ctors) {
|
for (Constructor ctor : ctors) {
|
||||||
Class[] paramTypes = ctor.getParameterTypes();
|
Class[] paramTypes = ctor.getParameterTypes();
|
||||||
List<TypeDescriptor> paramDescriptors = new ArrayList<TypeDescriptor>(paramTypes.length);
|
List<TypeDescriptor> paramDescriptors = new ArrayList<TypeDescriptor>(paramTypes.length);
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,8 @@ package org.springframework.expression.spel.support;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
@ -33,11 +35,13 @@ import org.springframework.expression.MethodResolver;
|
||||||
import org.springframework.expression.TypeConverter;
|
import org.springframework.expression.TypeConverter;
|
||||||
import org.springframework.expression.spel.SpelEvaluationException;
|
import org.springframework.expression.spel.SpelEvaluationException;
|
||||||
import org.springframework.expression.spel.SpelMessage;
|
import org.springframework.expression.spel.SpelMessage;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A method resolver that uses reflection to locate the method that should be invoked.
|
* A method resolver that uses reflection to locate the method that should be invoked.
|
||||||
*
|
*
|
||||||
* @author Andy Clement
|
* @author Andy Clement
|
||||||
|
* @author Juergen Hoeller
|
||||||
* @since 3.0
|
* @since 3.0
|
||||||
*/
|
*/
|
||||||
public class ReflectiveMethodResolver implements MethodResolver {
|
public class ReflectiveMethodResolver implements MethodResolver {
|
||||||
|
|
@ -58,20 +62,21 @@ public class ReflectiveMethodResolver implements MethodResolver {
|
||||||
*/
|
*/
|
||||||
public MethodExecutor resolve(EvaluationContext context, Object targetObject, String name,
|
public MethodExecutor resolve(EvaluationContext context, Object targetObject, String name,
|
||||||
List<TypeDescriptor> argumentTypes) throws AccessException {
|
List<TypeDescriptor> argumentTypes) throws AccessException {
|
||||||
|
|
||||||
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 = type.getMethods();
|
||||||
|
|
||||||
// If a filter is registered for this type, call it
|
// If a filter is registered for this type, call it
|
||||||
MethodFilter methodfilter = (filters==null?null:filters.get(type));
|
MethodFilter filter = (this.filters != null ? this.filters.get(type) : null);
|
||||||
if (methodfilter!=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 = methodfilter.filter(methodsForFiltering);
|
List<Method> methodsFiltered = filter.filter(methodsForFiltering);
|
||||||
if (methodsFiltered == null || methodsFiltered.size()==0) {
|
if (CollectionUtils.isEmpty(methodsFiltered)) {
|
||||||
methods = NO_METHODS;
|
methods = NO_METHODS;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -79,10 +84,19 @@ public class ReflectiveMethodResolver implements MethodResolver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Arrays.sort(methods, new Comparator<Method>() {
|
||||||
|
public int compare(Method m1, Method m2) {
|
||||||
|
int m1pl = m1.getParameterTypes().length;
|
||||||
|
int m2pl = m2.getParameterTypes().length;
|
||||||
|
return (new Integer(m1pl)).compareTo(m2pl);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Method closeMatch = null;
|
Method closeMatch = null;
|
||||||
int[] argsToConvert = null;
|
int[] argsToConvert = null;
|
||||||
boolean multipleOptions = false;
|
|
||||||
Method matchRequiringConversion = null;
|
Method matchRequiringConversion = null;
|
||||||
|
boolean multipleOptions = false;
|
||||||
|
|
||||||
for (Method method : methods) {
|
for (Method method : methods) {
|
||||||
if (method.isBridge()) {
|
if (method.isBridge()) {
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -139,7 +153,7 @@ public class ReflectiveMethodResolver implements MethodResolver {
|
||||||
|
|
||||||
public void registerMethodFilter(Class<?> type, MethodFilter filter) {
|
public void registerMethodFilter(Class<?> type, MethodFilter filter) {
|
||||||
if (this.filters == null) {
|
if (this.filters == null) {
|
||||||
this.filters = new HashMap<Class<?>,MethodFilter>();
|
this.filters = new HashMap<Class<?>, MethodFilter>();
|
||||||
}
|
}
|
||||||
if (filter == null) {
|
if (filter == null) {
|
||||||
this.filters.remove(type);
|
this.filters.remove(type);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue