/apache-commons-ognl-3.0.2/src/main/java/org/apache/commons/ognl/OgnlRuntime.java
Java | 2782 lines | 1988 code | 399 blank | 395 comment | 588 complexity | 09fef185f02459fa6e4611a4ff7c2a06 MD5 | raw file
Possible License(s): Apache-2.0
- /*
- * $Id$
- * 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 org.apache.commons.ognl;
- import org.apache.commons.ognl.enhance.ExpressionCompiler;
- import org.apache.commons.ognl.enhance.OgnlExpressionCompiler;
- import org.apache.commons.ognl.internal.ClassCache;
- import org.apache.commons.ognl.internal.ClassCacheImpl;
- import java.beans.BeanInfo;
- import java.beans.IndexedPropertyDescriptor;
- import java.beans.IntrospectionException;
- import java.beans.Introspector;
- import java.beans.MethodDescriptor;
- import java.beans.PropertyDescriptor;
- import java.lang.reflect.AccessibleObject;
- import java.lang.reflect.Array;
- import java.lang.reflect.Constructor;
- import java.lang.reflect.Field;
- import java.lang.reflect.GenericArrayType;
- import java.lang.reflect.InvocationTargetException;
- import java.lang.reflect.Member;
- import java.lang.reflect.Method;
- import java.lang.reflect.Modifier;
- import java.lang.reflect.ParameterizedType;
- import java.lang.reflect.Proxy;
- import java.lang.reflect.Type;
- import java.lang.reflect.TypeVariable;
- import java.math.BigDecimal;
- import java.math.BigInteger;
- import java.security.Permission;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.Collection;
- import java.util.Collections;
- import java.util.Enumeration;
- import java.util.HashMap;
- import java.util.IdentityHashMap;
- import java.util.Iterator;
- import java.util.List;
- import java.util.Map;
- import java.util.Set;
- /**
- * Utility class used by internal OGNL API to do various things like:
- *
- * <ul>
- * <li>Handles majority of reflection logic / caching. </li>
- * <li>Utility methods for casting strings / various numeric types used by {@link OgnlExpressionCompiler}.</li.
- * <li>Core runtime configuration point for setting/using global {@link TypeConverter} / {@link OgnlExpressionCompiler} /
- * {@link NullHandler} instances / etc.. </li>
- *</ul>
- *
- * @author Luke Blanshard (blanshlu@netscape.net)
- * @author Drew Davidson (drew@ognl.org)
- */
- public class OgnlRuntime {
- /**
- * Constant expression used to indicate that a given method / property couldn't be found
- * during reflection operations.
- */
- public static final Object NotFound = new Object();
- public static final List NotFoundList = new ArrayList();
- public static final Map NotFoundMap = new HashMap();
- public static final Object[] NoArguments = new Object[]{};
- public static final Class[] NoArgumentTypes = new Class[]{};
- /**
- * Token returned by TypeConverter for no conversion possible
- */
- public static final Object NoConversionPossible = "ognl.NoConversionPossible";
- /**
- * Not an indexed property
- */
- public static int INDEXED_PROPERTY_NONE = 0;
- /**
- * JavaBeans IndexedProperty
- */
- public static int INDEXED_PROPERTY_INT = 1;
- /**
- * OGNL ObjectIndexedProperty
- */
- public static int INDEXED_PROPERTY_OBJECT = 2;
- /**
- * Constant string representation of null string.
- */
- public static final String NULL_STRING = "" + null;
- /**
- * Java beans standard set method prefix.
- */
- private static final String SET_PREFIX = "set";
- /**
- * Java beans standard get method prefix.
- */
- private static final String GET_PREFIX = "get";
- /**
- * Java beans standard is<Foo> boolean getter prefix.
- */
- private static final String IS_PREFIX = "is";
- /**
- * Prefix padding for hexadecimal numbers to HEX_LENGTH.
- */
- private static final Map HEX_PADDING = new HashMap();
- private static final int HEX_LENGTH = 8;
- /**
- * Returned by <CODE>getUniqueDescriptor()</CODE> when the object is <CODE>null</CODE>.
- */
- private static final String NULL_OBJECT_STRING = "<null>";
- /**
- * Used to store the result of determining if current jvm is 1.5 language compatible.
- */
- private static boolean _jdk15 = false;
- private static boolean _jdkChecked = false;
- static final ClassCache _methodAccessors = new ClassCacheImpl();
- static final ClassCache _propertyAccessors = new ClassCacheImpl();
- static final ClassCache _elementsAccessors = new ClassCacheImpl();
- static final ClassCache _nullHandlers = new ClassCacheImpl();
- static final ClassCache _propertyDescriptorCache = new ClassCacheImpl();
- static final ClassCache _constructorCache = new ClassCacheImpl();
- static final ClassCache _staticMethodCache = new ClassCacheImpl();
- static final ClassCache _instanceMethodCache = new ClassCacheImpl();
- static final ClassCache _invokePermissionCache = new ClassCacheImpl();
- static final ClassCache _fieldCache = new ClassCacheImpl();
- static final List _superclasses = new ArrayList(); /* Used by fieldCache lookup */
- static final ClassCache[] _declaredMethods = new ClassCache[]{new ClassCacheImpl(), new ClassCacheImpl()};
- static final Map _primitiveTypes = new HashMap(101);
- static final ClassCache _primitiveDefaults = new ClassCacheImpl();
- static final Map _methodParameterTypesCache = new HashMap(101);
- static final Map _genericMethodParameterTypesCache = new HashMap(101);
- static final Map _ctorParameterTypesCache = new HashMap(101);
- static SecurityManager _securityManager = System.getSecurityManager();
- static final EvaluationPool _evaluationPool = new EvaluationPool();
- static final ObjectArrayPool _objectArrayPool = new ObjectArrayPool();
- static final IntHashMap _methodAccessCache = new IntHashMap();
- static final IntHashMap _methodPermCache = new IntHashMap();
- static ClassCacheInspector _cacheInspector;
- /**
- * Expression compiler used by {@link Ognl#compileExpression(OgnlContext, Object, String)} calls.
- */
- private static OgnlExpressionCompiler _compiler;
- /**
- * Lazy loading of Javassist library
- */
- static {
- try {
- Class.forName("javassist.ClassPool");
- _compiler = new ExpressionCompiler();
- } catch (ClassNotFoundException e) {
- throw new IllegalArgumentException("Javassist library is missing in classpath! Please add missed dependency!",e);
- }
- }
- private static IdentityHashMap PRIMITIVE_WRAPPER_CLASSES = new IdentityHashMap();
- /**
- * Used to provide primitive type equivalent conversions into and out of
- * native / object types.
- */
- static {
- PRIMITIVE_WRAPPER_CLASSES.put(Boolean.TYPE, Boolean.class);
- PRIMITIVE_WRAPPER_CLASSES.put(Boolean.class, Boolean.TYPE);
- PRIMITIVE_WRAPPER_CLASSES.put(Byte.TYPE, Byte.class);
- PRIMITIVE_WRAPPER_CLASSES.put(Byte.class, Byte.TYPE);
- PRIMITIVE_WRAPPER_CLASSES.put(Character.TYPE, Character.class);
- PRIMITIVE_WRAPPER_CLASSES.put(Character.class, Character.TYPE);
- PRIMITIVE_WRAPPER_CLASSES.put(Short.TYPE, Short.class);
- PRIMITIVE_WRAPPER_CLASSES.put(Short.class, Short.TYPE);
- PRIMITIVE_WRAPPER_CLASSES.put(Integer.TYPE, Integer.class);
- PRIMITIVE_WRAPPER_CLASSES.put(Integer.class, Integer.TYPE);
- PRIMITIVE_WRAPPER_CLASSES.put(Long.TYPE, Long.class);
- PRIMITIVE_WRAPPER_CLASSES.put(Long.class, Long.TYPE);
- PRIMITIVE_WRAPPER_CLASSES.put(Float.TYPE, Float.class);
- PRIMITIVE_WRAPPER_CLASSES.put(Float.class, Float.TYPE);
- PRIMITIVE_WRAPPER_CLASSES.put(Double.TYPE, Double.class);
- PRIMITIVE_WRAPPER_CLASSES.put(Double.class, Double.TYPE);
- }
- private static final Map NUMERIC_CASTS = new HashMap();
- /**
- * Constant strings for casting different primitive types.
- */
- static {
- NUMERIC_CASTS.put(Double.class, "(double)");
- NUMERIC_CASTS.put(Float.class, "(float)");
- NUMERIC_CASTS.put(Integer.class, "(int)");
- NUMERIC_CASTS.put(Long.class, "(long)");
- NUMERIC_CASTS.put(BigDecimal.class, "(double)");
- NUMERIC_CASTS.put(BigInteger.class, "");
- }
- private static final Map NUMERIC_VALUES = new HashMap();
- /**
- * Constant strings for getting the primitive value of different
- * native types on the generic {@link Number} object interface. (or the less
- * generic BigDecimal/BigInteger types)
- */
- static {
- NUMERIC_VALUES.put(Double.class, "doubleValue()");
- NUMERIC_VALUES.put(Float.class, "floatValue()");
- NUMERIC_VALUES.put(Integer.class, "intValue()");
- NUMERIC_VALUES.put(Long.class, "longValue()");
- NUMERIC_VALUES.put(Short.class, "shortValue()");
- NUMERIC_VALUES.put(Byte.class, "byteValue()");
- NUMERIC_VALUES.put(BigDecimal.class, "doubleValue()");
- NUMERIC_VALUES.put(BigInteger.class, "doubleValue()");
- NUMERIC_VALUES.put(Boolean.class, "booleanValue()");
- }
- private static final Map NUMERIC_LITERALS = new HashMap();
- /**
- * Numeric primitive literal string expressions.
- */
- static {
- NUMERIC_LITERALS.put(Integer.class, "");
- NUMERIC_LITERALS.put(Integer.TYPE, "");
- NUMERIC_LITERALS.put(Long.class, "l");
- NUMERIC_LITERALS.put(Long.TYPE, "l");
- NUMERIC_LITERALS.put(BigInteger.class, "d");
- NUMERIC_LITERALS.put(Float.class, "f");
- NUMERIC_LITERALS.put(Float.TYPE, "f");
- NUMERIC_LITERALS.put(Double.class, "d");
- NUMERIC_LITERALS.put(Double.TYPE, "d");
- NUMERIC_LITERALS.put(BigInteger.class, "d");
- NUMERIC_LITERALS.put(BigDecimal.class, "d");
- }
- private static final Map NUMERIC_DEFAULTS = new HashMap();
- static {
- NUMERIC_DEFAULTS.put(Boolean.class, Boolean.FALSE);
- NUMERIC_DEFAULTS.put(Byte.class, new Byte((byte) 0));
- NUMERIC_DEFAULTS.put(Short.class, new Short((short) 0));
- NUMERIC_DEFAULTS.put(Character.class, new Character((char) 0));
- NUMERIC_DEFAULTS.put(Integer.class, new Integer(0));
- NUMERIC_DEFAULTS.put(Long.class, new Long(0L));
- NUMERIC_DEFAULTS.put(Float.class, new Float(0.0f));
- NUMERIC_DEFAULTS.put(Double.class, new Double(0.0));
- NUMERIC_DEFAULTS.put(BigInteger.class, new BigInteger("0"));
- NUMERIC_DEFAULTS.put(BigDecimal.class, new BigDecimal(0.0));
- }
- static {
- PropertyAccessor p = new ArrayPropertyAccessor();
- setPropertyAccessor(Object.class, new ObjectPropertyAccessor());
- setPropertyAccessor(byte[].class, p);
- setPropertyAccessor(short[].class, p);
- setPropertyAccessor(char[].class, p);
- setPropertyAccessor(int[].class, p);
- setPropertyAccessor(long[].class, p);
- setPropertyAccessor(float[].class, p);
- setPropertyAccessor(double[].class, p);
- setPropertyAccessor(Object[].class, p);
- setPropertyAccessor(List.class, new ListPropertyAccessor());
- setPropertyAccessor(Map.class, new MapPropertyAccessor());
- setPropertyAccessor(Set.class, new SetPropertyAccessor());
- setPropertyAccessor(Iterator.class, new IteratorPropertyAccessor());
- setPropertyAccessor(Enumeration.class, new EnumerationPropertyAccessor());
- ElementsAccessor e = new ArrayElementsAccessor();
- setElementsAccessor(Object.class, new ObjectElementsAccessor());
- setElementsAccessor(byte[].class, e);
- setElementsAccessor(short[].class, e);
- setElementsAccessor(char[].class, e);
- setElementsAccessor(int[].class, e);
- setElementsAccessor(long[].class, e);
- setElementsAccessor(float[].class, e);
- setElementsAccessor(double[].class, e);
- setElementsAccessor(Object[].class, e);
- setElementsAccessor(Collection.class, new CollectionElementsAccessor());
- setElementsAccessor(Map.class, new MapElementsAccessor());
- setElementsAccessor(Iterator.class, new IteratorElementsAccessor());
- setElementsAccessor(Enumeration.class, new EnumerationElementsAccessor());
- setElementsAccessor(Number.class, new NumberElementsAccessor());
- NullHandler nh = new ObjectNullHandler();
- setNullHandler(Object.class, nh);
- setNullHandler(byte[].class, nh);
- setNullHandler(short[].class, nh);
- setNullHandler(char[].class, nh);
- setNullHandler(int[].class, nh);
- setNullHandler(long[].class, nh);
- setNullHandler(float[].class, nh);
- setNullHandler(double[].class, nh);
- setNullHandler(Object[].class, nh);
- MethodAccessor ma = new ObjectMethodAccessor();
- setMethodAccessor(Object.class, ma);
- setMethodAccessor(byte[].class, ma);
- setMethodAccessor(short[].class, ma);
- setMethodAccessor(char[].class, ma);
- setMethodAccessor(int[].class, ma);
- setMethodAccessor(long[].class, ma);
- setMethodAccessor(float[].class, ma);
- setMethodAccessor(double[].class, ma);
- setMethodAccessor(Object[].class, ma);
- _primitiveTypes.put("boolean", Boolean.TYPE);
- _primitiveTypes.put("byte", Byte.TYPE);
- _primitiveTypes.put("short", Short.TYPE);
- _primitiveTypes.put("char", Character.TYPE);
- _primitiveTypes.put("int", Integer.TYPE);
- _primitiveTypes.put("long", Long.TYPE);
- _primitiveTypes.put("float", Float.TYPE);
- _primitiveTypes.put("double", Double.TYPE);
- _primitiveDefaults.put(Boolean.TYPE, Boolean.FALSE);
- _primitiveDefaults.put(Boolean.class, Boolean.FALSE);
- _primitiveDefaults.put(Byte.TYPE, new Byte((byte) 0));
- _primitiveDefaults.put(Byte.class, new Byte((byte) 0));
- _primitiveDefaults.put(Short.TYPE, new Short((short) 0));
- _primitiveDefaults.put(Short.class, new Short((short) 0));
- _primitiveDefaults.put(Character.TYPE, new Character((char) 0));
- _primitiveDefaults.put(Integer.TYPE, new Integer(0));
- _primitiveDefaults.put(Long.TYPE, new Long(0L));
- _primitiveDefaults.put(Float.TYPE, new Float(0.0f));
- _primitiveDefaults.put(Double.TYPE, new Double(0.0));
- _primitiveDefaults.put(BigInteger.class, new BigInteger("0"));
- _primitiveDefaults.put(BigDecimal.class, new BigDecimal(0.0));
- }
- /**
- * Clears all of the cached reflection information normally used
- * to improve the speed of expressions that operate on the same classes
- * or are executed multiple times.
- *
- * <p>
- * <strong>Warning:</strong> Calling this too often can be a huge performance
- * drain on your expressions - use with care.
- * </p>
- */
- public static void clearCache()
- {
- _methodParameterTypesCache.clear();
- _ctorParameterTypesCache.clear();
- _propertyDescriptorCache.clear();
- _constructorCache.clear();
- _staticMethodCache.clear();
- _instanceMethodCache.clear();
- _invokePermissionCache.clear();
- _fieldCache.clear();
- _superclasses.clear();
- _declaredMethods[0].clear();
- _declaredMethods[1].clear();
- _methodAccessCache.clear();
- }
- /**
- * Checks if the current jvm is java language >= 1.5 compatible.
- *
- * @return True if jdk15 features are present.
- */
- public static boolean isJdk15()
- {
- if (_jdkChecked)
- return _jdk15;
- try
- {
- Class.forName("java.lang.annotation.Annotation");
- _jdk15 = true;
- } catch (Exception e) { /* ignore */ }
- _jdkChecked = true;
- return _jdk15;
- }
- public static String getNumericValueGetter(Class type)
- {
- return (String) NUMERIC_VALUES.get(type);
- }
- public static Class getPrimitiveWrapperClass(Class primitiveClass)
- {
- return (Class) PRIMITIVE_WRAPPER_CLASSES.get(primitiveClass);
- }
- public static String getNumericCast(Class type)
- {
- return (String) NUMERIC_CASTS.get(type);
- }
- public static String getNumericLiteral(Class type)
- {
- return (String) NUMERIC_LITERALS.get(type);
- }
- public static void setCompiler(OgnlExpressionCompiler compiler)
- {
- _compiler = compiler;
- }
- public static OgnlExpressionCompiler getCompiler()
- {
- return _compiler;
- }
- public static void compileExpression(OgnlContext context, Node expression, Object root)
- throws Exception
- {
- _compiler.compileExpression(context, expression, root);
- }
- /**
- * Gets the "target" class of an object for looking up accessors that are registered on the
- * target. If the object is a Class object this will return the Class itself, else it will
- * return object's getClass() result.
- */
- public static Class getTargetClass(Object o)
- {
- return (o == null) ? null : ((o instanceof Class) ? (Class) o : o.getClass());
- }
- /**
- * Returns the base name (the class name without the package name prepended) of the object
- * given.
- */
- public static String getBaseName(Object o)
- {
- return (o == null) ? null : getClassBaseName(o.getClass());
- }
- /**
- * Returns the base name (the class name without the package name prepended) of the class given.
- */
- public static String getClassBaseName(Class c)
- {
- String s = c.getName();
- return s.substring(s.lastIndexOf('.') + 1);
- }
- public static String getClassName(Object o, boolean fullyQualified)
- {
- if (!(o instanceof Class))
- {
- o = o.getClass();
- }
- return getClassName((Class) o, fullyQualified);
- }
- public static String getClassName(Class c, boolean fullyQualified)
- {
- return fullyQualified ? c.getName() : getClassBaseName(c);
- }
- /**
- * Returns the package name of the object's class.
- */
- public static String getPackageName(Object o)
- {
- return (o == null) ? null : getClassPackageName(o.getClass());
- }
- /**
- * Returns the package name of the class given.
- */
- public static String getClassPackageName(Class c)
- {
- String s = c.getName();
- int i = s.lastIndexOf('.');
- return (i < 0) ? null : s.substring(0, i);
- }
- /**
- * Returns a "pointer" string in the usual format for these things - 0x<hex digits>.
- */
- public static String getPointerString(int num)
- {
- StringBuffer result = new StringBuffer();
- String hex = Integer.toHexString(num), pad;
- Integer l = new Integer(hex.length());
- // result.append(HEX_PREFIX);
- if ((pad = (String) HEX_PADDING.get(l)) == null) {
- StringBuffer pb = new StringBuffer();
- for (int i = hex.length(); i < HEX_LENGTH; i++) {
- pb.append('0');
- }
- pad = new String(pb);
- HEX_PADDING.put(l, pad);
- }
- result.append(pad);
- result.append(hex);
- return new String(result);
- }
- /**
- * Returns a "pointer" string in the usual format for these things - 0x<hex digits> for the
- * object given. This will always return a unique value for each object.
- */
- public static String getPointerString(Object o)
- {
- return getPointerString((o == null) ? 0 : System.identityHashCode(o));
- }
- /**
- * Returns a unique descriptor string that includes the object's class and a unique integer
- * identifier. If fullyQualified is true then the class name will be fully qualified to include
- * the package name, else it will be just the class' base name.
- */
- public static String getUniqueDescriptor(Object object, boolean fullyQualified)
- {
- StringBuffer result = new StringBuffer();
- if (object != null) {
- if (object instanceof Proxy) {
- Class interfaceClass = object.getClass().getInterfaces()[0];
- result.append(getClassName(interfaceClass, fullyQualified));
- result.append('^');
- object = Proxy.getInvocationHandler(object);
- }
- result.append(getClassName(object, fullyQualified));
- result.append('@');
- result.append(getPointerString(object));
- } else {
- result.append(NULL_OBJECT_STRING);
- }
- return new String(result);
- }
- /**
- * Returns a unique descriptor string that includes the object's class' base name and a unique
- * integer identifier.
- */
- public static String getUniqueDescriptor(Object object)
- {
- return getUniqueDescriptor(object, false);
- }
- /**
- * Utility to convert a List into an Object[] array. If the list is zero elements this will
- * return a constant array; toArray() on List always returns a new object and this is wasteful
- * for our purposes.
- */
- public static Object[] toArray(List list)
- {
- Object[] result;
- int size = list.size();
- if (size == 0) {
- result = NoArguments;
- } else {
- result = getObjectArrayPool().create(list.size());
- for (int i = 0; i < size; i++) {
- result[i] = list.get(i);
- }
- }
- return result;
- }
- /**
- * Returns the parameter types of the given method.
- */
- public static Class[] getParameterTypes(Method m)
- {
- synchronized (_methodParameterTypesCache)
- {
- Class[] result;
- if ((result = (Class[]) _methodParameterTypesCache.get(m)) == null)
- {
- _methodParameterTypesCache.put(m, result = m.getParameterTypes());
- }
- return result;
- }
- }
- /**
- * Finds the appropriate parameter types for the given {@link Method} and
- * {@link Class} instance of the type the method is associated with. Correctly
- * finds generic types if running in >= 1.5 jre as well.
- *
- * @param type The class type the method is being executed against.
- * @param m The method to find types for.
- * @return Array of parameter types for the given method.
- */
- public static Class[] findParameterTypes(Class type, Method m)
- {
- if (type == null)
- {
- return getParameterTypes(m);
- }
- if (!isJdk15()
- || type.getGenericSuperclass() == null
- || !ParameterizedType.class.isInstance(type.getGenericSuperclass())
- || m.getDeclaringClass().getTypeParameters() == null)
- {
- return getParameterTypes(m);
- }
- synchronized (_genericMethodParameterTypesCache)
- {
- Class[] types;
- if ((types = (Class[]) _genericMethodParameterTypesCache.get(m)) != null)
- {
- ParameterizedType genericSuperclass = (ParameterizedType) type.getGenericSuperclass();
- if (Arrays.equals(types, genericSuperclass.getActualTypeArguments())) {
- return types;
- }
- }
- ParameterizedType param = (ParameterizedType)type.getGenericSuperclass();
- Type[] genTypes = m.getGenericParameterTypes();
- TypeVariable[] declaredTypes = m.getDeclaringClass().getTypeParameters();
- types = new Class[genTypes.length];
- typeSearch:
- for (int i=0; i < genTypes.length; i++)
- {
- TypeVariable paramType = null;
- if (TypeVariable.class.isInstance(genTypes[i]))
- {
- paramType = (TypeVariable)genTypes[i];
- } else if (GenericArrayType.class.isInstance(genTypes[i]))
- {
- paramType = (TypeVariable) ((GenericArrayType)genTypes[i]).getGenericComponentType();
- }
- else if (ParameterizedType.class.isInstance(genTypes[i]))
- {
- types[i] = (Class) ((ParameterizedType) genTypes[i]).getRawType();
- continue;
- } else if (Class.class.isInstance(genTypes[i]))
- {
- types[i] = (Class) genTypes[i];
- continue;
- }
- Class resolved = resolveType(param, paramType, declaredTypes);
- if (resolved != null)
- {
- if (GenericArrayType.class.isInstance(genTypes[i]))
- {
- resolved = Array.newInstance(resolved, 0).getClass();
- }
- types[i] = resolved;
- continue;
- }
- types[i] = m.getParameterTypes()[i];
- }
- _genericMethodParameterTypesCache.put(m, types);
- return types;
- }
- }
- static Class resolveType(ParameterizedType param, TypeVariable var, TypeVariable[] declaredTypes)
- {
- if (param.getActualTypeArguments().length < 1)
- return null;
- for (int i=0; i < declaredTypes.length; i++)
- {
- if (!TypeVariable.class.isInstance( param.getActualTypeArguments()[i])
- && declaredTypes[i].getName().equals(var.getName()))
- {
- return (Class) param.getActualTypeArguments()[i];
- }
- }
- /*
- for (int i=0; i < var.getBounds().length; i++)
- {
- Type t = var.getBounds()[i];
- Class resolvedType = null;
- if (ParameterizedType.class.isInstance(t))
- {
- ParameterizedType pparam = (ParameterizedType)t;
- for (int e=0; e < pparam.getActualTypeArguments().length; e++)
- {
- if (!TypeVariable.class.isInstance(pparam.getActualTypeArguments()[e]))
- continue;
- resolvedType = resolveType(pparam, (TypeVariable)pparam.getActualTypeArguments()[e], declaredTypes);
- }
- } else
- {
- resolvedType = findType(param.getActualTypeArguments(), (Class)t);
- }
- if (resolvedType != null)
- return resolvedType;
- }
- */
- return null;
- }
- static Class findType(Type[] types, Class type)
- {
- for (int i = 0; i < types.length; i++)
- {
- if (Class.class.isInstance(types[i]) && type.isAssignableFrom((Class)types[i]))
- return (Class)types[i];
- }
- return null;
- }
- /**
- * Returns the parameter types of the given method.
- */
- public static Class[] getParameterTypes(Constructor c)
- {
- synchronized (_ctorParameterTypesCache) {
- Class[] result;
- if ((result = (Class[]) _ctorParameterTypesCache.get(c)) == null) {
- _ctorParameterTypesCache.put(c, result = c.getParameterTypes());
- }
- return result;
- }
- }
- /**
- * Gets the SecurityManager that OGNL uses to determine permissions for invoking methods.
- *
- * @return SecurityManager for OGNL
- */
- public static SecurityManager getSecurityManager()
- {
- return _securityManager;
- }
- /**
- * Sets the SecurityManager that OGNL uses to determine permissions for invoking methods.
- *
- * @param value SecurityManager to set
- */
- public static void setSecurityManager(SecurityManager value)
- {
- _securityManager = value;
- }
- /**
- * Permission will be named "invoke.<declaring-class>.<method-name>".
- */
- public static Permission getPermission(Method method)
- {
- Permission result = null;
- Class mc = method.getDeclaringClass();
- synchronized (_invokePermissionCache) {
- Map permissions = (Map) _invokePermissionCache.get(mc);
- if (permissions == null) {
- _invokePermissionCache.put(mc, permissions = new HashMap(101));
- }
- if ((result = (Permission) permissions.get(method.getName())) == null) {
- result = new OgnlInvokePermission("invoke." + mc.getName() + "." + method.getName());
- permissions.put(method.getName(), result);
- }
- }
- return result;
- }
- public static Object invokeMethod(Object target, Method method, Object[] argsArray)
- throws InvocationTargetException, IllegalAccessException
- {
- boolean syncInvoke = false;
- boolean checkPermission = false;
- int mHash = method.hashCode();
- // only synchronize method invocation if it actually requires it
- synchronized(method) {
- if (_methodAccessCache.get(mHash) == null
- || _methodAccessCache.get(mHash) == Boolean.TRUE) {
- syncInvoke = true;
- }
- if (_securityManager != null && _methodPermCache.get(mHash) == null
- || _methodPermCache.get(mHash) == Boolean.FALSE) {
- checkPermission = true;
- }
- }
- Object result;
- boolean wasAccessible = true;
- if (syncInvoke)
- {
- synchronized(method)
- {
- if (checkPermission)
- {
- try
- {
- _securityManager.checkPermission(getPermission(method));
- _methodPermCache.put(mHash, Boolean.TRUE);
- } catch (SecurityException ex) {
- _methodPermCache.put(mHash, Boolean.FALSE);
- throw new IllegalAccessException("Method [" + method + "] cannot be accessed.");
- }
- }
- if (!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers()))
- {
- if (!(wasAccessible = ((AccessibleObject) method).isAccessible()))
- {
- ((AccessibleObject) method).setAccessible(true);
- _methodAccessCache.put(mHash, Boolean.TRUE);
- } else
- {
- _methodAccessCache.put(mHash, Boolean.FALSE);
- }
- } else
- {
- _methodAccessCache.put(mHash, Boolean.FALSE);
- }
- result = method.invoke(target, argsArray);
- if (!wasAccessible)
- {
- ((AccessibleObject) method).setAccessible(false);
- }
- }
- } else
- {
- if (checkPermission)
- {
- try
- {
- _securityManager.checkPermission(getPermission(method));
- _methodPermCache.put(mHash, Boolean.TRUE);
- } catch (SecurityException ex) {
- _methodPermCache.put(mHash, Boolean.FALSE);
- throw new IllegalAccessException("Method [" + method + "] cannot be accessed.");
- }
- }
- result = method.invoke(target, argsArray);
- }
- return result;
- }
- /**
- * Gets the class for a method argument that is appropriate for looking up methods by
- * reflection, by looking for the standard primitive wrapper classes and exchanging for them
- * their underlying primitive class objects. Other classes are passed through unchanged.
- *
- * @param arg an object that is being passed to a method
- * @return the class to use to look up the method
- */
- public static final Class getArgClass(Object arg)
- {
- if (arg == null)
- return null;
- Class c = arg.getClass();
- if (c == Boolean.class)
- return Boolean.TYPE;
- else if (c.getSuperclass() == Number.class) {
- if (c == Integer.class)
- return Integer.TYPE;
- if (c == Double.class)
- return Double.TYPE;
- if (c == Byte.class)
- return Byte.TYPE;
- if (c == Long.class)
- return Long.TYPE;
- if (c == Float.class)
- return Float.TYPE;
- if (c == Short.class)
- return Short.TYPE;
- } else if (c == Character.class)
- return Character.TYPE;
- return c;
- }
- /**
- * Tells whether the given object is compatible with the given class ---that is, whether the
- * given object can be passed as an argument to a method or constructor whose parameter type is
- * the given class. If object is null this will return true because null is compatible with any
- * type.
- */
- public static final boolean isTypeCompatible(Object object, Class c)
- {
- boolean result = true;
- if (object != null) {
- if (c.isPrimitive()) {
- if (getArgClass(object) != c) {
- result = false;
- }
- } else if (!c.isInstance(object)) {
- result = false;
- }
- }
- return result;
- }
- /**
- * Tells whether the given array of objects is compatible with the given array of classes---that
- * is, whether the given array of objects can be passed as arguments to a method or constructor
- * whose parameter types are the given array of classes.
- */
- public static boolean areArgsCompatible(Object[] args, Class[] classes)
- {
- return areArgsCompatible(args, classes, null);
- }
- public static boolean areArgsCompatible(Object[] args, Class[] classes, Method m)
- {
- boolean result = true;
- boolean varArgs = m != null && isJdk15() && m.isVarArgs();
- if (args.length != classes.length && !varArgs) {
- result = false;
- } else if (varArgs) {
- for (int index = 0, count = args.length; result && (index < count); ++index) {
- if (index >= classes.length){
- break;
- }
- result = isTypeCompatible(args[index], classes[index]);
- if (!result && classes[index].isArray()) {
- result = isTypeCompatible(args[index], classes[index].getComponentType());
- }
- }
- } else {
- for (int index = 0, count = args.length; result && (index < count); ++index) {
- result = isTypeCompatible(args[index], classes[index]);
- }
- }
- return result;
- }
- /**
- * Tells whether the first array of classes is more specific than the second. Assumes that the
- * two arrays are of the same length.
- */
- public static final boolean isMoreSpecific(Class[] classes1, Class[] classes2)
- {
- for (int index = 0, count = classes1.length; index < count; ++index) {
- Class c1 = classes1[index], c2 = classes2[index];
- if (c1 == c2)
- continue;
- else if (c1.isPrimitive())
- return true;
- else if (c1.isAssignableFrom(c2))
- return false;
- else if (c2.isAssignableFrom(c1))
- return true;
- }
- // They are the same! So the first is not more specific than the second.
- return false;
- }
- public static String getModifierString(int modifiers)
- {
- String result;
- if (Modifier.isPublic(modifiers))
- result = "public";
- else if (Modifier.isProtected(modifiers))
- result = "protected";
- else if (Modifier.isPrivate(modifiers))
- result = "private";
- else
- result = "";
- if (Modifier.isStatic(modifiers))
- result = "static " + result;
- if (Modifier.isFinal(modifiers))
- result = "final " + result;
- if (Modifier.isNative(modifiers))
- result = "native " + result;
- if (Modifier.isSynchronized(modifiers))
- result = "synchronized " + result;
- if (Modifier.isTransient(modifiers))
- result = "transient " + result;
- return result;
- }
- public static Class classForName(OgnlContext context, String className)
- throws ClassNotFoundException
- {
- Class result = (Class) _primitiveTypes.get(className);
- if (result == null) {
- ClassResolver resolver;
- if ((context == null) || ((resolver = context.getClassResolver()) == null)) {
- resolver = OgnlContext.DEFAULT_CLASS_RESOLVER;
- }
- result = resolver.classForName(className, context);
- }
- if (result == null)
- throw new ClassNotFoundException("Unable to resolve class: " + className);
- return result;
- }
- public static boolean isInstance(OgnlContext context, Object value, String className)
- throws OgnlException
- {
- try {
- Class c = classForName(context, className);
- return c.isInstance(value);
- } catch (ClassNotFoundException e) {
- throw new OgnlException("No such class: " + className, e);
- }
- }
- public static Object getPrimitiveDefaultValue(Class forClass)
- {
- return _primitiveDefaults.get(forClass);
- }
- public static Object getNumericDefaultValue(Class forClass)
- {
- return NUMERIC_DEFAULTS.get(forClass);
- }
- public static Object getConvertedType(OgnlContext context, Object target, Member member, String propertyName,
- Object value, Class type)
- {
- return context.getTypeConverter().convertValue(context, target, member, propertyName, value, type);
- }
- public static boolean getConvertedTypes(OgnlContext context, Object target, Member member, String propertyName,
- Class[] parameterTypes, Object[] args, Object[] newArgs)
- {
- boolean result = false;
- if (parameterTypes.length == args.length) {
- result = true;
- for (int i = 0, ilast = parameterTypes.length - 1; result && (i <= ilast); i++) {
- Object arg = args[i];
- Class type = parameterTypes[i];
- if (isTypeCompatible(arg, type)) {
- newArgs[i] = arg;
- } else {
- Object v = getConvertedType(context, target, member, propertyName, arg, type);
- if (v == OgnlRuntime.NoConversionPossible) {
- result = false;
- } else {
- newArgs[i] = v;
- }
- }
- }
- }
- return result;
- }
- public static Method getConvertedMethodAndArgs(OgnlContext context, Object target, String propertyName,
- List methods, Object[] args, Object[] newArgs)
- {
- Method result = null;
- TypeConverter converter = context.getTypeConverter();
- if ((converter != null) && (methods != null))
- {
- for (int i = 0, icount = methods.size(); (result == null) && (i < icount); i++)
- {
- Method m = (Method) methods.get(i);
- Class[] parameterTypes = findParameterTypes(target != null ? target.getClass() : null, m);//getParameterTypes(m);
- if (getConvertedTypes(context, target, m, propertyName, parameterTypes, args, newArgs))
- {
- result = m;
- }
- }
- }
- return result;
- }
- public static Constructor getConvertedConstructorAndArgs(OgnlContext context, Object target, List constructors,
- Object[] args, Object[] newArgs)
- {
- Constructor result = null;
- TypeConverter converter = context.getTypeConverter();
- if ((converter != null) && (constructors != null)) {
- for (int i = 0, icount = constructors.size(); (result == null) && (i < icount); i++) {
- Constructor ctor = (Constructor) constructors.get(i);
- Class[] parameterTypes = getParameterTypes(ctor);
- if (getConvertedTypes(context, target, ctor, null, parameterTypes, args, newArgs)) {
- result = ctor;
- }
- }
- }
- return result;
- }
- /**
- * Gets the appropriate method to be called for the given target, method name and arguments. If
- * successful this method will return the Method within the target that can be called and the
- * converted arguments in actualArgs. If unsuccessful this method will return null and the
- * actualArgs will be empty.
- *
- * @param context The current execution context.
- * @param source Target object to run against or method name.
- * @param target Instance of object to be run against.
- * @param propertyName Name of property to get method of.
- * @param methods List of current known methods.
- * @param args Arguments originally passed in.
- * @param actualArgs Converted arguments.
- *
- * @return Best method match or null if none could be found.
- */
- public static Method getAppropriateMethod(OgnlContext context, Object source, Object target, String propertyName,
- List methods, Object[] args, Object[] actualArgs)
- {
- Method result = null;
- Class[] resultParameterTypes = null;
- if (methods != null)
- {
- for (int i = 0, icount = methods.size(); i < icount; i++)
- {
- Method m = (Method) methods.get(i);
- Class typeClass = target != null ? target.getClass() : null;
- if (typeClass == null && source != null && Class.class.isInstance(source))
- {
- typeClass = (Class)source;
- }
- Class[] mParameterTypes = findParameterTypes(typeClass, m);
- if (areArgsCompatible(args, mParameterTypes, m)
- && ((result == null) || isMoreSpecific(mParameterTypes, resultParameterTypes)))
- {
- result = m;
- resultParameterTypes = mParameterTypes;
- System.arraycopy(args, 0, actualArgs, 0, args.length);
- for (int j = 0; j < mParameterTypes.length; j++)
- {
- Class type = mParameterTypes[j];
- if (type.isPrimitive() && (actualArgs[j] == null))
- {
- actualArgs[j] = getConvertedType(context, source, result, propertyName, null, type);
- }
- }
- }
- }
- }
- if (result == null)
- {
- result = getConvertedMethodAndArgs(context, target, propertyName, methods, args, actualArgs);
- }
- return result;
- }
- public static Object callAppropriateMethod(OgnlContext context, Object source, Object target, String methodName,
- String propertyName, List methods, Object[] args)
- throws MethodFailedException
- {
- Throwable reason = null;
- Object[] actualArgs = _objectArrayPool.create(args.length);
- try {
- Method method = getAppropriateMethod(context, source, target, propertyName, methods, args, actualArgs);
- if ((method == null) || !isMethodAccessible(context, source, method, propertyName))
- {
- StringBuffer buffer = new StringBuffer();
- String className = "";
- if (target != null)
- {
- className = target.getClass().getName() + ".";
- }
- for (int i = 0, ilast = args.length - 1; i <= ilast; i++)
- {
- Object arg = args[i];
- buffer.append((arg == null) ? NULL_STRING : arg.getClass().getName());
- if (i < ilast)
- {
- buffer.append(", ");
- }
- }
- throw new NoSuchMethodException(className + methodName + "(" + buffer + ")");
- }
- Object[] convertedArgs = actualArgs;
- if (isJdk15() && method.isVarArgs())
- {
- Class[] parmTypes = method.getParameterTypes();
- // split arguments in to two dimensional array for varargs reflection invocation
- // where it is expected that the parameter passed in to invoke the method
- // will look like "new Object[] { arrayOfNonVarArgsArguments, arrayOfVarArgsArguments }"
- for (int i=0; i < parmTypes.length; i++)
- {
- if (parmTypes[i].isArray())
- {
- convertedArgs = new Object[i + 1];
- System.arraycopy(actualArgs, 0, convertedArgs, 0, convertedArgs.length);
- Object[] varArgs;
- // if they passed in varargs arguments grab them and dump in to new varargs array
- if (actualArgs.length > i)
- {
- ArrayList varArgsList = new ArrayList();
- for (int j=i; j < actualArgs.length; j++)
- {
- if (actualArgs[j] != null)
- {
- varArgsList.add(actualArgs[j]);
- }
- }
- varArgs = varArgsList.toArray();
- } else
- {
- varArgs = new Object[0];
- }
- convertedArgs[i] = varArgs;
- break;
- }
- }
- }
- return invokeMethod(target, method, convertedArgs);
- } catch (NoSuchMethodException e) {
- reason = e;
- } catch (IllegalAccessException e) {
- reason = e;
- } catch (InvocationTargetException e) {
- reason = e.getTargetException();
- } finally {
- _objectArrayPool.recycle(actualArgs);
- }
- throw new MethodFailedException(source, methodName, reason);
- }
- public static Object callStaticMethod(OgnlContext context, String className, String methodName, Object[] args)
- throws OgnlException
- {
- try {
- Class targetClass = classForName(context, className);
- if (targetClass == null)
- throw new ClassNotFoundException("Unable to resolve class with name " + className);
- MethodAccessor ma = getMethodAccessor(targetClass);
- return ma.callStaticMethod(context, targetClass, methodName, args);
- } catch (ClassNotFoundException ex) {
- throw new MethodFailedException(className, methodName, ex);
- }
- }
- /**
- * Invokes the specified method against the target object.
- *
- * @param context
- * The current execution context.
- * @param target
- * The object to invoke the method on.
- * @param methodName
- * Name of the method - as in "getValue" or "add", etc..
- * @param propertyName
- * Name of the property to call instead?
- * @param args
- * Optional arguments needed for method.
- * @return Result of invoking method.
- *
- * @deprecated Use {@link #callMethod(OgnlContext, Object, String, Object[])} instead.
- * @throws OgnlException For lots of different reasons.
- */
- public static Object callMethod(OgnlContext context, Object target, String methodName, String propertyName, Object[] args)
- throws OgnlException
- {
- return callMethod(context, target, methodName == null ? propertyName : methodName, args);
- }
- /**
- * Invokes the specified method against the target object.
- *
- * @param context
- * The current execution context.
- * @param target
- * The object to invoke the method on.
- * @param methodName
- * Name of the method - as in "getValue" or "add", etc..
- * @param args
- * Optional arguments needed for method.
- * @return Result of invoking method.
- *
- * @throws OgnlException For lots of different reasons.
- */
- public static Object callMethod(OgnlContext context, Object target, String methodName, Object[] args)
- throws OgnlException
- {
- if (target == null)
- throw new NullPointerException("target is null for method " + methodName);
- return getMethodAccessor(target.getClass()).callMethod(context, target, methodName, args);
- }
- public static Object callConstructor(OgnlContext context, String className, Object[] args)
- throws OgnlException
- {
- Throwable reason = null;
- Object[] actualArgs = args;
- try {
- Constructor ctor = null;
- Class[] ctorParameterTypes = null;
- Class target = classForName(context, className);
- List constructors = getConstructors(target);
- for (int i = 0, icount = constructors.size(); i < icount; i++) {
- Constructor c = (Constructor) constructors.get(i);
- Class[] cParameterTypes = getParameterTypes(c);
- if (areArgsCompatible(args, cParameterTypes)
- && (ctor == null || isMoreSpecific(cParameterTypes, ctorParameterTypes))) {
- ctor = c;
- ctorParameterTypes = cParameterTypes;
- }
- }
- if (ctor == null) {
- actualArgs = _objectArrayPool.create(args.length);
- if ((ctor = getConvertedConstructorAndArgs(context, target, constructors, args, actualArgs)) == null) {
- throw new NoSuchMethodException();
- }
- }
- if (!context.getMemberAccess().isAccessible(context, target, ctor, null)) {
- throw new IllegalAccessException(
- "access denied to " + target.getName() + "()");
- }
- return ctor.newInstance(actualArgs);
- } catch (ClassNotFoundException e) {
- reason = e;
- } catch (NoSuchMethodException e) {
- reason = e;
- } catch (IllegalAccessException e) {
- reason = e;
- } catch (InvocationTargetException e) {
- reason = e.getTargetException();
- } catch (InstantiationException e) {
- reason = e;
- } finally {
- if (actualArgs != args) {
- _objectArrayPool.recycle(actualArgs);
- }
- }
- throw new MethodFailedException(className, "new", reason);
- }
- public static final Object getMethodValue(OgnlContext context, Object target, String propertyName)
- throws OgnlException, IllegalAccessException, NoSuchMethodException, IntrospectionException
- {
- return getMethodValue(context, target, propertyName, false);
- }
- /**
- * If the checkAccessAndExistence flag is true this method will check to see if the method
- * exists and if it is accessible according to the context's MemberAccess. If neither test
- * passes this will return NotFound.
- */
- public static final Object getMethodValue(OgnlContext context, Object target, String propertyName,
- boolean checkAccessAndExistence)
- throws OgnlException, IllegalAccessException, NoSuchMethodException, IntrospectionException
- {
- Object result = null;
- Method m = getGetMethod(context, (target == null) ? null : target.getClass() , propertyName);
- if (m == null)
- m = getReadMethod((target == null) ? null : target.getClass(), propertyName, 0);
- if (checkAccessAndExistence)
- {
- if ((m == null) || !context.getMemberAccess().isAccessible(context, target, m, propertyName))
- {
- result = NotFound;
- }
- }
- if (result == null) {
- if (m != null) {
- try {
- result = invokeMethod(target, m, NoArguments);
- } catch (InvocationTargetException ex) {
- throw new OgnlException(propertyName, ex.getTargetException());
- }
- } else {
- throw new NoSuchMethodException(propertyName);
- }
- }
- return result;
- }
- public static boolean setMethodValue(OgnlContext context, Object target, String propertyName, Object value)
- throws OgnlException, IllegalAccessException, NoSuchMethodException, IntrospectionException
- {
- return setMethodValue(context, target, propertyName, value, false);
- }
- public static boolean setMethodValue(OgnlContext context, Object target, String propertyName, Object value,
- boolean checkAccessAndExistence)
- throws OgnlException, IllegalAccessException, NoSuchMethodException, IntrospectionException
- {
- boolean result = true;
- Method m = getSetMethod(context, (target == null) ? null : target.getClass(), propertyName);
- if (checkAccessAndExistence)
- {
- if ((m == null) || !context.getMemberAccess().isAccessible(context, target, m, propertyName))
- {
- result = false;
- }
- }
- if (result)
- {
- if (m != null)
- {
- Object[] args = _objectArrayPool.create(value);
- try
- {
- callAppropriateMethod(context, target, target, m.getName(), propertyName,
- Collections.nCopies(1, m), args);
- } finally
- {
- _objectArrayPool.recycle(args);
- }
- } else
- {
- result = false;
- }
- }
- return result;
- }
- public static List getConstructors(Class targetClass)
- {
- List result;
- synchronized (_constructorCache) {
- if ((result = (List) _constructorCache.get(targetClass)) == null) {
- _constructorCache.put(targetClass, result = Arrays.asList(targetClass.getConstructors()));
- }
- }
- return result;
- }
- public static Map getMethods(Class targetClass, boolean staticMethods)
- {
- ClassCache cache = (staticMethods ? _staticMethodCache : _instanceMethodCache);
- Map result;
- synchronized (cache)
- {
- if ((result = (Map) cache.get(targetClass)) == null)
- {
- cache.put(targetClass, result = new HashMap(23));
- for (Class c = targetClass; c != null; c = c.getSuperclass())
- {
- Method[] ma = c.getDeclaredMethods();
- for (int i = 0, icount = ma.length; i < icount; i++)
- {
- // skip over synthetic methods
- if (!isMethodCallable(ma[i]))
- continue;
- if (Modifier.isStatic(ma[i].getModifiers()) == staticMethods)
- {
- List ml = (List) result.get(ma[i].getName());
- if (ml == null)
- result.put(ma[i].getName(), ml = new ArrayList());
- ml.add(ma[i]);
- }
- }
- }
- }
- }
- return result;
- }
- public static List getMethods(Class targetClass, String name, boolean staticMethods)
- {
- return (List) getMethods(targetClass, staticMethods).get(name);
- }
- public static Map getFields(Class targetClass)
- {
- Map result;
- synchronized (_fieldCache) {
- if ((result = (Map) _fieldCache.get(targetClass)) == null) {
- Field fa[];
- result = new HashMap(23);
- fa = targetClass.getDeclaredFields();
- for (int i = 0; i < fa.length; i++) {
- result.put(fa[i].getName(), fa[i]);
- }
- _fieldCache.put(targetClass, result);
- }
- }
- return result;
- }
- public static Field getField(Class inClass, String name)
- {
- Field result = null;
- synchronized (_fieldCache) {
- Object o = getFields(inClass).get(name);
- if (o == null) {
- _superclasses.clear();
- for (Class sc = inClass; (sc != null); sc = sc.getSuperclass()) {
- if ((o = getFields(sc).get(name)) == NotFound)
- break;
- _superclasses.add(sc);
- if ((result = (Field) o) != null)
- break;
- }
- /*
- * Bubble the found value (either cache miss or actual field) to all supeclasses
- * that we saw for quicker access next time.
- */
- for (int i = 0, icount = _superclasses.size(); i < icount; i++) {
- getFields((Class) _superclasses.get(i)).put(name, (result == null) ? NotFound : result);
- }
- } else {
- if (o instanceof Field) {
- result = (Field) o;
- } else {
- if (result == NotFound)
- result = null;
- }
- }
- }
- return result;
- }
- public static Object getFieldValue(OgnlContext context, Object target, String propertyName)
- throws NoSuchFieldException
- {
- return getFieldValue(context, target, propertyName, false);
- }
- public static Object getFieldValue(OgnlContext context, Object target, String propertyName,
- boolean checkAccessAndExistence)
- throws NoSuchFieldException
- {
- Object result = null;
- Field f = getField((target == null) ? null : target.getClass(), propertyName);
- if (checkAccessAndExistence) {
- if ((f == null) || !context.getMemberAccess().isAccessible(context, target, f, propertyName)) {
- result = NotFound;
- }
- }
- if (result == null) {
- if (f == null) {
- throw new NoSuchFieldException(propertyName);
- } else {
- try {
- Object state = null;
- if (!Modifier.isStatic(f.getModifiers())) {
- state = context.getMemberAccess().setup(context, target, f, propertyName);
- result = f.get(target);
- context.getMemberAccess().restore(context, target, f, propertyName, state);
- } else
- throw new NoSuchFieldException(propertyName);
- } catch (IllegalAccessException ex) {
- throw new NoSuchFieldException(propertyName);
- }
- }
- }
- return result;
- }
- public static boolean setFieldValue(OgnlContext context, Object target, String propertyName, Object value)
- throws OgnlException
- {
- boolean result = false;
- try {
- Field f = getField((target == null) ? null : target.getClass(), propertyName);
- Object state;
- if ((f != null) && !Modifier.isStatic(f.getModifiers())) {
- state = context.getMemberAccess().setup(context, target, f, propertyName);
- try {
- if (isTypeCompatible(value, f.getType())
- || ((value = getConvertedType(context, target, f, propertyName, value, f.getType())) != null)) {
- f.set(target, value);
- result = true;
- }
- } finally {
- context.getMemberAccess().restore(context, target, f, propertyName, state);
- }
- }
- } catch (IllegalAccessException ex) {
- throw new NoSuchPropertyException(target, propertyName, ex);
- }
- return result;
- }
- public static boolean isFieldAccessible(OgnlContext context, Object target, Class inClass, String propertyName)
- {
- return isFieldAccessible(context, target, getField(inClass, propertyName), propertyName);
- }
- public static boolean isFieldAccessible(OgnlContext context, Object target, Field field, String propertyName)
- {
- return context.getMemberAccess().isAccessible(context, target, field, propertyName);
- }
- public static boolean hasField(OgnlContext context, Object target, Class inClass, String propertyName)
- {
- Field f = getField(inClass, propertyName);
- return (f != null) && isFieldAccessible(context, target, f, propertyName);
- }
- public static Object getStaticField(OgnlContext context, String className, String fieldName)
- throws OgnlException
- {
- Exception reason = null;
- try {
- Class c = classForName(context, className);
- if (c == null)
- throw new OgnlException("Unable to find class " + className + " when resolving field name of " + fieldName);
- /*
- * Check for virtual static field "class"; this cannot interfere with normal static
- * fields because it is a reserved word.
- */
- if (fieldName.equals("class"))
- {
- return c;
- } else if (OgnlRuntime.isJdk15() && c.isEnum())
- {
- return Enum.valueOf(c, fieldName);
- } else
- {
- Field f = c.getField(fieldName);
- if (!Modifier.isStatic(f.getModifiers()))
- throw new OgnlException("Field " + fieldName + " of class " + className + " is not static");
- return f.get(null);
- }
- } catch (ClassNotFoundException e) {
- reason = e;
- } catch (NoSuchFieldException e) {
- reason = e;
- } catch (SecurityException e) {
- reason = e;
- } catch (IllegalAccessException e) {
- reason = e;
- }
- throw new OgnlException("Could not get static field " + fieldName + " from class " + className, reason);
- }
- public static List getDeclaredMethods(Class targetClass, String propertyName, boolean findSets)
- {
- List result = null;
- ClassCache cache = _declaredMethods[findSets ? 0 : 1];
- synchronized (cache) {
- Map propertyCache = (Map) cache.get(targetClass);
- if ((propertyCache == null) || ((result = (List) propertyCache.get(propertyName)) == null)) {
- String baseName = Character.toUpperCase(propertyName.charAt(0)) + propertyName.substring(1);
- for (Class c = targetClass; c != null; c = c.getSuperclass()) {
- Method[] methods = c.getDeclaredMethods();
- for (int i = 0; i < methods.length; i++) {
- if (!isMethodCallable(methods[i]))
- continue;
- String ms = methods[i].getName();
- if (ms.endsWith(baseName)) {
- boolean isSet = false, isIs = false;
- if ((isSet = ms.startsWith(SET_PREFIX)) || ms.startsWith(GET_PREFIX)
- || (isIs = ms.startsWith(IS_PREFIX))) {
- int prefixLength = (isIs ? 2 : 3);
- if (isSet == findSets) {
- if (baseName.length() == (ms.length() - prefixLength)) {
- if (result == null) {
- result = new ArrayList();
- }
- result.add(methods[i]);
- }
- }
- }
- }
- }
- }
- if (propertyCache == null) {
- cache.put(targetClass, propertyCache = new HashMap(101));
- }
- propertyCache.put(propertyName, (result == null) ? NotFoundList : result);
- }
- return (result == NotFoundList) ? null : result;
- }
- }
- /**
- * Convenience used to check if a method is volatile or synthetic so as to avoid
- * calling un-callable methods.
- *
- * @param m The method to check.
- * @return True if the method should be callable, false otherwise.
- */
- static boolean isMethodCallable(Method m)
- {
- if ((isJdk15() && m.isSynthetic()) || Modifier.isVolatile(m.getModifiers()))
- return false;
- return true;
- }
- public static Method getGetMethod(OgnlContext context, Class targetClass, String propertyName)
- throws IntrospectionException, OgnlException
- {
- Method result = null;
- List methods = getDeclaredMethods(targetClass, propertyName, false /* find 'get' methods */);
- if (methods != null)
- {
- for (int i = 0, icount = methods.size(); i < icount; i++)
- {
- Method m = (Method) methods.get(i);
- Class[] mParameterTypes = findParameterTypes(targetClass, m); //getParameterTypes(m);
- if (mParameterTypes.length == 0)
- {
- result = m;
- break;
- }
- }
- }
- return result;
- }
- public static boolean isMethodAccessible(OgnlContext context, Object target, Method method, String propertyName)
- {
- return (method != null) && context.getMemberAccess().isAccessible(context, target, method, propertyName);
- }
- public static boolean hasGetMethod(OgnlContext context, Object target, Class targetClass, String propertyName)
- throws IntrospectionException, OgnlException
- {
- return isMethodAccessible(context, target, getGetMethod(context, targetClass, propertyName), propertyName);
- }
- public static Method getSetMethod(OgnlContext context, Class targetClass, String propertyName)
- throws IntrospectionException, OgnlException
- {
- Method result = null;
- List methods = getDeclaredMethods(targetClass, propertyName, true /* find 'set' methods */);
- if (methods != null)
- {
- for (int i = 0, icount = methods.size(); i < icount; i++)
- {
- Method m = (Method) methods.get(i);
- Class[] mParameterTypes = findParameterTypes(targetClass, m); //getParameterTypes(m);
- if (mParameterTypes.length == 1) {
- result = m;
- break;
- }
- }
- }
- return result;
- }
- public static final boolean hasSetMethod(OgnlContext context, Object target, Class targetClass, String propertyName)
- throws IntrospectionException, OgnlException
- {
- return isMethodAccessible(context, target, getSetMethod(context, targetClass, propertyName), propertyName);
- }
- public static final boolean hasGetProperty(OgnlContext context, Object target, Object oname)
- throws IntrospectionException, OgnlException
- {
- Class targetClass = (target == null) ? null : target.getClass();
- String name = oname.toString();
- return hasGetMethod(context, target, targetClass, name) || hasField(context, target, targetClass, name);
- }
- public static final boolean hasSetProperty(OgnlContext context, Object target, Object oname)
- throws IntrospectionException, OgnlException
- {
- Class targetClass = (target == null) ? null : target.getClass();
- String name = oname.toString();
- return hasSetMethod(context, target, targetClass, name) || hasField(context, target, targetClass, name);
- }
- private static final boolean indexMethodCheck(List methods)
- {
- boolean result = false;
- if (methods.size() > 0) {
- Method fm = (Method) methods.get(0);
- Class[] fmpt = getParameterTypes(fm);
- int fmpc = fmpt.length;
- Class lastMethodClass = fm.getDeclaringClass();
- result = true;
- for (int i = 1; result && (i < methods.size()); i++) {
- Method m = (Method) methods.get(i);
- Class c = m.getDeclaringClass();
- // Check to see if more than one method implemented per class
- if (lastMethodClass == c) {
- result = false;
- } else {
- Class[] mpt = getParameterTypes(fm);
- int mpc = fmpt.length;
- if (fmpc != mpc) {
- result = false;
- }
- for (int j = 0; j < fmpc; j++) {
- if (fmpt[j] != mpt[j]) {
- result = false;
- break;
- }
- }
- }
- lastMethodClass = c;
- }
- }
- return result;
- }
- static void findObjectIndexedPropertyDescriptors(Class targetClass, Map intoMap)
- throws OgnlException
- {
- Map allMethods = getMethods(targetClass, false);
- Map pairs = new HashMap(101);
- for (Iterator it = allMethods.keySet().iterator(); it.hasNext();) {
- String methodName = (String) it.next();
- List methods = (List) allMethods.get(methodName);
- /*
- * Only process set/get where there is exactly one implementation of the method per
- * class and those implementations are all the same
- */
- if (indexMethodCheck(methods)) {
- boolean isGet = false, isSet = false;
- Method m = (Method) methods.get(0);
- if (((isSet = methodName.startsWith(SET_PREFIX)) || (isGet = methodName.startsWith(GET_PREFIX)))
- && (methodName.length() > 3)) {
- String propertyName = Introspector.decapitalize(methodName.substring(3));
- Class[] parameterTypes = getParameterTypes(m);
- int parameterCount = parameterTypes.length;
- if (isGet && (parameterCount == 1) && (m.getReturnType() != Void.TYPE)) {
- List pair = (List) pairs.get(propertyName);
- if (pair == null) {
- pairs.put(propertyName, pair = new ArrayList());
- }
- pair.add(m);
- }
- if (isSet && (parameterCount == 2) && (m.getReturnType() == Void.TYPE)) {
- List pair = (List) pairs.get(propertyName);
- if (pair == null) {
- pairs.put(propertyName, pair = new ArrayList());
- }
- pair.add(m);
- }
- }
- }
- }
- for (Iterator it = pairs.keySet().iterator(); it.hasNext();) {
- String propertyName = (String) it.next();
- List methods = (List) pairs.get(propertyName);
- if (methods.size() == 2) {
- Method method1 = (Method) methods.get(0), method2 = (Method) methods.get(1), setMethod = (method1
- .getParameterTypes().length == 2) ? method1 : method2, getMethod = (setMethod == method1) ? method2
- : method1;
- Class keyType = getMethod.getParameterTypes()[0], propertyType = getMethod.getReturnType();
- if (keyType == setMethod.getParameterTypes()[0]) {
- if (propertyType == setMethod.getParameterTypes()[1]) {
- ObjectIndexedPropertyDescriptor propertyDescriptor;
- try {
- propertyDescriptor = new ObjectIndexedPropertyDescriptor(propertyName, propertyType,
- getMethod, setMethod);
- } catch (Exception ex) {
- throw new OgnlException("creating object indexed property descriptor for '" + propertyName
- + "' in " + targetClass, ex);
- }
- intoMap.put(propertyName, propertyDescriptor);
- }
- }
- }
- }
- }
- /**
- * This method returns the property descriptors for the given class as a Map.
- *
- * @param targetClass The class to get the descriptors for.
- * @return Map map of property descriptors for class.
- *
- * @throws IntrospectionException on errors using {@link Introspector}.
- * @throws OgnlException On general errors.
- */
- public static Map getPropertyDescriptors(Class targetClass)
- throws IntrospectionException, OgnlException
- {
- Map result;
- synchronized (_propertyDescriptorCache) {
- if ((result = (Map) _propertyDescriptorCache.get(targetClass)) == null)
- {
- PropertyDescriptor[] pda = Introspector.getBeanInfo(targetClass).getPropertyDescriptors();
- result = new HashMap(101);
- for (int i = 0, icount = pda.length; i < icount; i++)
- {
- // workaround for Introspector bug 6528714 (bugs.sun.com)
- if (pda[i].getReadMethod() != null && !isMethodCallable(pda[i].getReadMethod()))
- {
- pda[i].setReadMethod(findClosestMatchingMethod(targetClass, pda[i].getReadMethod(), pda[i].getName(),
- pda[i].getPropertyType(), true));
- }
- if (pda[i].getWriteMethod() != null && !isMethodCallable(pda[i].getWriteMethod()))
- {
- pda[i].setWriteMethod(findClosestMatchingMethod(targetClass, pda[i].getWriteMethod(), pda[i].getName(),
- pda[i].getPropertyType(), false));
- }
- result.put(pda[i].getName(), pda[i]);
- }
- findObjectIndexedPropertyDescriptors(targetClass, result);
- _propertyDescriptorCache.put(targetClass, result);
- }
- }
- return result;
- }
- /**
- * This method returns a PropertyDescriptor for the given class and property name using a Map
- * lookup (using getPropertyDescriptorsMap()).
- */
- public static PropertyDescriptor getPropertyDescriptor(Class targetClass, String propertyName)
- throws IntrospectionException, OgnlException
- {
- if (targetClass == null)
- return null;
- return (PropertyDescriptor) getPropertyDescriptors(targetClass).get(propertyName);
- }
- static Method findClosestMatchingMethod(Class targetClass, Method m, String propertyName,
- Class propertyType, boolean isReadMethod)
- {
- List methods = getDeclaredMethods(targetClass, propertyName, !isReadMethod);
- for (int i=0; i < methods.size(); i++)
- {
- Method method = (Method) methods.get(i);
- if (method.getName().equals(m.getName())
- && m.getReturnType().isAssignableFrom(m.getReturnType())
- && method.getReturnType() == propertyType
- && method.getParameterTypes().length == m.getParameterTypes().length) {
- return method;
- }
- }
- return m;
- }
- public static PropertyDescriptor[] getPropertyDescriptorsArray(Class targetClass)
- throws IntrospectionException
- {
- PropertyDescriptor[] result = null;
- if (targetClass != null) {
- synchronized (_propertyDescriptorCache) {
- if ((result = (PropertyDescriptor[]) _propertyDescriptorCache.get(targetClass)) == null) {
- _propertyDescriptorCache.put(targetClass, result = Introspector.getBeanInfo(targetClass)
- .getPropertyDescriptors());
- }
- }
- }
- return result;
- }
- /**
- * Gets the property descriptor with the given name for the target class given.
- *
- * @param targetClass Class for which property descriptor is desired
- * @param name Name of property
- * @return PropertyDescriptor of the named property or null if the class has no property with
- * the given name
- */
- public static PropertyDescriptor getPropertyDescriptorFromArray(Class targetClass, String name)
- throws IntrospectionException
- {
- PropertyDescriptor result = null;
- PropertyDescriptor[] pda = getPropertyDescriptorsArray(targetClass);
- for (int i = 0, icount = pda.length; (result == null) && (i < icount); i++) {
- if (pda[i].getName().compareTo(name) == 0) {
- result = pda[i];
- }
- }
- return result;
- }
- public static void setMethodAccessor(Class cls, MethodAccessor accessor)
- {
- synchronized (_methodAccessors) {
- _methodAccessors.put(cls, accessor);
- }
- }
- public static MethodAccessor getMethodAccessor(Class cls)
- throws OgnlException
- {
- MethodAccessor answer = (MethodAccessor) getHandler(cls, _methodAccessors);
- if (answer != null)
- return answer;
- throw new OgnlException("No method accessor for " + cls);
- }
- public static void setPropertyAccessor(Class cls, PropertyAccessor accessor)
- {
- synchronized (_propertyAccessors) {
- _propertyAccessors.put(cls, accessor);
- }
- }
- public static PropertyAccessor getPropertyAccessor(Class cls)
- throws OgnlException
- {
- PropertyAccessor answer = (PropertyAccessor) getHandler(cls, _propertyAccessors);
- if (answer != null)
- return answer;
- throw new OgnlException("No property accessor for class " + cls);
- }
- public static ElementsAccessor getElementsAccessor(Class cls)
- throws OgnlException
- {
- ElementsAccessor answer = (ElementsAccessor) getHandler(cls, _elementsAccessors);
- if (answer != null)
- return answer;
- throw new OgnlException("No elements accessor for class " + cls);
- }
- public static void setElementsAccessor(Class cls, ElementsAccessor accessor)
- {
- synchronized (_elementsAccessors) {
- _elementsAccessors.put(cls, accessor);
- }
- }
- public static NullHandler getNullHandler(Class cls)
- throws OgnlException
- {
- NullHandler answer = (NullHandler) getHandler(cls, _nullHandlers);
- if (answer != null)
- return answer;
- throw new OgnlException("No null handler for class " + cls);
- }
- public static void setNullHandler(Class cls, NullHandler handler)
- {
- synchronized (_nullHandlers) {
- _nullHandlers.put(cls, handler);
- }
- }
- private static Object getHandler(Class forClass, ClassCache handlers)
- {
- Object answer = null;
- synchronized (handlers) {
- if ((answer = handlers.get(forClass)) == null) {
- Class keyFound;
- if (forClass.isArray()) {
- answer = handlers.get(Object[].class);
- keyFound = null;
- } else {
- keyFound = forClass;
- outer:
- for (Class c = forClass; c != null; c = c.getSuperclass()) {
- answer = handlers.get(c);
- if (answer == null) {
- Class[] interfaces = c.getInterfaces();
- for (int index = 0, count = interfaces.length; index < count; ++index) {
- Class iface = interfaces[index];
- answer = handlers.get(iface);
- if (answer == null) {
- /* Try super-interfaces */
- answer = getHandler(iface, handlers);
- }
- if (answer != null) {
- keyFound = iface;
- break outer;
- }
- }
- } else {
- keyFound = c;
- break;
- }
- }
- }
- if (answer != null) {
- if (keyFound != forClass) {
- handlers.put(forClass, answer);
- }
- }
- }
- }
- return answer;
- }
- public static Object getProperty(OgnlContext context, Object source, Object name)
- throws OgnlException
- {
- PropertyAccessor accessor;
- if (source == null)
- {
- throw new OgnlException("source is null for getProperty(null, \"" + name + "\")");
- }
- if ((accessor = getPropertyAccessor(getTargetClass(source))) == null)
- {
- throw new OgnlException("No property accessor for " + getTargetClass(source).getName());
- }
- return accessor.getProperty(context, source, name);
- }
- public static void setProperty(OgnlContext context, Object target, Object name, Object value)
- throws OgnlException
- {
- PropertyAccessor accessor;
- if (target == null) {
- throw new OgnlException("target is null for setProperty(null, \"" + name + "\", " + value + ")");
- }
- if ((accessor = getPropertyAccessor(getTargetClass(target))) == null) {
- throw new OgnlException("No property accessor for " + getTargetClass(target).getName());
- }
- accessor.setProperty(context, target, name, value);
- }
- /**
- * Determines the index property type, if any. Returns <code>INDEXED_PROPERTY_NONE</code> if
- * the property is not index-accessible as determined by OGNL or JavaBeans. If it is indexable
- * then this will return whether it is a JavaBeans indexed property, conforming to the indexed
- * property patterns (returns <code>INDEXED_PROPERTY_INT</code>) or if it conforms to the
- * OGNL arbitrary object indexable (returns <code>INDEXED_PROPERTY_OBJECT</code>).
- */
- public static int getIndexedPropertyType(OgnlContext context, Class sourceClass, String name)
- throws OgnlException
- {
- int result = INDEXED_PROPERTY_NONE;
- try {
- PropertyDescriptor pd = getPropertyDescriptor(sourceClass, name);
- if (pd != null) {
- if (pd instanceof IndexedPropertyDescriptor) {
- result = INDEXED_PROPERTY_INT;
- } else {
- if (pd instanceof ObjectIndexedPropertyDescriptor) {
- result = INDEXED_PROPERTY_OBJECT;
- }
- }
- }
- } catch (Exception ex) {
- throw new OgnlException("problem determining if '" + name + "' is an indexed property", ex);
- }
- return result;
- }
- public static Object getIndexedProperty(OgnlContext context, Object source, String name, Object index)
- throws OgnlException
- {
- Object[] args = _objectArrayPool.create(index);
- try {
- PropertyDescriptor pd = getPropertyDescriptor((source == null) ? null : source.getClass(), name);
- Method m;
- if (pd instanceof IndexedPropertyDescriptor) {
- m = ((IndexedPropertyDescriptor) pd).getIndexedReadMethod();
- } else {
- if (pd instanceof ObjectIndexedPropertyDescriptor) {
- m = ((ObjectIndexedPropertyDescriptor) pd).getIndexedReadMethod();
- } else {
- throw new OgnlException("property '" + name + "' is not an indexed property");
- }
- }
- return callMethod(context, source, m.getName(), args);
- } catch (OgnlException ex) {
- throw ex;
- } catch (Exception ex) {
- throw new OgnlException("getting indexed property descriptor for '" + name + "'", ex);
- } finally {
- _objectArrayPool.recycle(args);
- }
- }
- public static void setIndexedProperty(OgnlContext context, Object source, String name, Object index,
- Object value)
- throws OgnlException
- {
- Object[] args = _objectArrayPool.create(index, value);
- try {
- PropertyDescriptor pd = getPropertyDescriptor((source == null) ? null : source.getClass(), name);
- Method m;
- if (pd instanceof IndexedPropertyDescriptor) {
- m = ((IndexedPropertyDescriptor) pd).getIndexedWriteMethod();
- } else {
- if (pd instanceof ObjectIndexedPropertyDescriptor) {
- m = ((ObjectIndexedPropertyDescriptor) pd).getIndexedWriteMethod();
- } else {
- throw new OgnlException("property '" + name + "' is not an indexed property");
- }
- }
- callMethod(context, source, m.getName(), args);
- } catch (OgnlException ex) {
- throw ex;
- } catch (Exception ex) {
- throw new OgnlException("getting indexed property descriptor for '" + name + "'", ex);
- } finally {
- _objectArrayPool.recycle(args);
- }
- }
- public static EvaluationPool getEvaluationPool()
- {
- return _evaluationPool;
- }
- public static ObjectArrayPool getObjectArrayPool()
- {
- return _objectArrayPool;
- }
- /**
- * Registers the specified {@link ClassCacheInspector} with all class reflection based internal
- * caches. This may have a significant performance impact so be careful using this in production scenarios.
- *
- * @param inspector
- * The inspector instance that will be registered with all internal cache instances.
- */
- public static void setClassCacheInspector(ClassCacheInspector inspector)
- {
- _cacheInspector = inspector;
- _propertyDescriptorCache.setClassInspector(_cacheInspector);
- _constructorCache.setClassInspector(_cacheInspector);
- _staticMethodCache.setClassInspector(_cacheInspector);
- _instanceMethodCache.setClassInspector(_cacheInspector);
- _invokePermissionCache.setClassInspector(_cacheInspector);
- _fieldCache.setClassInspector(_cacheInspector);
- _declaredMethods[0].setClassInspector(_cacheInspector);
- _declaredMethods[1].setClassInspector(_cacheInspector);
- }
- public static Method getMethod(OgnlContext context, Class target, String name,
- Node[] children, boolean includeStatic)
- throws Exception
- {
- Class[] parms;
- if (children != null && children.length > 0)
- {
- parms = new Class[children.length];
- // used to reset context after loop
- Class currType = context.getCurrentType();
- Class currAccessor = context.getCurrentAccessor();
- Object cast = context.get(ExpressionCompiler.PRE_CAST);
- context.setCurrentObject(context.getRoot());
- context.setCurrentType(context.getRoot() != null ? context.getRoot().getClass() : null);
- context.setCurrentAccessor(null);
- context.setPreviousType(null);
- for (int i=0; i < children.length; i++)
- {
- children[i].toGetSourceString(context, context.getRoot());
- parms[i] = context.getCurrentType();
- }
- context.put(ExpressionCompiler.PRE_CAST, cast);
- context.setCurrentType(currType);
- context.setCurrentAccessor(currAccessor);
- context.setCurrentObject(target);
- } else
- {
- parms = new Class[0];
- }
- List methods = OgnlRuntime.getMethods(target, name, includeStatic);
- if (methods == null)
- return null;
- for (int i = 0; i < methods.size(); i++)
- {
- Method m = (Method) methods.get(i);
- boolean varArgs = isJdk15() && m.isVarArgs();
- if (parms.length != m.getParameterTypes().length && !varArgs)
- continue;
- Class[] mparms = m.getParameterTypes();
- boolean matched = true;
- for (int p = 0; p < mparms.length; p++)
- {
- if (varArgs && mparms[p].isArray()){
- continue;
- }
- if (parms[p] == null)
- {
- matched = false;
- break;
- }
- if (parms[p] == mparms[p])
- continue;
- if (mparms[p].isPrimitive()
- && Character.TYPE != mparms[p] && Byte.TYPE != mparms[p]
- && Number.class.isAssignableFrom(parms[p])
- && OgnlRuntime.getPrimitiveWrapperClass(parms[p]) == mparms[p])
- {
- continue;
- }
- matched = false;
- break;
- }
- if (matched)
- return m;
- }
- return null;
- }
- /**
- * Finds the best possible match for a method on the specified target class with a matching
- * name.
- *
- * <p>
- * The name matched will also try different combinations like <code>is + name, has + name, get + name, etc..</code>
- * </p>
- *
- * @param target
- * The class to find a matching method against.
- * @param name
- * The name of the method.
- * @return The most likely matching {@link Method}, or null if none could be found.
- */
- public static Method getReadMethod(Class target, String name)
- {
- return getReadMethod(target, name, -1);
- }
- public static Method getReadMethod(Class target, String name, int numParms)
- {
- try {
- name = name.replaceAll("\"", "").toLowerCase();
- BeanInfo info = Introspector.getBeanInfo(target);
- MethodDescriptor[] methods = info.getMethodDescriptors();
- // exact matches first
- Method m = null;
- for (int i = 0; i < methods.length; i++)
- {
- if (!isMethodCallable(methods[i].getMethod()))
- continue;
- if ((methods[i].getName().equalsIgnoreCase(name)
- || methods[i].getName().toLowerCase().equals(name)
- || methods[i].getName().toLowerCase().equals("get" + name)
- || methods[i].getName().toLowerCase().equals("has" + name)
- || methods[i].getName().toLowerCase().equals("is" + name))
- && !methods[i].getName().startsWith("set"))
- {
- if (numParms > 0 && methods[i].getMethod().getParameterTypes().length == numParms)
- return methods[i].getMethod();
- else if (numParms < 0)
- {
- if ((m != null && m.getParameterTypes().length > methods[i].getMethod().getParameterTypes().length)
- || m == null)
- {
- m = methods[i].getMethod();
- }
- }
- }
- }
- if (m != null)
- return m;
- for (int i = 0; i < methods.length; i++)
- {
- if (!isMethodCallable(methods[i].getMethod()))
- continue;
- if (methods[i].getName().toLowerCase().endsWith(name)
- && !methods[i].getName().startsWith("set")
- && methods[i].getMethod().getReturnType() != Void.TYPE) {
- if (numParms > 0 && methods[i].getMethod().getParameterTypes().length == numParms)
- return methods[i].getMethod();
- else if (numParms < 0)
- {
- if ((m != null && m.getParameterTypes().length > methods[i].getMethod().getParameterTypes().length)
- || m == null)
- {
- m = methods[i].getMethod();
- }
- }
- }
- }
- if (m != null)
- return m;
- // try one last time adding a get to beginning
- if (!name.startsWith("get"))
- return OgnlRuntime.getReadMethod(target, "get" + name, numParms);
- } catch (Throwable t)
- {
- throw OgnlOps.castToRuntime(t);
- }
- return null;
- }
- public static Method getWriteMethod(Class target, String name)
- {
- return getWriteMethod(target, name, -1);
- }
- public static Method getWriteMethod(Class target, String name, int numParms)
- {
- try {
- name = name.replaceAll("\"", "");
- BeanInfo info = Introspector.getBeanInfo(target);
- MethodDescriptor[] methods = info.getMethodDescriptors();
- for (int i = 0; i < methods.length; i++) {
- if (!isMethodCallable(methods[i].getMethod()))
- continue;
- if ((methods[i].getName().equalsIgnoreCase(name)
- || methods[i].getName().toLowerCase().equals(name.toLowerCase())
- || methods[i].getName().toLowerCase().equals("set" + name.toLowerCase()))
- && !methods[i].getName().startsWith("get")) {
- if (numParms > 0 && methods[i].getMethod().getParameterTypes().length == numParms)
- return methods[i].getMethod();
- else if (numParms < 0)
- return methods[i].getMethod();
- }
- }
- // try again on pure class
- Method[] cmethods = target.getClass().getMethods();
- for (int i = 0; i < cmethods.length; i++) {
- if (!isMethodCallable(cmethods[i]))
- continue;
- if ((cmethods[i].getName().equalsIgnoreCase(name)
- || cmethods[i].getName().toLowerCase().equals(name.toLowerCase())
- || cmethods[i].getName().toLowerCase().equals("set" + name.toLowerCase()))
- && !cmethods[i].getName().startsWith("get")) {
- if (numParms > 0 && cmethods[i].getParameterTypes().length == numParms)
- return cmethods[i];
- else if (numParms < 0)
- return cmethods[i];
- }
- }
- // try one last time adding a set to beginning
- if (!name.startsWith("set")) {
- return OgnlRuntime.getReadMethod(target, "set" + name, numParms);
- }
- } catch (Throwable t)
- {
- throw OgnlOps.castToRuntime(t);
- }
- return null;
- }
- public static PropertyDescriptor getProperty(Class target, String name)
- {
- try {
- BeanInfo info = Introspector.getBeanInfo(target);
- PropertyDescriptor[] pds = info.getPropertyDescriptors();
- for (int i = 0; i < pds.length; i++) {
- if (pds[i].getName().equalsIgnoreCase(name)
- || pds[i].getName().toLowerCase().equals(name.toLowerCase())
- || pds[i].getName().toLowerCase().endsWith(name.toLowerCase()))
- return pds[i];
- }
- } catch (Throwable t)
- {
- throw OgnlOps.castToRuntime(t);
- }
- return null;
- }
- public static boolean isBoolean(String expression)
- {
- if (expression == null)
- return false;
- if ("true".equals(expression) || "false".equals(expression)
- || "!true".equals(expression) || "!false".equals(expression)
- || "(true)".equals(expression)
- || "!(true)".equals(expression)
- || "(false)".equals(expression)
- || "!(false)".equals(expression)
- || expression.startsWith("org.apache.commons.ognl.OgnlOps"))
- return true;
- return false;
- }
- /**
- * Compares the {@link OgnlContext#getCurrentType()} and {@link OgnlContext#getPreviousType()} class types
- * on the stack to determine if a numeric expression should force object conversion.
- * <p/>
- * <p/>
- * Normally used in conjunction with the <code>forceConversion</code> parameter of
- * {@link OgnlRuntime#getChildSource(OgnlContext,Object,Node,boolean)}.
- * </p>
- *
- * @param context The current context.
- * @return True, if the class types on the stack wouldn't be comparable in a pure numeric expression such as <code>o1 >= o2</code>.
- */
- public static boolean shouldConvertNumericTypes(OgnlContext context)
- {
- if (context.getCurrentType() == null || context.getPreviousType() == null)
- return true;
- if (context.getCurrentType() == context.getPreviousType()
- && context.getCurrentType().isPrimitive() && context.getPreviousType().isPrimitive())
- return false;
- return context.getCurrentType() != null && !context.getCurrentType().isArray()
- && context.getPreviousType() != null && !context.getPreviousType().isArray();
- }
- /**
- * Attempts to get the java source string represented by the specific child expression
- * via the {@link JavaSource#toGetSourceString(OgnlContext,Object)} interface method.
- *
- * @param context The ognl context to pass to the child.
- * @param target The current object target to use.
- * @param child The child expression.
- * @return The result of calling {@link JavaSource#toGetSourceString(OgnlContext,Object)} plus additional
- * enclosures of {@link OgnlOps#convertValue(Object,Class,boolean)} for conversions.
- * @throws OgnlException Mandatory exception throwing catching.. (blehh)
- */
- public static String getChildSource(OgnlContext context, Object target, Node child)
- throws OgnlException
- {
- return getChildSource(context, target, child, false);
- }
- /**
- * Attempts to get the java source string represented by the specific child expression
- * via the {@link JavaSource#toGetSourceString(OgnlContext,Object)} interface method.
- *
- * @param context The ognl context to pass to the child.
- * @param target The current object target to use.
- * @param child The child expression.
- * @param forceConversion If true, forces {@link OgnlOps#convertValue(Object,Class)} conversions on the objects.
- * @return The result of calling {@link JavaSource#toGetSourceString(OgnlContext,Object)} plus additional
- * enclosures of {@link OgnlOps#convertValue(Object,Class,boolean)} for conversions.
- * @throws OgnlException Mandatory exception throwing catching.. (blehh)
- */
- public static String getChildSource(OgnlContext context, Object target, Node child, boolean forceConversion)
- throws OgnlException
- {
- String pre = (String) context.get("_currentChain");
- if (pre == null)
- pre = "";
- try
- {
- child.getValue(context, target);
- } catch (NullPointerException e)
- {
- // ignore
- } catch (ArithmeticException e)
- {
- context.setCurrentType(int.class);
- return "0";
- } catch (Throwable t)
- {
- throw OgnlOps.castToRuntime(t);
- }
- String source = null;
- try
- {
- source = child.toGetSourceString(context, target);
- }
- catch (Throwable t)
- {
- throw OgnlOps.castToRuntime(t);
- }
- // handle root / method expressions that may not have proper root java source access
- if (!ASTConst.class.isInstance(child)
- && (target == null || context.getRoot() != target))
- {
- source = pre + source;
- }
- if (context.getRoot() != null)
- {
- source = ExpressionCompiler.getRootExpression(child, context.getRoot(), context) + source;
- context.setCurrentAccessor(context.getRoot().getClass());
- }
- if (ASTChain.class.isInstance(child))
- {
- String cast = (String) context.remove(ExpressionCompiler.PRE_CAST);
- if (cast == null)
- cast = "";
- source = cast + source;
- }
- if (source == null || source.trim().length() < 1)
- source = "null";
- return source;
- }
- }