Author: markt Date: Fri Feb 21 11:42:41 2014 New Revision: 1570537 URL: http://svn.apache.org/r1570537 Log: Back-port the remainder of fix for https://issues.apache.org/bugzilla/show_bug.cgi?id=55483 Handle overloaded constructors. As far as the constructor matching code is concerned, constructors can be treated as methods with a special name. Therefore, refactor the newly enhanced method matching code to handle methods or constructors and then use it to replace the current simplistic constructor matching.
Modified: tomcat/tc7.0.x/trunk/ (props changed) tomcat/tc7.0.x/trunk/java/javax/el/Util.java Propchange: tomcat/tc7.0.x/trunk/ ------------------------------------------------------------------------------ Merged /tomcat/trunk:r1518381 Modified: tomcat/tc7.0.x/trunk/java/javax/el/Util.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/javax/el/Util.java?rev=1570537&r1=1570536&r2=1570537&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/javax/el/Util.java (original) +++ tomcat/tc7.0.x/trunk/java/javax/el/Util.java Fri Feb 21 11:42:41 2014 @@ -22,7 +22,9 @@ 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; @@ -192,7 +194,6 @@ class Util { * This method duplicates code in org.apache.el.util.ReflectionUtil. When * making changes keep the code in sync. */ - @SuppressWarnings("null") static Method findMethod(Class<?> clazz, String methodName, Class<?>[] paramTypes, Object[] paramValues) { @@ -202,27 +203,42 @@ class Util { paramString(paramTypes))); } - int paramCount; 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<Wrapper,Integer>(); + + int paramCount; if (paramTypes == null) { paramCount = 0; } else { paramCount = paramTypes.length; } - Method[] methods = clazz.getMethods(); - Map<Method,Integer> candidates = new HashMap<Method,Integer>(); - - for (Method m : methods) { - if (!m.getName().equals(methodName)) { - // Method name doesn't match - continue; - } - - Class<?>[] mParamTypes = m.getParameterTypes(); + for (Wrapper w : wrappers) { + Class<?>[] mParamTypes = w.getParameterTypes(); int mParamCount; if (mParamTypes == null) { mParamCount = 0; @@ -232,7 +248,7 @@ class Util { // Check the number of parameters if (!(paramCount == mParamCount || - (m.isVarArgs() && paramCount >= mParamCount))) { + (w.isVarArgs() && paramCount >= mParamCount))) { // Method has wrong number of parameters continue; } @@ -244,7 +260,7 @@ class Util { // Can't be null if (mParamTypes[i].equals(paramTypes[i])) { exactMatch++; - } else if (i == (mParamCount - 1) && m.isVarArgs()) { + } else if (i == (mParamCount - 1) && w.isVarArgs()) { Class<?> varType = mParamTypes[i].getComponentType(); for (int j = i; j < paramCount; j++) { if (!isAssignableFrom(paramTypes[j], varType)) { @@ -281,18 +297,18 @@ class Util { // If a method is found where every parameter matches exactly, // return it if (exactMatch == paramCount) { - return getMethod(clazz, m); + return w; } - candidates.put(m, Integer.valueOf(exactMatch)); + 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; - Method match = null; + Wrapper match = null; boolean multiple = false; - for (Map.Entry<Method, Integer> entry : candidates.entrySet()) { + for (Map.Entry<Wrapper, Integer> entry : candidates.entrySet()) { if (entry.getValue().intValue() > bestMatch || match == null) { bestMatch = entry.getValue().intValue(); @@ -306,7 +322,7 @@ class Util { if (bestMatch == paramCount - 1) { // Only one parameter is not an exact match - try using the // super class - match = resolveAmbiguousMethod(candidates.keySet(), paramTypes); + match = resolveAmbiguousWrapper(candidates.keySet(), paramTypes); } else { match = null; } @@ -315,7 +331,7 @@ class Util { // 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, methodName, + null, "util.method.ambiguous", clazz, name, paramString(paramTypes))); } } @@ -323,11 +339,11 @@ class Util { // Handle case where no match at all was found if (match == null) { throw new MethodNotFoundException(message( - null, "util.method.notfound", clazz, methodName, + null, "util.method.notfound", clazz, name, paramString(paramTypes))); } - return getMethod(clazz, match); + return match; } @@ -351,19 +367,19 @@ class Util { /* - * This class duplicates code in org.apache.el.util.ReflectionUtil. When + * This method duplicates code in org.apache.el.util.ReflectionUtil. When * making changes keep the code in sync. */ - private static Method resolveAmbiguousMethod(Set<Method> candidates, + private static Wrapper resolveAmbiguousWrapper(Set<Wrapper> candidates, Class<?>[] paramTypes) { // Identify which parameter isn't an exact match - Method m = candidates.iterator().next(); + Wrapper w = candidates.iterator().next(); int nonMatchIndex = 0; Class<?> nonMatchClass = null; for (int i = 0; i < paramTypes.length; i++) { - if (m.getParameterTypes()[i] != paramTypes[i]) { + if (w.getParameterTypes()[i] != paramTypes[i]) { nonMatchIndex = i; nonMatchClass = paramTypes[i]; break; @@ -375,7 +391,7 @@ class Util { return null; } - for (Method c : candidates) { + for (Wrapper c : candidates) { if (c.getParameterTypes()[nonMatchIndex] == paramTypes[nonMatchIndex]) { // Methods have different non-matching parameters @@ -387,7 +403,7 @@ class Util { // Can't be null Class<?> superClass = nonMatchClass.getSuperclass(); while (superClass != null) { - for (Method c : candidates) { + for (Wrapper c : candidates) { if (c.getParameterTypes()[nonMatchIndex].equals(superClass)) { // Found a match return c; @@ -397,9 +413,9 @@ class Util { } // Treat instances of Number as a special case - Method match = null; + Wrapper match = null; if (Number.class.isAssignableFrom(nonMatchClass)) { - for (Method c : candidates) { + for (Wrapper c : candidates) { Class<?> candidateType = c.getParameterTypes()[nonMatchIndex]; if (Number.class.isAssignableFrom(candidateType) || candidateType.isPrimitive()) { @@ -419,7 +435,7 @@ class Util { /* - * This class duplicates code in org.apache.el.util.ReflectionUtil. When + * This method duplicates code in org.apache.el.util.ReflectionUtil. When * making changes keep the code in sync. */ static boolean isAssignableFrom(Class<?> src, Class<?> target) { @@ -457,7 +473,7 @@ class Util { /* - * This class duplicates code in org.apache.el.util.ReflectionUtil. When + * 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) { @@ -490,7 +506,7 @@ class Util { /* - * This class duplicates code in org.apache.el.util.ReflectionUtil. When + * 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) { @@ -526,43 +542,32 @@ class Util { } - static Constructor<?> findConstructor(Object base, Class<?>[] paramTypes, - Object[] params) { + static Constructor<?> findConstructor(Class<?> clazz, Class<?>[] paramTypes, + Object[] paramValues) { - Constructor<?> match = null; + String methodName = "<init>"; - Class<?> clazz = base.getClass(); - if (paramTypes != null) { - try { - match = getConstructor(clazz, clazz.getConstructor(paramTypes)); - } catch (NoSuchMethodException e) { - throw new MethodNotFoundException(e); - } - } else { - int paramCount = 0; - if (params != null) { - paramCount = params.length; - } - Constructor<?>[] constructors = clazz.getConstructors(); - for (Constructor<?> c : constructors) { - if (c.getParameterTypes().length == paramCount) { - // Same number of parameters - use the first match - match = getConstructor(clazz, c); - break; - } - if (c.isVarArgs() - && paramCount > c.getParameterTypes().length - 2) { - match = getConstructor(clazz, c); - } - } - if (match == null) { - throw new MethodNotFoundException( - "Unable to find constructor with [" + paramCount + - "] parameters"); - } + if (clazz == null) { + throw new MethodNotFoundException( + message(null, "util.method.notfound", clazz, methodName, + paramString(paramTypes))); } - return match; + 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()); } @@ -622,4 +627,77 @@ class Util { } return parameters; } + + + private abstract static class Wrapper { + + public static List<Wrapper> wrap(Method[] methods, String name) { + List<Wrapper> result = new ArrayList<Wrapper>(); + 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<Wrapper>(); + 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