You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2013/10/28 22:04:59 UTC

svn commit: r1536524 - in /tomcat/tc7.0.x/trunk: ./ java/javax/el/ArrayELResolver.java java/javax/el/Util.java test/javax/el/TestArrayELResolver.java

Author: markt
Date: Mon Oct 28 21:04:58 2013
New Revision: 1536524

URL: http://svn.apache.org/r1536524
Log:
Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=55691
ArrayELResolver needs to handle the case where the base object is an array of primitives.

Added:
    tomcat/tc7.0.x/trunk/java/javax/el/Util.java
      - copied, changed from r1536520, tomcat/trunk/java/javax/el/Util.java
Modified:
    tomcat/tc7.0.x/trunk/   (props changed)
    tomcat/tc7.0.x/trunk/java/javax/el/ArrayELResolver.java
    tomcat/tc7.0.x/trunk/test/javax/el/TestArrayELResolver.java

Propchange: tomcat/tc7.0.x/trunk/
------------------------------------------------------------------------------
  Merged /tomcat/trunk:r1536520

Modified: tomcat/tc7.0.x/trunk/java/javax/el/ArrayELResolver.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/javax/el/ArrayELResolver.java?rev=1536524&r1=1536523&r2=1536524&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/javax/el/ArrayELResolver.java (original)
+++ tomcat/tc7.0.x/trunk/java/javax/el/ArrayELResolver.java Mon Oct 28 21:04:58 2013
@@ -93,9 +93,8 @@ public class ArrayELResolver extends ELR
 
             int idx = coerce(property);
             checkBounds(base, idx);
