Widening, catch and cope with security exceptions, which are somewhat fiddly,

we can enumerate non-public members on some classes, whereas on other classes
we can't even call getDeclaredFields(). Things work for now and at some point
I'm going to change Presents to eliminate the need for (field) reflection
completely.


git-svn-id: https://samskivert.googlecode.com/svn/trunk@2101 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
mdb
2007-05-08 23:46:15 +00:00
parent 6642bc00e7
commit 92a095968c
+66 -84
View File
@@ -30,16 +30,16 @@ import java.util.*;
* Class object related utility routines. * Class object related utility routines.
* *
* <p> This code was adapted from code provided by Paul Hosler in <a * <p> This code was adapted from code provided by Paul Hosler in <a
* href="http://www.javareport.com/html/from_pages/article.asp?id=4276">an * href="http://www.javareport.com/html/from_pages/article.asp?id=4276">an article</a> for Java
* article</a> for Java Report Online. * Report Online.
*/ */
public class ClassUtil public class ClassUtil
{ {
/** /**
* @param clazz a class. * @param clazz a class.
* *
* @return true if the class is accessible, false otherwise. * @return true if the class is accessible, false otherwise. Presently returns true if the
* Presently returns true if the class is declared public. * class is declared public.
*/ */
public static boolean classIsAccessible (Class clazz) public static boolean classIsAccessible (Class clazz)
{ {
@@ -57,8 +57,8 @@ public class ClassUtil
} }
/** /**
* Add all the fields of the specifed class (and its ancestors) to the * Add all the fields of the specifed class (and its ancestors) to the list. Note, if we are
* list. * running in a sandbox, this will only enumerate public members.
*/ */
public static void getFields (Class clazz, List<Field> addTo) public static void getFields (Class clazz, List<Field> addTo)
{ {
@@ -67,20 +67,27 @@ public class ClassUtil
if (pclazz != null && !pclazz.equals(Object.class)) { if (pclazz != null && !pclazz.equals(Object.class)) {
getFields(pclazz, addTo); getFields(pclazz, addTo);
} }
// then reflect on this class's declared fields // then reflect on this class's declared fields
Field[] fields = clazz.getDeclaredFields(); Field[] fields;
try {
fields = clazz.getDeclaredFields();
} catch (SecurityException se) {
System.err.println("Unable to get declared fields of " + clazz.getName() + ": " + se);
fields = new Field[0];
}
// override the default accessibility check for the fields // override the default accessibility check for the fields
AccessibleObject.setAccessible(fields, true); try {
AccessibleObject.setAccessible(fields, true);
} catch (SecurityException se) {
// ah well, only publics for us
}
int fcount = fields.length; for (Field field : fields) {
for (int ii = 0; ii < fcount; ii++) {
Field field = fields[ii];
int mods = field.getModifiers(); int mods = field.getModifiers();
// skip static and transient fields if (Modifier.isStatic(mods) || Modifier.isTransient(mods)) {
if (((mods & Modifier.STATIC) != 0) || continue; // skip static and transient fields
((mods & Modifier.TRANSIENT) != 0)) {
continue;
} }
addTo.add(field); addTo.add(field);
} }
@@ -89,41 +96,32 @@ public class ClassUtil
/** /**
* @param args an object array. * @param args an object array.
* *
* @return an array of Class objects representing the classes of the * @return an array of Class objects representing the classes of the objects in the given
* objects in the given Object array. If args is null, a zero-length * Object array. If args is null, a zero-length Class array is returned. If an element in
* Class array is returned. If an element in args is null, then * args is null, then Void.TYPE is the corresponding Class in the return array.
* Void.TYPE is the corresponding Class in the return array.
*/ */
public static Class[] getParameterTypesFrom (Object[] args) public static Class[] getParameterTypesFrom (Object[] args)
{ {
Class[] argTypes = null; Class[] argTypes = null;
if (args != null) { if (args != null) {
argTypes = new Class[args.length]; argTypes = new Class[args.length];
for (int i = 0; i < args.length; ++i) { for (int i = 0; i < args.length; ++i) {
argTypes[i] = (args[i] == null) ? argTypes[i] = (args[i] == null) ? Void.TYPE : args[i].getClass();
Void.TYPE : args[i].getClass();
} }
} else { } else {
argTypes = new Class[0]; argTypes = new Class[0];
} }
return argTypes; return argTypes;
} }
/** /**
* Tells whether instances of the classes in the 'rhs' array could be * Tells whether instances of the classes in the 'rhs' array could be used as parameters to a
* used as parameters to a reflective method invocation whose * reflective method invocation whose parameter list has types denoted by the 'lhs' array.
* parameter list has types denoted by the 'lhs' array.
* *
* @param lhs Class array representing the types of the formal * @param lhs Class array representing the types of the formal parameters of a method.
* parameters of a method. * @param rhs Class array representing the types of the actual parameters of a method. A null
* @param rhs Class array representing the types of the actual * value or Void.TYPE is considered to match a corresponding Object or array class in lhs, but
* parameters of a method. A null value or Void.TYPE is considered to * not a primitive.
* match a corresponding Object or array class in lhs, but not a
* primitive.
* *
* @return true if compatible, false otherwise. * @return true if compatible, false otherwise.
*/ */
@@ -135,17 +133,19 @@ public class ClassUtil
for (int i = 0; i < lhs.length; ++i) { for (int i = 0; i < lhs.length; ++i) {
if (rhs[i] == null || rhs[i].equals(Void.TYPE)) { if (rhs[i] == null || rhs[i].equals(Void.TYPE)) {
if (lhs[i].isPrimitive()) if (lhs[i].isPrimitive()) {
return false; return false;
else } else {
continue; continue;
}
} }
if (!lhs[i].isAssignableFrom(rhs[i])) { if (!lhs[i].isAssignableFrom(rhs[i])) {
Class<?> lhsPrimEquiv = primitiveEquivalentOf(lhs[i]); Class<?> lhsPrimEquiv = primitiveEquivalentOf(lhs[i]);
Class<?> rhsPrimEquiv = primitiveEquivalentOf(rhs[i]); Class<?> rhsPrimEquiv = primitiveEquivalentOf(rhs[i]);
if (!primitiveIsAssignableFrom(lhsPrimEquiv, rhsPrimEquiv)) if (!primitiveIsAssignableFrom(lhsPrimEquiv, rhsPrimEquiv)) {
return false; return false;
}
} }
} }
@@ -153,20 +153,16 @@ public class ClassUtil
} }
/** /**
* Searches for the method with the given name and formal parameter * Searches for the method with the given name and formal parameter types that is in the
* types that is in the nearest accessible class in the class * nearest accessible class in the class hierarchy, starting with clazz's superclass. The
* hierarchy, starting with clazz's superclass. The superclass and * superclass and implemented interfaces of clazz are searched, then their superclasses,
* implemented interfaces of clazz are searched, then their * etc. until a method is found. Returns null if there is no such method.
* superclasses, etc. until a method is found. Returns null if there
* is no such method.
* *
* @param clazz a class. * @param clazz a class.
* @param methodName name of a method. * @param methodName name of a method.
* @param parameterTypes Class array representing the types of a * @param parameterTypes Class array representing the types of a method's formal parameters.
* method's formal parameters.
* *
* @return the nearest method located, or null if there is no such * @return the nearest method located, or null if there is no such method.
* method.
*/ */
public static Method getAccessibleMethodFrom ( public static Method getAccessibleMethodFrom (
Class clazz, String methodName, Class[] parameterTypes) Class clazz, String methodName, Class[] parameterTypes)
@@ -177,9 +173,9 @@ public class ClassUtil
if (superclass != null && classIsAccessible(superclass)) { if (superclass != null && classIsAccessible(superclass)) {
try { try {
overriddenMethod = overriddenMethod = superclass.getMethod(methodName, parameterTypes);
superclass.getMethod(methodName, parameterTypes); } catch (NoSuchMethodException nsme) {
} catch (NoSuchMethodException _) { // no problem
} }
if (overriddenMethod != null) { if (overriddenMethod != null) {
@@ -187,21 +183,18 @@ public class ClassUtil
} }
} }
// If here, then clazz represents Object, or an interface, or the // If here, then clazz represents Object, or an interface, or the superclass did not have
// superclass did not have an override. Check implemented // an override. Check implemented interfaces.
// interfaces.
Class[] interfaces = clazz.getInterfaces(); Class[] interfaces = clazz.getInterfaces();
for (int i = 0; i < interfaces.length; ++i) { for (int i = 0; i < interfaces.length; ++i) {
overriddenMethod = null; overriddenMethod = null;
if (classIsAccessible(interfaces[i])) { if (classIsAccessible(interfaces[i])) {
try { try {
overriddenMethod = overriddenMethod = interfaces[i].getMethod(methodName, parameterTypes);
interfaces[i].getMethod(methodName, parameterTypes); } catch (NoSuchMethodException nsme) {
} catch (NoSuchMethodException _) { // no problem
} }
if (overriddenMethod != null) { if (overriddenMethod != null) {
return overriddenMethod; return overriddenMethod;
} }
@@ -212,9 +205,7 @@ public class ClassUtil
// Try superclass's superclass and implemented interfaces. // Try superclass's superclass and implemented interfaces.
if (superclass != null) { if (superclass != null) {
overriddenMethod = getAccessibleMethodFrom( overriddenMethod = getAccessibleMethodFrom(superclass, methodName, parameterTypes);
superclass, methodName, parameterTypes);
if (overriddenMethod != null) { if (overriddenMethod != null) {
return overriddenMethod; return overriddenMethod;
} }
@@ -222,9 +213,7 @@ public class ClassUtil
// Try implemented interfaces' extended interfaces... // Try implemented interfaces' extended interfaces...
for (int i = 0; i < interfaces.length; ++i) { for (int i = 0; i < interfaces.length; ++i) {
overriddenMethod = getAccessibleMethodFrom( overriddenMethod = getAccessibleMethodFrom(interfaces[i], methodName, parameterTypes);
interfaces[i], methodName, parameterTypes);
if (overriddenMethod != null) { if (overriddenMethod != null) {
return overriddenMethod; return overriddenMethod;
} }
@@ -237,9 +226,8 @@ public class ClassUtil
/** /**
* @param clazz a Class. * @param clazz a Class.
* *
* @return the class's primitive equivalent, if clazz is a primitive * @return the class's primitive equivalent, if clazz is a primitive wrapper. If clazz is
* wrapper. If clazz is primitive, returns clazz. Otherwise, * primitive, returns clazz. Otherwise, returns null.
* returns null.
*/ */
public static Class<?> primitiveEquivalentOf (Class clazz) public static Class<?> primitiveEquivalentOf (Class clazz)
{ {
@@ -255,16 +243,14 @@ public class ClassUtil
} }
/** /**
* Tells whether an instance of the primitive class represented by * Tells whether an instance of the primitive class represented by 'rhs' can be assigned to an
* 'rhs' can be assigned to an instance of the primitive class * instance of the primitive class represented by 'lhs'.
* represented by 'lhs'.
* *
* @param lhs assignee class. * @param lhs assignee class.
* @param rhs assigned class. * @param rhs assigned class.
* *
* @return true if compatible, false otherwise. If either argument is * @return true if compatible, false otherwise. If either argument is <code>null</code>, or one
* <code>null</code>, or one of the parameters does not represent a * of the parameters does not represent a primitive (e.g. Byte.TYPE), returns false.
* primitive (e.g. Byte.TYPE), returns false.
*/ */
public static boolean primitiveIsAssignableFrom (Class lhs, Class rhs) public static boolean primitiveIsAssignableFrom (Class lhs, Class rhs)
{ {
@@ -284,13 +270,11 @@ public class ClassUtil
return wideningSet.contains(lhs); return wideningSet.contains(lhs);
} }
/** /** Mapping from primitive wrapper Classes to their corresponding
* Mapping from primitive wrapper Classes to their corresponding * primitive Classes. */
* primitive Classes. protected static final Map<Class<?>,Class<?>> _objectToPrimitiveMap =
*/
private static final Map<Class<?>,Class<?>> _objectToPrimitiveMap =
new HashMap<Class<?>,Class<?>>(13); new HashMap<Class<?>,Class<?>>(13);
private static final Map<Class<?>,Class<?>> _primitiveToObjectMap = protected static final Map<Class<?>,Class<?>> _primitiveToObjectMap =
new HashMap<Class<?>,Class<?>>(13); new HashMap<Class<?>,Class<?>>(13);
static { static {
@@ -312,11 +296,9 @@ public class ClassUtil
_primitiveToObjectMap.put(Short.TYPE, Short.class); _primitiveToObjectMap.put(Short.TYPE, Short.class);
} }
/** /** Mapping from primitive wrapper Classes to the sets of primitive classes whose instances can
* Mapping from primitive wrapper Classes to the sets of primitive * be assigned an instance of the first. */
* classes whose instances can be assigned an instance of the first. protected static final Map<Class,Set<Class>> _primitiveWideningsMap =
*/
private static final Map<Class,Set<Class>> _primitiveWideningsMap =
new HashMap<Class,Set<Class>>(11); new HashMap<Class,Set<Class>>(11);
static { static {