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