org.zkoss.zk.ui.select.impl.Reflections Maven / Gradle / Ivy
/**
*
*/
package org.zkoss.zk.ui.select.impl;
import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
/**
* A collection of reflection utilities.
* @since 6.0.0
* @author simonpai
*/
public class Reflections {
// field scanner //
/**
* Traverse through all fields with a certain annotation in a class and
* it super classes. Subclass first.
* All the fields with the same name will be scanned too. (since 6.5.1),
* before 6.5.1 release, only the subclass will be scanned.
*/
public static void forFields(Class> clazz, Class annotationClass,
FieldRunner runner) {
for (Class> c = clazz; c != null; c = c.getSuperclass()) {
for (Field f : c.getDeclaredFields()) {
A anno = f.getAnnotation(annotationClass);
if (anno == null)
continue;
f.setAccessible(true);
runner.onField(c, f, anno);
}
}
}
// method scanner //
/**
* Traverse through all methods with a certain annotation in a class,
* including ones inherited from its super class.
*/
public static void forMethods(Class> clazz, Class annotationClass,
MethodRunner runner) {
for (Method m : clazz.getMethods()) {
A anno = m.getAnnotation(annotationClass);
if (anno == null)
continue;
m.setAccessible(true);
runner.onMethod(clazz, m, anno);
}
}
// field information //
/**
* Return true if field is of Collection type, and an object of type clazz
* can be added into the Collection.
*/
public static boolean isAppendableToCollection(Type type, Object object) {
if (!Collection.class.isAssignableFrom(getClass(type)))
return false;
if (type instanceof ParameterizedType)
return getClass(((ParameterizedType) type).getActualTypeArguments()[0]).isAssignableFrom(object.getClass());
return type instanceof Class>;
}
// method information //
/**
* Return true if the given arguments can be passed as the arguments of
* the method.
*/
public static boolean isPassableToMethod(Method method, Object... arguments) {
Type[] types = method.getGenericParameterTypes();
if (types.length != arguments.length)
return false;
for (int i = 0; i < types.length; i++)
if (!getClass(types[i]).isAssignableFrom(arguments[i].getClass()))
return false;
return true;
}
// field operation //
/**
* Set a value to a field of the object.
*/
public static void setFieldValue(Object bean, Field field, Object value) {
try {
field.set(bean, value);
} catch (IllegalArgumentException e) {
throw new IllegalStateException("IllegalStateException @ setFieldValue");
} catch (IllegalAccessException e) {
throw new IllegalStateException("IllegalAccessException @ setFieldValue");
}
}
/**
* Get field value.
*/
public static Object getFieldValue(Object bean, Field field) {
try {
return field.get(bean);
} catch (IllegalArgumentException e) {
throw new IllegalStateException("IllegalStateException @ getFieldValue");
} catch (IllegalAccessException e) {
throw new IllegalStateException("IllegalStateException @ getFieldValue");
}
}
/**
* Add the item to a collection field of an object.
*/
@SuppressWarnings("unchecked")
public static void addToCollectionField(Object owner, Field field, Object item) {
if (!isAppendableToCollection(field.getGenericType(), item))
throw new IllegalArgumentException(item + " is not appendable to " + field);
try {
field.setAccessible(true);
Collection c = (Collection) field.get(owner);
if (c == null)
throw new IllegalArgumentException(field + " has not been initiated.");
c.add(item);
} catch (IllegalAccessException e) {
throw new IllegalStateException(e);
}
}
/**
* Invoke a method reflexively.
*/
public static void invokeMethod(Method method, Object bean, Object... arguments) {
if (!isPassableToMethod(method, arguments))
throw new IllegalArgumentException("Arguments does not match method signature: " + method);
method.setAccessible(true);
try {
method.invoke(bean, arguments);
} catch (IllegalAccessException e) {
throw new IllegalStateException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
// interface //
public interface FieldRunner {
public void onField(Class> clazz, Field field, A annotation);
}
public interface MethodRunner {
public void onMethod(Class> clazz, Method method, A annotation);
}
/**
* Return the Class representing the given Type.
*/
public static Class> getClass(Type type) {
if (type instanceof Class>)
return (Class>) type;
else if (type instanceof ParameterizedType)
return getClass(((ParameterizedType) type).getRawType());
else if (type instanceof GenericArrayType) {
Class> c = getClass(((GenericArrayType) type).getGenericComponentType());
if (c != null)
return Array.newInstance(c, 0).getClass();
}
return null;
}
}