Return-Path: X-Original-To: apmail-tomcat-dev-archive@www.apache.org Delivered-To: apmail-tomcat-dev-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id CA8F210886 for ; Fri, 21 Feb 2014 11:43:08 +0000 (UTC) Received: (qmail 9090 invoked by uid 500); 21 Feb 2014 11:43:05 -0000 Delivered-To: apmail-tomcat-dev-archive@tomcat.apache.org Received: (qmail 9019 invoked by uid 500); 21 Feb 2014 11:43:04 -0000 Mailing-List: contact dev-help@tomcat.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: "Tomcat Developers List" Delivered-To: mailing list dev@tomcat.apache.org Received: (qmail 9004 invoked by uid 99); 21 Feb 2014 11:43:03 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 21 Feb 2014 11:43:03 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 21 Feb 2014 11:43:01 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id D3E2D2388868 for ; Fri, 21 Feb 2014 11:42:41 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1570537 - in /tomcat/tc7.0.x/trunk: ./ java/javax/el/Util.java Date: Fri, 21 Feb 2014 11:42:41 -0000 To: dev@tomcat.apache.org From: markt@apache.org X-Mailer: svnmailer-1.0.9 Message-Id: <20140221114241.D3E2D2388868@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org 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 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 wrappers, + String name, Class[] paramTypes, Object[] paramValues) { + + Map candidates = new HashMap(); + + int paramCount; if (paramTypes == null) { paramCount = 0; } else { paramCount = paramTypes.length; } - Method[] methods = clazz.getMethods(); - Map candidates = new HashMap(); - - 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 entry : candidates.entrySet()) { + for (Map.Entry 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 candidates, + private static Wrapper resolveAmbiguousWrapper(Set 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 = ""; - 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 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 wrap(Method[] methods, String name) { + List result = new ArrayList(); + for (Method method : methods) { + if (method.getName().equals(name)) { + result.add(new MethodWrapper(method)); + } + } + return result; + } + + public static List wrap(Constructor[] constructors) { + List 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-unsubscribe@tomcat.apache.org For additional commands, e-mail: dev-help@tomcat.apache.org