-            if (value != null &&
-                    !base.getClass().getComponentType().isAssignableFrom(
-                            value.getClass())) {
+            if (value != null && !Util.isAssignableFrom(value.getClass(),
+                    base.getClass().getComponentType())) {
                 throw new ClassCastException(message(context,
                         "objectNotAssignable",
                         new Object[] {value.getClass().getName(),

Copied: tomcat/tc7.0.x/trunk/java/javax/el/Util.java (from r1536520, tomcat/trunk/java/javax/el/Util.java)
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/javax/el/Util.java?p2=tomcat/tc7.0.x/trunk/java/javax/el/Util.java&p1=tomcat/trunk/java/javax/el/Util.java&r1=1536520&r2=1536524&rev=1536524&view=diff
==============================================================================
--- tomcat/trunk/java/javax/el/Util.java (original)
+++ tomcat/tc7.0.x/trunk/java/javax/el/Util.java Mon Oct 28 21:04:58 2013
@@ -16,424 +16,8 @@
  */
 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;
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
 class Util {
 
-    /**
-     * Checks whether the supplied Throwable is one that needs to be
-     * rethrown and swallows all others.
-     * @param t the Throwable to check
-     */
-    static void handleThrowable(Throwable t) {
-        if (t instanceof ThreadDeath) {
-            throw (ThreadDeath) t;
-        }
-        if (t instanceof VirtualMachineError) {
-            throw (VirtualMachineError) t;
-        }
-        // All other instances of Throwable will be silently swallowed
-    }
-
-
-    static String message(ELContext context, String name, Object... props) {
-        Locale locale = null;
-        if (context != null) {
-            locale = context.getLocale();
-        }
-        if (locale == null) {
-            locale = Locale.getDefault();
-            if (locale == null) {
-                return "";
-            }
-        }
-        ResourceBundle bundle = ResourceBundle.getBundle(
-                "javax.el.LocalStrings", locale);
-        try {
-            String template = bundle.getString(name);
-            if (props != null) {
-                template = MessageFormat.format(template, props);
-            }
-            return template;
-        } catch (MissingResourceException e) {
-            return "Missing Resource: '" + name + "' for Locale "
-                    + locale.getDisplayName();
-        }
-    }
-
-
-    private static final CacheValue nullTcclFactory = new CacheValue();
-    private static final ConcurrentMap<CacheKey, CacheValue> factoryCache =
-            new ConcurrentHashMap<>();
-
-    /**
-     * Provides a per class loader cache of ExpressionFactory instances without
-     * pinning any in memory as that could trigger a memory leak.
-     */
-    static ExpressionFactory getExpressionFactory() {
-
-        ClassLoader tccl = Thread.currentThread().getContextClassLoader();
-        CacheValue cacheValue = null;
-        ExpressionFactory factory = null;
-
-        if (tccl == null) {
-            cacheValue = nullTcclFactory;
-        } else {
-            CacheKey key = new CacheKey(tccl);
-            cacheValue = factoryCache.get(key);
-            if (cacheValue == null) {
-                CacheValue newCacheValue = new CacheValue();
-                cacheValue = factoryCache.putIfAbsent(key, newCacheValue);
-                if (cacheValue == null) {
-                    cacheValue = newCacheValue;
-                }
-            }
-        }
-
-        final Lock readLock = cacheValue.getLock().readLock();
-        readLock.lock();
-        try {
-            factory = cacheValue.getExpressionFactory();
-        } finally {
-            readLock.unlock();
-        }
-
-        if (factory == null) {
-            final Lock writeLock = cacheValue.getLock().writeLock();
-            try {
-                writeLock.lock();
-                factory = cacheValue.getExpressionFactory();
-                if (factory == null) {
-                    factory = ExpressionFactory.newInstance();
-                    cacheValue.setExpressionFactory(factory);
-                }
-            } finally {
-                writeLock.unlock();
-            }
-        }
-
-        return factory;
-    }
-
-
-    /**
-     * Key used to cache default ExpressionFactory information per class
-     * loader. The class loader reference is never {@code null}, because
-     * {@code null} tccl is handled separately.
-     */
-    private static class CacheKey {
-        private final int hash;
-        private final WeakReference<ClassLoader> ref;
-
-        public CacheKey(ClassLoader key) {
-            hash = key.hashCode();
-            ref = new WeakReference<>(key);
-        }
-
-        @Override
-        public int hashCode() {
-            return hash;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (obj == this) {
-                return true;
-            }
-            if (!(obj instanceof CacheKey)) {
-                return false;
-            }
-            ClassLoader thisKey = ref.get();
-            if (thisKey == null) {
-                return false;
-            }
-            return thisKey == ((CacheKey) obj).ref.get();
-        }
-    }
-
-    private static class CacheValue {
-        private final ReadWriteLock lock = new ReentrantReadWriteLock();
-        private WeakReference<ExpressionFactory> ref;
-
-        public CacheValue() {
-        }
-
-        public ReadWriteLock getLock() {
-            return lock;
-        }
-
-        public ExpressionFactory getExpressionFactory() {
-            return ref != null ? ref.get() : null;
-        }
-
-        public void setExpressionFactory(ExpressionFactory factory) {
-            ref = new WeakReference<>(factory);
-        }
-    }
-
-
-    /*
-     * 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.
@@ -470,234 +54,4 @@ class Util {
         }
         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;
-        }
-        Class<?>[] inf = type.getInterfaces();
-        Method mp = null;
-        for (int i = 0; i < inf.length; i++) {
-            try {
-                mp = inf[i].getMethod(m.getName(), m.getParameterTypes());
-                mp = getMethod(mp.getDeclaringClass(), mp);
-                if (mp != null) {
-                    return mp;
-                }
-            } catch (NoSuchMethodException e) {
-                // Ignore
-            }
-        }
-        Class<?> sup = type.getSuperclass();
-        if (sup != null) {
-            try {
-                mp = sup.getMethod(m.getName(), m.getParameterTypes());
-                mp = getMethod(mp.getDeclaringClass(), mp);
-                if (mp != null) {
-                    return mp;
-                }
-            } catch (NoSuchMethodException e) {
-                // Ignore
-            }
-        }
-        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();
-        }
-    }
 }

Modified: tomcat/tc7.0.x/trunk/test/javax/el/TestArrayELResolver.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/test/javax/el/TestArrayELResolver.java?rev=1536524&r1=1536523&r2=1536524&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/test/javax/el/TestArrayELResolver.java (original)
+++ tomcat/tc7.0.x/trunk/test/javax/el/TestArrayELResolver.java Mon Oct 28 21:04:58 2013
@@ -237,6 +237,21 @@ public class TestArrayELResolver {
     }
 
     /**
+     * Tests setting arrays of primitives.
+     * https://issues.apache.org/bugzilla/show_bug.cgi?id=55691
+     */
+    @Test
+    public void testSetValue08() {
+        ArrayELResolver resolver = new ArrayELResolver();
+        ELContext context = new ELContextImpl();
+
+        int[] base = new int[] { 1, 2, 3 };
+        resolver.setValue(context, base, new Integer(1), Integer.valueOf(4));
+
+        Assert.assertEquals(Integer.valueOf(base[1]), Integer.valueOf(4));
+    }
+
+    /**
      * Tests that a null context results in an NPE as per EL Javadoc.
      */
     @Test(expected = NullPointerException.class)



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