ttomcat-1778514358873.zip-extract/apache-tomcat-11.0.18-src/java/jakarta/el/Util.java

Path
ttomcat-1778514358873.zip-extract/apache-tomcat-11.0.18-src/java/jakarta/el/Util.java
Status
scanned
Type
file
Name
Util.java
Extension
.java
Programming language
Java
Mime type
text/plain
File type
ASCII text, with CRLF line terminators
Tag

      
    
Rootfs path

      
    
Size
26478 (25.9 KB)
MD5
fef321f82f476a23a30d9aadf8611470
SHA1
02e9b8cca06bc4cb9a8d3bb1e23ddd56c1bf300a
SHA256
3353ab0f022fdd07f7663a9ed785ff8251f58c725d7913aae94e24264ede9ad9
SHA512

      
    
SHA1_git
dcb1ce7c39589c6183dfe3c1551bb1e4d3423f28
Is binary

      
    
Is text
True
Is archive

      
    
Is media

      
    
Is legal

      
    
Is manifest

      
    
Is readme

      
    
Is top level

      
    
Is key file

      
    
Util.java | 25.9 KB |

/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jakarta.el; import java.lang.reflect.AccessibleObject; 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; class Util { private static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0]; private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0]; /** * 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 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("jakarta.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 ExpressionFactoryCache factoryCache = new ExpressionFactoryCache(); /** * 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(); return factoryCache.getOrCreateExpressionFactory(tccl); } /* * This method duplicates code in org.apache.el.util.ReflectionUtil. When making changes keep the code in sync. */ static Method findMethod(ELContext context, Class<?> clazz, Object base, 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); } // Fast path: when no arguments exist, there can only be one matching method and no need for coercion. if (paramTypes.length == 0) { try { Method method = clazz.getMethod(methodName, paramTypes); return getMethod(clazz, base, method); } catch (NoSuchMethodException | SecurityException ignore) { // Fall through to broader, slower logic } } Method[] methods = clazz.getMethods(); List<Wrapper<Method>> wrappers = Wrapper.wrap(methods, methodName); Wrapper<Method> result = findWrapper(context, clazz, wrappers, methodName, paramTypes, paramValues); return getMethod(clazz, base, result.unWrap()); } /* * This method duplicates code in org.apache.el.util.ReflectionUtil. When making changes keep the code in sync. */ @SuppressWarnings("null") private static <T> Wrapper<T> findWrapper(ELContext context, Class<?> clazz, List<Wrapper<T>> wrappers, String name, Class<?>[] paramTypes, Object[] paramValues) { Map<Wrapper<T>,MatchResult> candidates = new HashMap<>(); int paramCount = paramTypes.length; for (Wrapper<T> w : wrappers) { Class<?>[] mParamTypes = w.getParameterTypes(); int mParamCount; if (mParamTypes == null) { mParamCount = 0; } else { mParamCount = mParamTypes.length; } // Check the number of parameters // Multiple tests to improve readability if (!w.isVarArgs() && paramCount != mParamCount) { // Method has wrong number of parameters continue; } if (w.isVarArgs() && paramCount < mParamCount - 1) { // Method has wrong number of parameters continue; } if (w.isVarArgs() && paramCount == mParamCount && paramValues != null && paramValues.length > paramCount && !paramTypes[mParamCount - 1].isArray()) { // Method arguments don't match continue; } if (w.isVarArgs() && paramCount > mParamCount && paramValues != null && paramValues.length != paramCount) { // Might match a different varargs method continue; } if (!w.isVarArgs() && paramValues != null && paramCount != paramValues.length) { // Might match a different varargs method continue; } // Check the parameters match int exactMatch = 0; int assignableMatch = 0; int coercibleMatch = 0; int varArgsMatch = 0; boolean noMatch = false; for (int i = 0; i < mParamCount; i++) { // Can't be null if (w.isVarArgs() && i == (mParamCount - 1)) { if (i == paramCount || (paramValues != null && paramValues.length == i)) { // Var args defined but nothing is passed as varargs // Use MAX_VALUE so this matches only if nothing else does varArgsMatch = Integer.MAX_VALUE; break; } Class<?> varType = mParamTypes[i].getComponentType(); for (int j = i; j < paramCount; j++) { if (isAssignableFrom(paramTypes[j], varType)) { assignableMatch++; varArgsMatch++; } else { if (paramValues == null) { noMatch = true; break; } else { if (isCoercibleFrom(context, paramValues[j], varType)) { coercibleMatch++; varArgsMatch++; } else { 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 (mParamTypes[i].equals(paramTypes[i])) { exactMatch++; } else if (paramTypes[i] != null && isAssignableFrom(paramTypes[i], mParamTypes[i])) { assignableMatch++; } else { if (paramValues == null) { noMatch = true; break; } else { if (isCoercibleFrom(context, paramValues[i], mParamTypes[i])) { coercibleMatch++; } else { noMatch = true; break; } } } } } if (noMatch) { continue; } // If a method is found where every parameter matches exactly, // and no vars args are present, return it if (exactMatch == paramCount && varArgsMatch == 0) { return w; } candidates.put(w, new MatchResult(w.isVarArgs(), exactMatch, assignableMatch, coercibleMatch, varArgsMatch, w.isBridge())); } // Look for the method that has the highest number of parameters where // the type matches exactly MatchResult bestMatch = new MatchResult(true, 0, 0, 0, 0, true); Wrapper<T> match = null; boolean multiple = false; for (Map.Entry<Wrapper<T>,MatchResult> entry : candidates.entrySet()) { int cmp = entry.getValue().compareTo(bestMatch); if (cmp > 0 || match == null) { bestMatch = entry.getValue(); match = entry.getKey(); multiple = false; } else if (cmp == 0) { multiple = true; } } if (multiple) { if (bestMatch.getExactCount() == 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 String paramString(Class<?>[] types) { if (types != null) { StringBuilder sb = new StringBuilder(); for (Class<?> type : types) { if (type == null) { sb.append("null, "); } else { sb.append(type.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 <T> Wrapper<T> resolveAmbiguousWrapper(Set<Wrapper<T>> candidates, Class<?>[] paramTypes) { // Identify which parameter isn't an exact match Wrapper<T> 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<T> 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<T> 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<T> match = null; if (Number.class.isAssignableFrom(nonMatchClass)) { for (Wrapper<T> 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. */ 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(ELContext context, Object src, Class<?> target) { /* * TODO: This isn't pretty but it works. Significant refactoring would be required to avoid the exception. See * also OptionalELResolver.convertToType(). */ try { context.convertToType(src, target); } catch (ELException e) { return false; } return true; } private static Class<?>[] getTypesFromValues(Object[] values) { if (values == null) { return EMPTY_CLASS_ARRAY; } 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, Object base, Method m) { if (m == null || (Modifier.isPublic(type.getModifiers()) && (Modifier.isStatic(m.getModifiers()) && canAccess(null, m) || canAccess(base, m)))) { return m; } Class<?>[] interfaces = type.getInterfaces(); Method mp; for (Class<?> iface : interfaces) { try { mp = iface.getMethod(m.getName(), m.getParameterTypes()); mp = getMethod(mp.getDeclaringClass(), base, 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(), base, mp); if (mp != null) { return mp; } } catch (NoSuchMethodException e) { // Ignore } } return null; } static Constructor<?> findConstructor(ELContext context, Class<?> clazz, Class<?>[] paramTypes, Object[] paramValues) { String methodName = "<init>"; if (clazz == null) { throw new MethodNotFoundException( message(null, "util.method.notfound", null, methodName, paramString(paramTypes))); } if (paramTypes == null) { paramTypes = getTypesFromValues(paramValues); } Constructor<?>[] constructors = clazz.getConstructors(); List<Wrapper<Constructor<?>>> wrappers = Wrapper.wrap(constructors); Wrapper<Constructor<?>> wrapper = findWrapper(context, clazz, wrappers, methodName, paramTypes, paramValues); Constructor<?> constructor = wrapper.unWrap(); if (!Modifier.isPublic(clazz.getModifiers()) || !canAccess(null, constructor)) { throw new MethodNotFoundException( message(null, "util.method.notfound", clazz, methodName, paramString(paramTypes))); } return constructor; } static boolean canAccess(Object base, AccessibleObject accessibleObject) { try { return accessibleObject.canAccess(base); } catch (IllegalArgumentException iae) { return false; } } static Object[] buildParameters(ELContext context, Class<?>[] parameterTypes, boolean isVarArgs, Object[] params) { Object[] parameters = null; if (parameterTypes.length > 0) { parameters = new Object[parameterTypes.length]; int paramCount; if (params == null) { params = EMPTY_OBJECT_ARRAY; } 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] = context.convertToType(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, context.convertToType(params[i], varArgClass)); } parameters[varArgIndex] = varargs; } else { parameters = new Object[parameterTypes.length]; for (int i = 0; i < parameterTypes.length; i++) { parameters[i] = context.convertToType(params[i], parameterTypes[i]); } } } return parameters; } private abstract static class Wrapper<T> { public static List<Wrapper<Method>> wrap(Method[] methods, String name) { List<Wrapper<Method>> result = new ArrayList<>(); for (Method method : methods) { if (method.getName().equals(name)) { result.add(new MethodWrapper(method)); } } return result; } public static List<Wrapper<Constructor<?>>> wrap(Constructor<?>[] constructors) { List<Wrapper<Constructor<?>>> result = new ArrayList<>(); for (Constructor<?> constructor : constructors) { result.add(new ConstructorWrapper(constructor)); } return result; } public abstract T unWrap(); public abstract Class<?>[] getParameterTypes(); public abstract boolean isVarArgs(); public abstract boolean isBridge(); } private static class MethodWrapper extends Wrapper<Method> { private final Method m; MethodWrapper(Method m) { this.m = m; } @Override public Method unWrap() { return m; } @Override public Class<?>[] getParameterTypes() { return m.getParameterTypes(); } @Override public boolean isVarArgs() { return m.isVarArgs(); } @Override public boolean isBridge() { return m.isBridge(); } } private static class ConstructorWrapper extends Wrapper<Constructor<?>> { private final Constructor<?> c; ConstructorWrapper(Constructor<?> c) { this.c = c; } @Override public Constructor<?> unWrap() { return c; } @Override public Class<?>[] getParameterTypes() { return c.getParameterTypes(); } @Override public boolean isVarArgs() { return c.isVarArgs(); } @Override public boolean isBridge() { return false; } } /* * This class duplicates code in org.apache.el.util.ReflectionUtil. When making changes keep the code in sync. */ private record MatchResult(boolean varArgs, int exactCount, int assignableCount, int coercibleCount, int varArgsCount, boolean bridge) implements Comparable<MatchResult> { public boolean isVarArgs() { return varArgs; } public int getExactCount() { return exactCount; } public int getAssignableCount() { return assignableCount; } public int getCoercibleCount() { return coercibleCount; } public int getVarArgsCount() { return varArgsCount; } public boolean isBridge() { return bridge; } @Override public int compareTo(MatchResult o) { // Non-varArgs always beats varArgs int cmp = Boolean.compare(o.isVarArgs(), this.isVarArgs()); if (cmp == 0) { cmp = Integer.compare(this.getExactCount(), o.getExactCount()); if (cmp == 0) { cmp = Integer.compare(this.getAssignableCount(), o.getAssignableCount()); if (cmp == 0) { cmp = Integer.compare(this.getCoercibleCount(), o.getCoercibleCount()); if (cmp == 0) { // Fewer var args matches are better cmp = Integer.compare(o.getVarArgsCount(), this.getVarArgsCount()); if (cmp == 0) { // The nature of bridge methods is such that it actually // doesn't matter which one we pick as long as we pick // one. That said, pick the 'right' one (the non-bridge // one) anyway. cmp = Boolean.compare(o.isBridge(), this.isBridge()); } } } } } return cmp; } @Override public boolean equals(Object o) { return o == this || (null != o && this.getClass().equals(o.getClass()) && ((MatchResult) o).getExactCount() == this.getExactCount() && ((MatchResult) o).getAssignableCount() == this.getAssignableCount() && ((MatchResult) o).getCoercibleCount() == this.getCoercibleCount() && ((MatchResult) o).getVarArgsCount() == this.getVarArgsCount() && ((MatchResult) o).isVarArgs() == this.isVarArgs() && ((MatchResult) o).isBridge() == this.isBridge()); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + getAssignableCount(); result = prime * result + (isBridge() ? 1231 : 1237); result = prime * result + getCoercibleCount(); result = prime * result + getExactCount(); result = prime * result + (isVarArgs() ? 1231 : 1237); result = prime * result + getVarArgsCount(); return result; } } }
Detected license expression
apache-2.0
Detected license expression (SPDX)
Apache-2.0
Percentage of license text
5.52
Copyrights

      
    
Holders

      
    
Authors

      
    
License detections License expression License expression SPDX
apache_2_0-4bde3f57-78aa-4201-96bf-531cba09e7de apache-2.0 Apache-2.0
URL Start line End line
http://www.apache.org/licenses/LICENSE-2.0 9 9