https://issues.apache.org/bugzilla/show_bug.cgi?id=56652

            Bug ID: 56652
           Summary: EL defineFunction does not support method signatures
                    with arrays as arguments
           Product: Tomcat 8
           Version: trunk
          Hardware: PC
            Status: NEW
          Severity: normal
          Priority: P2
         Component: EL
          Assignee: dev@tomcat.apache.org
          Reporter: artfied...@gmail.com

When defineFuncton in ELProcessor is called it uses class.getName() to compare
class names, and the MethodSignature class used to parse the signatures will
return whatever value is defined(in the method signature) as the class name
when its fully qualified. 

So if the method signature is lets say "boolean
sameSize(java.util.Collection[])" defineFunction wont find a matching method on
the provided class, because class.getName() will return
"[Ljava.util.Collection;" instead. 

To get around this I made some tweaks to unqualified type's also to check for
array, and also to always get the correct class name, I changed it to always
get the referenced class then use the getName() function there. 

I added most the functionality to the ImportHandler to reuse the cache and
because it was contently there

Original Code in 8.0.8
[javax.el.ELProcessor- MethodSignature]

ImportHandler importHandler = context.getImportHandler();
for (int i = 0; i < parameterTypeNames.length; i++) {
    parameterTypeNames[i] = parameterTypeNames[i].trim();
    if (!parameterTypeNames[i].contains(".")) {
        Class<?> clazz = importHandler.resolveClass(
                parameterTypeNames[i]);
        if (clazz == null) {
            throw new NoSuchMethodException(Util.message(
                    context,
                    "elProcessor.defineFunctionInvalidParameterTypeName",
                    parameterTypeNames[i], methodName,
                    className));
        }
        parameterTypeNames[i] = clazz.getName();
    }
}

Replaced with:

ImportHandler importHandler = context.getImportHandler();
Class<?> clazz;
for (int i = 0; i < parameterTypeNames.length; i++) {
    clazz = importHandler.extendedResolveClass(parameterTypeNames[i].trim());
    if (clazz == null) {
        throw new NoSuchMethodException(Util.message(
                context,
                "elProcessor.defineFunctionInvalidParameterTypeName",
                parameterTypeNames[i], methodName,
                className));
    }
    parameterTypeNames[i] = clazz.getName();
}


[javax.el.ImportHandler] - Added the following methods

/**
 * This version of Class<?> resolveClass(String name) will allow qualified
names, 
 * handles arrays, and for qualified names will ignore requiring the type is a
public class
 * Note: added to this class to take advantage of the existing cache, and will
cache 
 * original name for qualified names before parsing
 * @param name Classname with or without namespace
 * @return
 */
public java.lang.Class<?> extendedResolveClass(String name) {
    Class<?> result = clazzes.get(name);

    if (result == null) {
        int firstBracketIndex = name.indexOf('[');
        if (name.contains(".")) 
        {
            try {
                if (firstBracketIndex > -1)
                    result = Class.forName(convertArrayClassName(name,
firstBracketIndex));
                else
                    result = Class.forName(name);
            } catch (ClassNotFoundException e) {
                return null;
            }

            Class<?> conflict = clazzes.get(name);

            if (conflict != null) {
                throw new ELException(Util.message(null,
                        "importHandler.ambiguousImport", name,
conflict.getName()));
            }

            clazzes.put(name, result);
        }
        else {
            // Search the package imports - note there may be multiple matches
            // (which correctly triggers an error)
            for (String p : packages) {
                String className = p + '.' + name;
                if (firstBracketIndex > -1) 
                    className = convertArrayClassName(className,
firstBracketIndex);
                result = findClass(className, true);
            }
        }
    }

    return result;
}

/**
 * Converts a class name in the format of java.util.Collection[] to
[Ljava.util.Collection;
 * @param typeName Original class name
 * @param firstBracketIndex position of the first [
 * @return The class name in the format of [LclassName;
 */
private String convertArrayClassName(String typeName, int firstBracketIndex)
{
    final int length = typeName.length();
    StringBuilder sb = new StringBuilder(length + 1); // +1 is to account for
';'
    sb.append('[');
    for(int i = firstBracketIndex + 2; i < length; i++) 
    {
        if (typeName.charAt(i) == '[')
        {
            sb.append('[');
            i++;
        }
    }
    typeName = typeName.substring(0, firstBracketIndex).trim();
    switch(typeName) 
    {
        case "boolean": 
            sb.append('Z');
            break;
        case "byte":
            sb.append('B');
            break;
        case "char":
            sb.append('C');
            break;
        case "double":
            sb.append('D');
            break;
        case "float":
            sb.append('F');
            break;
        case "int":
            sb.append('I');
            break;
        case "long":
            sb.append('J');  
            break;
        case "short":
            sb.append('S');
            break;
        default:
            sb.append('L');
            sb.append(typeName);
            sb.append(';');
            break;
    }
    return sb.toString();
}

-- 
You are receiving this mail because:
You are the assignee for the bug.

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to