Author: markt Date: Tue Sep 17 11:33:26 2013 New Revision: 1523988 URL: http://svn.apache.org/r1523988 Log: Use java.beans.Expression to simplify method and constructor matching/execution. Approach suggested by Esmond Pitt.
Modified: tomcat/trunk/java/javax/el/BeanELResolver.java tomcat/trunk/java/javax/el/StaticFieldELResolver.java tomcat/trunk/java/javax/el/Util.java Modified: tomcat/trunk/java/javax/el/BeanELResolver.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/javax/el/BeanELResolver.java?rev=1523988&r1=1523987&r2=1523988&view=diff ============================================================================== --- tomcat/trunk/java/javax/el/BeanELResolver.java (original) +++ tomcat/trunk/java/javax/el/BeanELResolver.java Tue Sep 17 11:33:26 2013 @@ -166,16 +166,16 @@ public class BeanELResolver extends ELRe String methodName = (String) factory.coerceToType(method, String.class); - // Find the matching method - Method matchingMethod = - Util.findMethod(base.getClass(), methodName, paramTypes, params); - - Object[] parameters = Util.buildParameters( - matchingMethod.getParameterTypes(), matchingMethod.isVarArgs(), - params); + java.beans.Expression beanExpression = + new java.beans.Expression(base, methodName, params); - Object result = null; + Object result; try { + result = beanExpression.getValue(); + } catch (Exception e) { + throw new ELException(e); + } +/* try { result = matchingMethod.invoke(base, parameters); } catch (IllegalArgumentException | IllegalAccessException e) { throw new ELException(e); @@ -184,7 +184,7 @@ public class BeanELResolver extends ELRe Util.handleThrowable(cause); throw new ELException(cause); } - +*/ context.setPropertyResolved(base, method); return result; } Modified: tomcat/trunk/java/javax/el/StaticFieldELResolver.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/javax/el/StaticFieldELResolver.java?rev=1523988&r1=1523987&r2=1523988&view=diff ============================================================================== --- tomcat/trunk/java/javax/el/StaticFieldELResolver.java (original) +++ tomcat/trunk/java/javax/el/StaticFieldELResolver.java Tue Sep 17 11:33:26 2013 @@ -17,10 +17,7 @@ package javax.el; import java.beans.FeatureDescriptor; -import java.lang.reflect.Constructor; import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Iterator; @@ -92,61 +89,29 @@ public class StaticFieldELResolver exten throw new NullPointerException(); } + Object result = null; + if (base instanceof ELClass && method instanceof String) { context.setPropertyResolved(base, method); - Class<?> clazz = ((ELClass) base).getKlass(); String methodName = (String) method; - if ("<init>".equals(methodName)) { - Constructor<?> match = - Util.findConstructor(clazz, paramTypes, params); - - Object[] parameters = Util.buildParameters( - match.getParameterTypes(), match.isVarArgs(), params); - - Object result = null; - - try { - result = match.newInstance(parameters); - } catch (IllegalArgumentException | IllegalAccessException | - InstantiationException e) { - throw new ELException(e); - } catch (InvocationTargetException e) { - Throwable cause = e.getCause(); - Util.handleThrowable(cause); - throw new ELException(cause); - } - return result; - - } else { - Method match = - Util.findMethod(clazz, methodName, paramTypes, params); - - int modifiers = match.getModifiers(); - if (!Modifier.isStatic(modifiers)) { - throw new MethodNotFoundException(Util.message(context, - "staticFieldELResolver.methodNotFound", methodName, - clazz.getName())); - } + // java.beans.Expression uses 'new' for constructors + methodName = "new"; + } + Class<?> clazz = ((ELClass) base).getKlass(); - Object[] parameters = Util.buildParameters( - match.getParameterTypes(), match.isVarArgs(), params); + java.beans.Expression beanExpression = + new java.beans.Expression(clazz, methodName, params); - Object result = null; - try { - result = match.invoke(null, parameters); - } catch (IllegalArgumentException | IllegalAccessException e) { - throw new ELException(e); - } catch (InvocationTargetException e) { - Throwable cause = e.getCause(); - Util.handleThrowable(cause); - throw new ELException(cause); - } - return result; + try { + result = beanExpression.getValue(); + } catch (Exception e) { + throw new ELException(e); } } - return null; + + return result; } @Override Modified: tomcat/trunk/java/javax/el/Util.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/javax/el/Util.java?rev=1523988&r1=1523987&r2=1523988&view=diff ============================================================================== --- tomcat/trunk/java/javax/el/Util.java (original) +++ tomcat/trunk/java/javax/el/Util.java Tue Sep 17 11:33:26 2013 @@ -17,19 +17,12 @@ package javax.el; import java.lang.ref.WeakReference; -import java.lang.reflect.Array; -import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; import java.util.Locale; -import java.util.Map; import java.util.MissingResourceException; import java.util.ResourceBundle; -import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.locks.Lock; @@ -194,321 +187,6 @@ class Util { * This method duplicates code in org.apache.el.util.ReflectionUtil. When * making changes keep the code in sync. */ - static Method findMethod(Class<?> clazz, String methodName, - Class<?>[] paramTypes, Object[] paramValues) { - - if (clazz == null || methodName == null) { - throw new MethodNotFoundException( - message(null, "util.method.notfound", clazz, methodName, - paramString(paramTypes))); - } - - if (paramTypes == null) { - paramTypes = getTypesFromValues(paramValues); - } - - Method[] methods = clazz.getMethods(); - - List<Wrapper> wrappers = Wrapper.wrap(methods, methodName); - - Wrapper result = findWrapper( - clazz, wrappers, methodName, paramTypes, paramValues); - - if (result == null) { - return null; - } - return getMethod(clazz, (Method) result.unWrap()); - } - - /* - * This method duplicates code in org.apache.el.util.ReflectionUtil. When - * making changes keep the code in sync. - */ - @SuppressWarnings("null") - private static Wrapper findWrapper(Class<?> clazz, List<Wrapper> wrappers, - String name, Class<?>[] paramTypes, Object[] paramValues) { - - Map<Wrapper,Integer> candidates = new HashMap<>(); - - int paramCount; - if (paramTypes == null) { - paramCount = 0; - } else { - paramCount = paramTypes.length; - } - - for (Wrapper w : wrappers) { - Class<?>[] mParamTypes = w.getParameterTypes(); - int mParamCount; - if (mParamTypes == null) { - mParamCount = 0; - } else { - mParamCount = mParamTypes.length; - } - - // Check the number of parameters - if (!(paramCount == mParamCount || - (w.isVarArgs() && paramCount >= mParamCount))) { - // Method has wrong number of parameters - continue; - } - - // Check the parameters match - int exactMatch = 0; - boolean noMatch = false; - for (int i = 0; i < mParamCount; i++) { - // Can't be null - if (mParamTypes[i].equals(paramTypes[i])) { - exactMatch++; - } else if (i == (mParamCount - 1) && w.isVarArgs()) { - Class<?> varType = mParamTypes[i].getComponentType(); - for (int j = i; j < paramCount; j++) { - if (!isAssignableFrom(paramTypes[j], varType)) { - if (paramValues == null) { - noMatch = true; - break; - } else { - if (!isCoercibleFrom(paramValues[j], varType)) { - noMatch = true; - break; - } - } - } - // Don't treat a varArgs match as an exact match, it can - // lead to a varArgs method matching when the result - // should be ambiguous - } - } else if (!isAssignableFrom(paramTypes[i], mParamTypes[i])) { - if (paramValues == null) { - noMatch = true; - break; - } else { - if (!isCoercibleFrom(paramValues[i], mParamTypes[i])) { - noMatch = true; - break; - } - } - } - } - if (noMatch) { - continue; - } - - // If a method is found where every parameter matches exactly, - // return it - if (exactMatch == paramCount) { - return w; - } - - candidates.put(w, Integer.valueOf(exactMatch)); - } - - // Look for the method that has the highest number of parameters where - // the type matches exactly - int bestMatch = 0; - Wrapper match = null; - boolean multiple = false; - for (Map.Entry<Wrapper, Integer> entry : candidates.entrySet()) { - if (entry.getValue().intValue() > bestMatch || - match == null) { - bestMatch = entry.getValue().intValue(); - match = entry.getKey(); - multiple = false; - } else if (entry.getValue().intValue() == bestMatch) { - multiple = true; - } - } - if (multiple) { - if (bestMatch == paramCount - 1) { - // Only one parameter is not an exact match - try using the - // super class - match = resolveAmbiguousWrapper(candidates.keySet(), paramTypes); - } else { - match = null; - } - - if (match == null) { - // If multiple methods have the same matching number of parameters - // the match is ambiguous so throw an exception - throw new MethodNotFoundException(message( - null, "util.method.ambiguous", clazz, name, - paramString(paramTypes))); - } - } - - // Handle case where no match at all was found - if (match == null) { - throw new MethodNotFoundException(message( - null, "util.method.notfound", clazz, name, - paramString(paramTypes))); - } - - return match; - } - - - private static final String paramString(Class<?>[] types) { - if (types != null) { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < types.length; i++) { - if (types[i] == null) { - sb.append("null, "); - } else { - sb.append(types[i].getName()).append(", "); - } - } - if (sb.length() > 2) { - sb.setLength(sb.length() - 2); - } - return sb.toString(); - } - return null; - } - - - /* - * This method duplicates code in org.apache.el.util.ReflectionUtil. When - * making changes keep the code in sync. - */ - private static Wrapper resolveAmbiguousWrapper(Set<Wrapper> candidates, - Class<?>[] paramTypes) { - // Identify which parameter isn't an exact match - Wrapper w = candidates.iterator().next(); - - int nonMatchIndex = 0; - Class<?> nonMatchClass = null; - - for (int i = 0; i < paramTypes.length; i++) { - if (w.getParameterTypes()[i] != paramTypes[i]) { - nonMatchIndex = i; - nonMatchClass = paramTypes[i]; - break; - } - } - - if (nonMatchClass == null) { - // Null will always be ambiguous - return null; - } - - for (Wrapper c : candidates) { - if (c.getParameterTypes()[nonMatchIndex] == - paramTypes[nonMatchIndex]) { - // Methods have different non-matching parameters - // Result is ambiguous - return null; - } - } - - // Can't be null - Class<?> superClass = nonMatchClass.getSuperclass(); - while (superClass != null) { - for (Wrapper c : candidates) { - if (c.getParameterTypes()[nonMatchIndex].equals(superClass)) { - // Found a match - return c; - } - } - superClass = superClass.getSuperclass(); - } - - // Treat instances of Number as a special case - Wrapper match = null; - if (Number.class.isAssignableFrom(nonMatchClass)) { - for (Wrapper c : candidates) { - Class<?> candidateType = c.getParameterTypes()[nonMatchIndex]; - if (Number.class.isAssignableFrom(candidateType) || - candidateType.isPrimitive()) { - if (match == null) { - match = c; - } else { - // Match still ambiguous - match = null; - break; - } - } - } - } - - return match; - } - - - /* - * This method duplicates code in org.apache.el.util.ReflectionUtil. When - * making changes keep the code in sync. - */ - private static boolean isAssignableFrom(Class<?> src, Class<?> target) { - // src will always be an object - // Short-cut. null is always assignable to an object and in EL null - // can always be coerced to a valid value for a primitive - if (src == null) { - return true; - } - - Class<?> targetClass; - if (target.isPrimitive()) { - if (target == Boolean.TYPE) { - targetClass = Boolean.class; - } else if (target == Character.TYPE) { - targetClass = Character.class; - } else if (target == Byte.TYPE) { - targetClass = Byte.class; - } else if (target == Short.TYPE) { - targetClass = Short.class; - } else if (target == Integer.TYPE) { - targetClass = Integer.class; - } else if (target == Long.TYPE) { - targetClass = Long.class; - } else if (target == Float.TYPE) { - targetClass = Float.class; - } else { - targetClass = Double.class; - } - } else { - targetClass = target; - } - return targetClass.isAssignableFrom(src); - } - - - /* - * This method duplicates code in org.apache.el.util.ReflectionUtil. When - * making changes keep the code in sync. - */ - private static boolean isCoercibleFrom(Object src, Class<?> target) { - // TODO: This isn't pretty but it works. Significant refactoring would - // be required to avoid the exception. - try { - getExpressionFactory().coerceToType(src, target); - } catch (ELException e) { - return false; - } - return true; - } - - - private static Class<?>[] getTypesFromValues(Object[] values) { - if (values == null) { - return null; - } - - Class<?> result[] = new Class<?>[values.length]; - for (int i = 0; i < values.length; i++) { - if (values[i] == null) { - result[i] = null; - } else { - result[i] = values[i].getClass(); - } - } - return result; - } - - - /* - * This method duplicates code in org.apache.el.util.ReflectionUtil. When - * making changes keep the code in sync. - */ static Method getMethod(Class<?> type, Method m) { if (m == null || Modifier.isPublic(type.getModifiers())) { return m; @@ -540,164 +218,4 @@ class Util { } return null; } - - - static Constructor<?> findConstructor(Class<?> clazz, Class<?>[] paramTypes, - Object[] paramValues) { - - String methodName = "<init>"; - - if (clazz == null) { - throw new MethodNotFoundException( - message(null, "util.method.notfound", clazz, methodName, - paramString(paramTypes))); - } - - if (paramTypes == null) { - paramTypes = getTypesFromValues(paramValues); - } - - Constructor<?>[] constructors = clazz.getConstructors(); - - List<Wrapper> wrappers = Wrapper.wrap(constructors); - - Wrapper result = findWrapper( - clazz, wrappers, methodName, paramTypes, paramValues); - - if (result == null) { - return null; - } - return getConstructor(clazz, (Constructor<?>) result.unWrap()); - } - - - static Constructor<?> getConstructor(Class<?> type, Constructor<?> c) { - if (c == null || Modifier.isPublic(type.getModifiers())) { - return c; - } - Constructor<?> cp = null; - Class<?> sup = type.getSuperclass(); - if (sup != null) { - try { - cp = sup.getConstructor(c.getParameterTypes()); - cp = getConstructor(cp.getDeclaringClass(), cp); - if (cp != null) { - return cp; - } - } catch (NoSuchMethodException e) { - // Ignore - } - } - return null; - } - - - static Object[] buildParameters(Class<?>[] parameterTypes, - boolean isVarArgs,Object[] params) { - ExpressionFactory factory = getExpressionFactory(); - Object[] parameters = null; - if (parameterTypes.length > 0) { - parameters = new Object[parameterTypes.length]; - int paramCount = params.length; - if (isVarArgs) { - int varArgIndex = parameterTypes.length - 1; - // First argCount-1 parameters are standard - for (int i = 0; (i < varArgIndex); i++) { - parameters[i] = factory.coerceToType(params[i], - parameterTypes[i]); - } - // Last parameter is the varargs - Class<?> varArgClass = - parameterTypes[varArgIndex].getComponentType(); - final Object varargs = Array.newInstance( - varArgClass, - (paramCount - varArgIndex)); - for (int i = (varArgIndex); i < paramCount; i++) { - Array.set(varargs, i - varArgIndex, - factory.coerceToType(params[i], varArgClass)); - } - parameters[varArgIndex] = varargs; - } else { - parameters = new Object[parameterTypes.length]; - for (int i = 0; i < parameterTypes.length; i++) { - parameters[i] = factory.coerceToType(params[i], - parameterTypes[i]); - } - } - } - return parameters; - } - - - private abstract static class Wrapper { - - public static List<Wrapper> wrap(Method[] methods, String name) { - List<Wrapper> result = new ArrayList<>(); - for (Method method : methods) { - if (method.getName().equals(name)) { - result.add(new MethodWrapper(method)); - } - } - return result; - } - - public static List<Wrapper> wrap(Constructor<?>[] constructors) { - List<Wrapper> result = new ArrayList<>(); - for (Constructor<?> constructor : constructors) { - result.add(new ConstructorWrapper(constructor)); - } - return result; - } - - public abstract Object unWrap(); - public abstract Class<?>[] getParameterTypes(); - public abstract boolean isVarArgs(); - } - - - private static class MethodWrapper extends Wrapper { - private final Method m; - - public MethodWrapper(Method m) { - this.m = m; - } - - @Override - public Object unWrap() { - return m; - } - - @Override - public Class<?>[] getParameterTypes() { - return m.getParameterTypes(); - } - - @Override - public boolean isVarArgs() { - return m.isVarArgs(); - } - } - - private static class ConstructorWrapper extends Wrapper { - private final Constructor<?> c; - - public ConstructorWrapper(Constructor<?> c) { - this.c = c; - } - - @Override - public Object unWrap() { - return c; - } - - @Override - public Class<?>[] getParameterTypes() { - return c.getParameterTypes(); - } - - @Override - public boolean isVarArgs() { - return c.isVarArgs(); - } - } } --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org