[Adapdev-commits] Adapdev/src/Adapdev.NVelocity/Util/Introspection AmbiguousException.cs,1.4,1.5 Cla
Status: Beta
Brought to you by:
intesar66
Update of /cvsroot/adapdev/Adapdev/src/Adapdev.NVelocity/Util/Introspection In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv909/src/Adapdev.NVelocity/Util/Introspection Added Files: AmbiguousException.cs ClassMap.cs IntrospectionCacheData.cs Introspector.cs IntrospectorBase.cs MethodMap.cs Twonk.cs Log Message: --- NEW FILE: MethodMap.cs --- namespace NVelocity.Util.Introspection { using System; using System.Collections; using System.Reflection; public class MethodMap { public MethodMap() { } /// <summary> Keep track of all methods with the same name. /// </summary> //UPGRADE_NOTE: The initialization of 'methodByNameMap' was moved to method 'InitBlock'. 'ms-help://MS.VSCC/commoner/redir/redirect.htm?keyword="jlca1005"' internal Hashtable methodByNameMap = new Hashtable(); /// <summary> Add a method to a list of methods by name. /// For a particular class we are keeping track /// of all the methods with the same name. /// </summary> public virtual void add(MethodInfo method) { String methodName = method.Name; IList l = (IList) methodByNameMap[methodName]; if (l == null) { l = new ArrayList(); methodByNameMap[methodName] = l; } l.Add(method); return; } /// <summary> Return a list of methods with the same name. /// </summary> /// <param name="String">key /// </param> /// <returns>List list of methods /// /// </returns> public virtual IList get(String key) { return (IList) methodByNameMap[key]; } /// <summary> <p> /// Find a method. Attempts to find the /// most appropriate method using the /// sense of 'specificity'. /// </p> /// /// <p> /// This turns out to be a relatively rare case /// where this is needed - however, functionality /// like this is needed. This may not be the /// optimum approach, but it works. /// </p> /// </summary> /// <param name="String">name of method /// </param> /// <param name="Object[]">params /// </param> /// <returns>Method /// /// </returns> public virtual MethodInfo find(String methodName, Object[] params_Renamed) { IList methodList = (IList) methodByNameMap[methodName]; if (methodList == null) { return null; } Type[] parameterTypes = null; MethodInfo method = null; int numMethods = methodList.Count; int bestDistance = - 2; MethodInfo bestMethod = null; Twonk bestTwonk = null; bool ambiguous = false; for (int i = 0; i < numMethods; i++) { method = (MethodInfo) methodList[i]; parameterTypes = GetMethodParameterTypes(method); /* * The methods we are trying to compare must * the same number of arguments. */ if (parameterTypes.Length == params_Renamed.Length) { /* * use the calling parameters as the baseline * and calculate the 'distance' from the parameters * to the method args. This will be useful when * determining specificity */ Twonk twonk = calcDistance(params_Renamed, parameterTypes); if (twonk != null) { /* * if we don't have anything yet, take it */ if (bestTwonk == null) { bestTwonk = twonk; bestMethod = method; } else { /* * now see which is more specific, this current * versus what we think of as the best candidate */ int val = twonk.moreSpecific(bestTwonk); //System.out.println("Val = " + val + " for " + method + " vs " + bestMethod ); if (val == 0) { /* * this means that the parameters 'crossed' * therefore, it's ambiguous because one is as * good as the other */ ambiguous = true; } else if (val == 1) { /* * the current method is clearly more * specific than the current best, so * we take the current we are testing * and clear the ambiguity flag */ ambiguous = false; bestTwonk = twonk; bestMethod = method; } } } } } /* * if ambiguous is true, it means we couldn't decide * so inform the caller... */ if (ambiguous) { throw new AmbiguousException(); } return bestMethod; } /// <summary> Calculates the distance, expressed as a vector of inheritance /// steps, between the calling args and the method args. /// There still is an issue re interfaces... /// </summary> private Twonk calcDistance(Object[] set, Type[] base_Renamed) { if (set.Length != base_Renamed.Length) return null; Twonk twonk = new Twonk(set.Length); int distance = 0; for (int i = 0; i < set.Length; i++) { /* * can I get from here to there? */ Type setclass = set[i].GetType(); if (!base_Renamed[i].IsAssignableFrom(set[i].GetType())) return null; /* * ok, I can. How many steps? */ Type c = setclass; while (c != null) { /* * is this a valid step? */ if (!base_Renamed[i].IsAssignableFrom(c)) { /* * it stopped being assignable - therefore we are looking at * an interface as our target, so move back one step * from the distance as the stop wasn't valid */ break; } if (base_Renamed[i].Equals(c)) { /* * we are equal, so no need to move forward */ break; } c = c.BaseType; twonk.distance++; twonk.vec[i]++; } } return twonk; } private static Type[] GetMethodParameterTypes(MethodInfo method) { ParameterInfo[] parms = method.GetParameters(); Type[] types = new Type[parms.Length]; for (Int32 i = 0; i < parms.Length; i++) { types[i] = parms[i].ParameterType; } return types; } } } --- NEW FILE: AmbiguousException.cs --- namespace NVelocity.Util.Introspection { using System; /// <summary> simple distinguishable exception, used when /// we run across ambiguous overloading /// </summary> public class AmbiguousException : Exception { } } --- NEW FILE: Introspector.cs --- namespace NVelocity.Util.Introspection { using System; using System.Reflection; using NVelocity.Runtime; /// <summary> This basic function of this class is to return a Method /// object for a particular class given the name of a method /// and the parameters to the method in the form of an Object[] /// /// The first time the Introspector sees a /// class it creates a class method map for the /// class in question. Basically the class method map /// is a Hastable where Method objects are keyed by a /// concatenation of the method name and the names of /// classes that make up the parameters. /// /// For example, a method with the following signature: /// /// public void method(String a, StringBuffer b) /// /// would be mapped by the key: /// /// "method" + "java.lang.String" + "java.lang.StringBuffer" /// /// This mapping is performed for all the methods in a class /// and stored for /// </summary> public class Introspector : IntrospectorBase { /// <summary> define a public string so that it can be looked for /// if interested /// </summary> public const String CACHEDUMP_MSG = "Introspector : detected classloader change. Dumping cache."; /// <summary> our engine runtime services /// </summary> private RuntimeServices rsvc = null; /// <summary> Recieves our RuntimeServices object /// </summary> public Introspector(RuntimeServices r) { this.rsvc = r; } /// <summary> Gets the method defined by <code>name</code> and /// <code>params</code> for the Class <code>c</code>. /// </summary> /// <param name="c">Class in which the method search is taking place /// </param> /// <param name="name">Name of the method being searched for /// </param> /// <param name="params">An array of Objects (not Classes) that describe the /// the parameters /// </param> /// <returns>The desired Method object. /// </returns> public override MethodInfo getMethod(Type c, String name, Object[] params_Renamed) { /* * just delegate to the base class */ try { return base.getMethod(c, name, params_Renamed); } catch (AmbiguousException ae) { /* * whoops. Ambiguous. Make a nice log message and return null... */ String msg = "Introspection Error : Ambiguous method invocation " + name + "( "; for (int i = 0; i < params_Renamed.Length; i++) { if (i > 0) msg = msg + ", "; msg = msg + params_Renamed[i].GetType().FullName; } msg = msg + ") for class " + c; rsvc.error(msg); } return null; } /// <summary> Gets the method defined by <code>name</code> and /// <code>params</code> for the Class <code>c</code>. /// </summary> /// <param name="c">Class in which the method search is taking place /// </param> /// <param name="name">Name of the method being searched for /// </param> /// <param name="params">An array of Objects (not Classes) that describe the /// the parameters /// </param> /// <returns>The desired Method object. /// </returns> public override PropertyInfo getProperty(Type c, String name) { /* * just delegate to the base class */ try { return base.getProperty(c, name); } catch (AmbiguousException ae) { /* * whoops. Ambiguous. Make a nice log message and return null... */ String msg = "Introspection Error : Ambiguous property invocation " + name + " "; msg = msg + " for class " + c; rsvc.error(msg); } return null; } /// <summary> Clears the classmap and classname /// caches, and logs that we did so /// </summary> protected internal override void clearCache() { base.clearCache(); rsvc.info(CACHEDUMP_MSG); } } } --- NEW FILE: Twonk.cs --- namespace NVelocity.Util.Introspection { /// <summary> little class to hold 'distance' information /// for calling params, as well as determine /// specificity /// </summary> internal class Twonk { public int distance; public int[] vec; public Twonk(int size) { vec = new int[size]; } public virtual int moreSpecific(Twonk other) { if (other.vec.Length != vec.Length) return - 1; bool low = false; bool high = false; for (int i = 0; i < vec.Length; i++) { if (vec[i] > other.vec[i]) { high = true; } else if (vec[i] < other.vec[i]) { low = true; } } /* * this is a 'crossing' - meaning that * we saw the parameter 'slopes' cross * this means ambiguity */ if (high && low) return 0; /* * we saw that all args were 'high', meaning * that the other method is more specific so * we are less */ if (high && !low) return - 1; /* * we saw that all points were lower, therefore * we are more specific */ if (!high && low) return 1; /* * the remainder, neither high or low * means we are the same. This really can't * happen, as it implies the same args, right? */ return 1; } } } --- NEW FILE: IntrospectorBase.cs --- namespace NVelocity.Util.Introspection { using System; using System.Collections; using System.Reflection; /// <summary> This basic function of this class is to return a Method /// object for a particular class given the name of a method /// and the parameters to the method in the form of an Object[] /// /// The first time the Introspector sees a /// class it creates a class method map for the /// class in question. Basically the class method map /// is a Hastable where Method objects are keyed by a /// concatenation of the method name and the names of /// classes that make up the parameters. /// /// For example, a method with the following signature: /// /// public void method(String a, StringBuffer b) /// /// would be mapped by the key: /// /// "method" + "java.lang.String" + "java.lang.StringBuffer" /// /// This mapping is performed for all the methods in a class /// and stored for /// </summary> /// <author> <a href="mailto:jv...@ap...">Jason van Zyl</a> /// </author> /// <author> <a href="mailto:bo...@we...">Bob McWhirter</a> /// </author> /// <author> <a href="mailto:sze...@fr...">Attila Szegedi</a> /// </author> /// <author> <a href="mailto:pau...@kr...">Paulo Gaspar</a> /// </author> /// <version> $Id: IntrospectorBase.cs,v 1.5 2005/11/16 07:01:52 intesar66 Exp $ /// </version> public class IntrospectorBase { public IntrospectorBase() { } /// <summary> Holds the method maps for the classes we know about, keyed by /// Class object. /// </summary> protected internal Hashtable classMethodMaps = new Hashtable(); /// <summary> Holds the qualified class names for the classes /// we hold in the classMethodMaps hash /// </summary> protected internal IList cachedClassNames = new ArrayList(); /// <summary> Gets the method defined by <code>name</code> and /// <code>params</code> for the Class <code>c</code>. /// </summary> /// <param name="c">Class in which the method search is taking place /// </param> /// <param name="name">Name of the method being searched for /// </param> /// <param name="params">An array of Objects (not Classes) that describe the /// the parameters /// </param> /// <returns>The desired Method object. /// </returns> public virtual MethodInfo getMethod(Type c, String name, Object[] params_Renamed) { if (c == null) { throw new Exception("Introspector.getMethod(): Class method key was null: " + name); } ClassMap classMap = null; lock (classMethodMaps) { classMap = (ClassMap) classMethodMaps[c]; /* * if we don't have this, check to see if we have it * by name. if so, then we have a classloader change * so dump our caches. */ if (classMap == null) { if (cachedClassNames.Contains(c.FullName)) { /* * we have a map for a class with same name, but not * this class we are looking at. This implies a * classloader change, so dump */ clearCache(); } classMap = createClassMap(c); } } return classMap.findMethod(name, params_Renamed); } /// <summary> Gets the method defined by <code>name</code> and /// <code>params</code> for the Class <code>c</code>. /// </summary> /// <param name="c">Class in which the method search is taking place /// </param> /// <param name="name">Name of the method being searched for /// </param> /// <param name="params">An array of Objects (not Classes) that describe the /// the parameters /// </param> /// <returns>The desired Method object. /// </returns> public virtual PropertyInfo getProperty(Type c, String name) { if (c == null) { throw new Exception("Introspector.getMethod(): Class method key was null: " + name); } ClassMap classMap = null; lock (classMethodMaps) { classMap = (ClassMap) classMethodMaps[c]; /* * if we don't have this, check to see if we have it * by name. if so, then we have a classloader change * so dump our caches. */ if (classMap == null) { if (cachedClassNames.Contains(c.FullName)) { /* * we have a map for a class with same name, but not * this class we are looking at. This implies a * classloader change, so dump */ clearCache(); } classMap = createClassMap(c); } } return classMap.findProperty(name); } /// <summary> Creates a class map for specific class and registers it in the /// cache. Also adds the qualified name to the name->class map /// for later Classloader change detection. /// </summary> protected internal virtual ClassMap createClassMap(Type c) { ClassMap classMap = new ClassMap(c); classMethodMaps[c] = classMap; cachedClassNames.Add(c.FullName); return classMap; } /// <summary> Clears the classmap and classname /// caches /// </summary> protected internal virtual void clearCache() { /* * since we are synchronizing on this * object, we have to clear it rather than * just dump it. */ classMethodMaps.Clear(); /* * for speed, we can just make a new one * and let the old one be GC'd */ cachedClassNames = new ArrayList(); } } } --- NEW FILE: ClassMap.cs --- namespace NVelocity.Util.Introspection { using System; using System.Collections; using System.Reflection; using System.Text; /// <summary> A cache of introspection information for a specific class instance. /// Keys {@link java.lang.Method} objects by a concatenation of the /// method name and the names of classes that make up the parameters. /// </summary> public class ClassMap { internal virtual Type CachedClass { get { return clazz; } } private sealed class CacheMiss { } //UPGRADE_NOTE: Final was removed from the declaration of 'CACHE_MISS '. 'ms-help://MS.VSCC/commoner/redir/redirect.htm?keyword="jlca1003"' private static CacheMiss CACHE_MISS = new CacheMiss(); //UPGRADE_NOTE: Final was removed from the declaration of 'OBJECT '. 'ms-help://MS.VSCC/commoner/redir/redirect.htm?keyword="jlca1003"' private static Object OBJECT = new Object(); /// /// <summary> Class passed into the constructor used to as /// the basis for the Method map. /// </summary> private Type clazz; /// <summary> Cache of Methods, or CACHE_MISS, keyed by method /// name and actual arguments used to find it. /// </summary> private Hashtable methodCache = new Hashtable(); private Hashtable propertyCache = new Hashtable(); private MethodMap methodMap = new MethodMap(); /// <summary> Standard constructor /// </summary> public ClassMap(Type clazz) { this.clazz = clazz; populateMethodCache(); populatePropertyCache(); } public ClassMap() { } /// <returns>the class object whose methods are cached by this map. /// </returns> /// <summary> Find a Method using the methodKey /// provided. /// /// Look in the methodMap for an entry. If found, /// it'll either be a CACHE_MISS, in which case we /// simply give up, or it'll be a Method, in which /// case, we return it. /// /// If nothing is found, then we must actually go /// and introspect the method from the MethodMap. /// </summary> public virtual System.Reflection.MethodInfo findMethod(String name, Object[] params_Renamed) { String methodKey = makeMethodKey(name, params_Renamed); Object cacheEntry = methodCache[methodKey]; if (cacheEntry == CACHE_MISS) { return null; } if (cacheEntry == null) { try { cacheEntry = methodMap.find(name, params_Renamed); } catch (AmbiguousException ae) { /* * that's a miss :) */ methodCache[methodKey] = CACHE_MISS; throw ae; } if (cacheEntry == null) { methodCache[methodKey] = CACHE_MISS; } else { methodCache[methodKey] = cacheEntry; } } // Yes, this might just be null. return (System.Reflection.MethodInfo) cacheEntry; } /// <summary> Find a Method using the methodKey /// provided. /// /// Look in the methodMap for an entry. If found, /// it'll either be a CACHE_MISS, in which case we /// simply give up, or it'll be a Method, in which /// case, we return it. /// /// If nothing is found, then we must actually go /// and introspect the method from the MethodMap. /// </summary> public virtual PropertyInfo findProperty(String name) { Object cacheEntry = propertyCache[name]; if (cacheEntry == CACHE_MISS) { return null; } // Yes, this might just be null. return (PropertyInfo) cacheEntry; } /// <summary> Populate the Map of direct hits. These /// are taken from all the public methods /// that our class provides. /// </summary> private void populateMethodCache() { StringBuilder methodKey; /* * get all publicly accessible methods */ System.Reflection.MethodInfo[] methods = getAccessibleMethods(clazz); /* * map and cache them */ for (int i = 0; i < methods.Length; i++) { System.Reflection.MethodInfo method = methods[i]; /* * now get the 'public method', the method declared by a * public interface or class. (because the actual implementing * class may be a facade... */ System.Reflection.MethodInfo publicMethod = getPublicMethod(method); /* * it is entirely possible that there is no public method for * the methods of this class (i.e. in the facade, a method * that isn't on any of the interfaces or superclass * in which case, ignore it. Otherwise, map and cache */ if (publicMethod != null) { methodMap.add(publicMethod); methodCache[makeMethodKey(publicMethod)] = publicMethod; } } } private void populatePropertyCache() { StringBuilder methodKey; /* * get all publicly accessible methods */ PropertyInfo[] properties = getAccessibleProperties(clazz); /* * map and cache them */ for (int i = 0; i < properties.Length; i++) { PropertyInfo property = properties[i]; /* * now get the 'public method', the method declared by a * public interface or class. (because the actual implementing * class may be a facade... */ PropertyInfo publicProperty = getPublicProperty(property); /* * it is entirely possible that there is no public method for * the methods of this class (i.e. in the facade, a method * that isn't on any of the interfaces or superclass * in which case, ignore it. Otherwise, map and cache */ if (publicProperty != null) { //propertyMap.add(publicProperty); propertyCache[publicProperty.Name] = publicProperty; } } } /// <summary> Make a methodKey for the given method using /// the concatenation of the name and the /// types of the method parameters. /// </summary> private String makeMethodKey(System.Reflection.MethodInfo method) { //UPGRADE_TODO: The equivalent in .NET for method 'java.lang.reflect.Method.getParameterTypes' may return a different value. 'ms-help://MS.VSCC/commoner/redir/redirect.htm?keyword="jlca1043"' ParameterInfo[] parameterTypes = method.GetParameters(); StringBuilder methodKey = new StringBuilder(method.Name); for (int j = 0; j < parameterTypes.Length; j++) { /* * If the argument type is primitive then we want * to convert our primitive type signature to the * corresponding Object type so introspection for * methods with primitive types will work correctly. */ // TODO: I don't think that this is needed in .Net - boxing will happen and the types will still be available. // if (parameterTypes[j].GetType().IsPrimitive) { // if (parameterTypes[j].Equals(System.Type.GetType("System.Boolean"))) // methodKey.Append("java.lang.Boolean"); // else if (parameterTypes[j].Equals(System.Type.GetType("System.Byte"))) // methodKey.Append("java.lang.Byte"); // else if (parameterTypes[j].Equals(System.Type.GetType("System.Char"))) // methodKey.Append("java.lang.Character"); // else if (parameterTypes[j].Equals(System.Type.GetType("System.Double"))) // methodKey.Append("java.lang.Double"); // else if (parameterTypes[j].Equals(System.Type.GetType("System.Single"))) // methodKey.Append("java.lang.Float"); // else { // //UPGRADE_TODO: Field java.lang.Integer.TYPE was not converted. 'ms-help://MS.VSCC/commoner/redir/redirect.htm?keyword="jlca1095"' // if (parameterTypes[j].Equals(typeof(Int32))) // methodKey.Append("System.Int32"); // else { // //UPGRADE_TODO: Field java.lang.Long.TYPE was not converted. 'ms-help://MS.VSCC/commoner/redir/redirect.htm?keyword="jlca1095"' // if (parameterTypes[j].Equals(typeof(Int64))) // methodKey.Append("System.Int64"); // else if (parameterTypes[j].Equals(System.Type.GetType("System.Int16"))) // methodKey.Append("System.Int16"); // } // } // } // else { // methodKey.Append(parameterTypes[j].FullName); // } methodKey.Append(parameterTypes[j].ParameterType.FullName); } return methodKey.ToString(); } private static String makeMethodKey(String method, Object[] params_Renamed) { StringBuilder methodKey = new StringBuilder().Append(method); if (params_Renamed != null) { for (int j = 0; j < params_Renamed.Length; j++) { Object arg = params_Renamed[j]; if (arg == null) { arg = OBJECT; } methodKey.Append(arg.GetType().FullName); } } return methodKey.ToString(); } /// <summary> Retrieves public methods for a class. In case the class is not /// public, retrieves methods with same signature as its public methods /// from public superclasses and interfaces (if they exist). Basically /// upcasts every method to the nearest acccessible method. /// </summary> private static System.Reflection.MethodInfo[] getAccessibleMethods(Type clazz) { System.Reflection.MethodInfo[] methods = clazz.GetMethods(); // TODO: the rest of this method is trying to determine what is supposed to be callable - I think .Net just returns what is callable return methods; /* * Short circuit for the (hopefully) majority of cases where the * clazz is public */ //UPGRADE_TODO: Method java.lang.reflect.Modifier.isPublic was not converted. 'ms-help://MS.VSCC/commoner/redir/redirect.htm?keyword="jlca1095"' //UPGRADE_ISSUE: Method 'java.lang.Class.getModifiers' was not converted. 'ms-help://MS.VSCC/commoner/redir/redirect.htm?keyword="jlca1000_javalangClassgetModifiers"' if (clazz.IsPublic) { return methods; } /* * No luck - the class is not public, so we're going the longer way. */ MethodInfo[] methodInfos = new MethodInfo[methods.Length]; for (int i = methods.Length; i-- > 0; ) { methodInfos[i] = new MethodInfo(methods[i]); } int upcastCount = getAccessibleMethods(clazz, methodInfos, 0); /* * Reallocate array in case some method had no accessible counterpart. */ if (upcastCount < methods.Length) { methods = new System.Reflection.MethodInfo[upcastCount]; } int j = 0; for (int i = 0; i < methodInfos.Length; ++i) { MethodInfo methodInfo = methodInfos[i]; if (methodInfo.upcast) { methods[j++] = methodInfo.method; } } return methods; } private static PropertyInfo[] getAccessibleProperties(Type clazz) { PropertyInfo[] properties = clazz.GetProperties(); //TODO return properties; /* * Short circuit for the (hopefully) majority of cases where the * clazz is public */ if (clazz.IsPublic) { return properties; } /* * No luck - the class is not public, so we're going the longer way. */ properties = new PropertyInfo[0]; return properties; // TODO // MethodInfo[] methodInfos = new MethodInfo[methods.Length]; // // for (int i = methods.Length; i-- > 0; ) { // methodInfos[i] = new MethodInfo(methods[i]); // } // // int upcastCount = getAccessibleMethods(clazz, methodInfos, 0); // // /* // * Reallocate array in case some method had no accessible counterpart. // */ // // if (upcastCount < methods.Length) { // methods = new System.Reflection.MethodInfo[upcastCount]; // } // // int j = 0; // for (int i = 0; i < methodInfos.Length; ++i) { // MethodInfo methodInfo = methodInfos[i]; // if (methodInfo.upcast) { // methods[j++] = methodInfo.method; // } // } // return methods; } /// <summary> /// Recursively finds a match for each method, starting with the class, and then /// searching the superclass and interfaces. /// </summary> /// <param name="clazz">Class to check</param> /// <param name="methodInfos">array of methods we are searching to match</param> /// <param name="upcastCount">current number of methods we have matched</param> /// <returns>count of matched methods</returns> private static int getAccessibleMethods(Type clazz, MethodInfo[] methodInfos, int upcastCount) { int l = methodInfos.Length; /* * if this class is public, then check each of the currently * 'non-upcasted' methods to see if we have a match */ //UPGRADE_TODO: Method java.lang.reflect.Modifier.isPublic was not converted. 'ms-help://MS.VSCC/commoner/redir/redirect.htm?keyword="jlca1095"' //UPGRADE_ISSUE: Method 'java.lang.Class.getModifiers' was not converted. 'ms-help://MS.VSCC/commoner/redir/redirect.htm?keyword="jlca1000_javalangClassgetModifiers"' if (clazz.IsPublic) { for (int i = 0; i < l && upcastCount < l; ++i) { try { MethodInfo methodInfo = methodInfos[i]; if (!methodInfo.upcast) { methodInfo.tryUpcasting(clazz); upcastCount++; } } catch (MethodAccessException e) { /* * Intentionally ignored - it means * it wasn't found in the current class */ } } /* * Short circuit if all methods were upcast */ if (upcastCount == l) { return upcastCount; } } /* * Examine superclass */ Type superclazz = clazz.BaseType; if (superclazz != null) { upcastCount = getAccessibleMethods(superclazz, methodInfos, upcastCount); /* * Short circuit if all methods were upcast */ if (upcastCount == l) { return upcastCount; } } /* * Examine interfaces. Note we do it even if superclazz == null. * This is redundant as currently java.lang.Object does not implement * any interfaces, however nothing guarantees it will not in future. */ Type[] interfaces = clazz.GetInterfaces(); for (int i = interfaces.Length; i-- > 0; ) { upcastCount = getAccessibleMethods(interfaces[i], methodInfos, upcastCount); /* * Short circuit if all methods were upcast */ if (upcastCount == l) { return upcastCount; } } return upcastCount; } /// <summary> For a given method, retrieves its publicly accessible counterpart. /// This method will look for a method with same name /// and signature declared in a public superclass or implemented interface of this /// method's declaring class. This counterpart method is publicly callable. /// </summary> /// <param name="method">a method whose publicly callable counterpart is requested. /// </param> /// <returns>the publicly callable counterpart method. Note that if the parameter /// method is itself declared by a public class, this method is an identity /// function. /// </returns> public static System.Reflection.MethodInfo getPublicMethod(System.Reflection.MethodInfo method) { Type clazz = method.DeclaringType; //TODO see other todo messages in this class return method; /* * Short circuit for (hopefully the majority of) cases where the declaring * class is public. */ if (clazz.IsPublic) { return method; } return getPublicMethod(clazz, method.Name, GetMethodParameterTypes(method)); } public static PropertyInfo getPublicProperty(PropertyInfo property) { Type clazz = property.DeclaringType; // TODO: return property; /* * Short circuit for (hopefully the majority of) cases where the declaring * class is public. */ if (clazz.IsPublic) { return property; } //TODO return null; // return getPublicMethod(clazz, method.Name, GetMethodParameterTypes(method)); } /// <summary> Looks up the method with specified name and signature in the first public /// superclass or implemented interface of the class. /// </summary> /// <param name="class">the class whose method is sought /// </param> /// <param name="name">the name of the method /// </param> /// <param name="paramTypes">the classes of method parameters /// </param> private static System.Reflection.MethodInfo getPublicMethod(Type clazz, String name, Type[] paramTypes) { /* * if this class is public, then try to get it */ if (clazz.IsPublic) { try { return clazz.GetMethod(name, (Type[]) paramTypes); } catch (MethodAccessException e) { /* * If the class does not have the method, then neither its * superclass nor any of its interfaces has it so quickly return * null. */ return null; } } /* * try the superclass */ Type superclazz = clazz.BaseType; if (superclazz != null) { System.Reflection.MethodInfo superclazzMethod = getPublicMethod(superclazz, name, paramTypes); if (superclazzMethod != null) { return superclazzMethod; } } /* * and interfaces */ Type[] interfaces = clazz.GetInterfaces(); for (int i = 0; i < interfaces.Length; ++i) { System.Reflection.MethodInfo interfaceMethod = getPublicMethod(interfaces[i], name, paramTypes); if (interfaceMethod != null) { return interfaceMethod; } } return null; } /// <summary> Used for the iterative discovery process for public methods. /// </summary> private sealed class MethodInfo { internal System.Reflection.MethodInfo method; internal String name; internal Type[] parameterTypes; internal bool upcast; internal MethodInfo(System.Reflection.MethodInfo method) { this.method = null; name = method.Name; parameterTypes = GetMethodParameterTypes(method); upcast = false; } internal void tryUpcasting(Type clazz) { method = clazz.GetMethod(name, (Type[]) parameterTypes); name = null; parameterTypes = null; upcast = true; } } private static Type[] GetMethodParameterTypes(System.Reflection.MethodInfo method) { ParameterInfo[] parms = method.GetParameters(); Type[] types = new Type[parms.Length]; for (Int32 i = 0; i < parms.Length; i++) { types[i] = parms[i].ParameterType; } return types; } } } --- NEW FILE: IntrospectionCacheData.cs --- namespace NVelocity.Util.Introspection { using System; /* * The Apache Software License, Version 1.1 * * Copyright (c) 2001 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Velocity", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact ap...@ap.... * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */ /// <summary> Holds information for node-local context data introspection /// information. /// * /// </summary> /// <author> <a href="mailto:ge...@op...">Geir Magnusson Jr.</a> /// </author> /// <version> $Id: IntrospectionCacheData.cs,v 1.5 2005/11/16 07:01:52 intesar66 Exp $ /// /// </version> public class IntrospectionCacheData { /// /// <summary> Object to pair with class - currently either a Method or /// AbstractExecutor. It can be used in any way the using node /// wishes. /// </summary> public Object thingy; /* * Class of context data object associated with the introspection * information */ public Type contextData; } } |