package jef.tools.reflect;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import jef.tools.ArrayUtils;
/**
* JDK的反射机制进行泛型计算有诸多不便,<BR>
* <BR>
* 然后我们看下面这个场景
* <P>
* <code>
* public abstract class A<K>{<BR>
* public K method1();<BR>
* }<BR>
* <BR>
* public class B extends A<String>{<BR>
* }<BR>
* </code>
* </P>
* 当我们通过以下代码尝试获得方法的返回参数类型时:<BR>
* <P>
* <code>
* Method method=B.class.getMethod("method1");<BR>
* method.getReturnType(); //期望得到String.class,实际得到Object.class<BR>
* method.getGenericReturnType();//即使用这个方法也一样,不会得到String.class<BR>
* </code>
* </P>
* <BR>
* Field也有类似的问题。<BR>
* 即任意一个Method实例中,由于丢失了实际所在的class(子类)信息,只保留了DeclearingClass(父类), 从而也就丢失了泛型的提供者,
* 因此永远不可能计算出泛型的最小边界。 在泛型的场合下计算边界,三个泛型提供者Class/Methid/Field缺一不可。
* 为了弥补JDK的这个问题,提供了增强的ClassEx、MethodEx、FieldEx来代替JDK原生的Class、Method、Field进行带泛型的反射操作
*
* @see FieldEx
* @see ClassEx
*
*/
public class MethodEx {
private java.lang.reflect.Method method;
private ClassEx instanceClass;
/**
* The BridgeMethod is the method which extends from super class which
* generic type was as same as superclass and also is is Volatile. The only
* way to fetch the method who was overrided is by bridge method.
*/
private java.lang.reflect.Method bridgeMethod;
public MethodEx(java.lang.reflect.Method method) {
this(method, (Class<?>) null);
}
MethodEx(Method method, ClassEx clz) {
this.method = method;
this.instanceClass = clz;
}
public MethodEx(Method method, Class<?> clz) {
this.method = method;
this.instanceClass = new ClassEx(clz);
}
public java.lang.reflect.Method getJavaMethod() {
return method;
}
public Class<?> getInstanceClass() {
return instanceClass.getWrappered();
}
public int getModifiers() {
return method.getModifiers();
}
public void setAccessible(boolean flag) throws SecurityException {
method.setAccessible(flag);
}
public Object invoke(Object obj, Object... args) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
return method.invoke(obj, args);
}
@Override
public int hashCode() {
return method.hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj instanceof MethodEx) {
return this.method.equals(((MethodEx) obj).method);
}
return false;
}
/**
* 得到方法上的Annotation
*
* @param class1
* @return
*/
public <T extends Annotation> T getAnnotation(Class<T> class1) {
T anno= method.getAnnotation(class1);
if(anno!=null)return anno;
if (bridgeMethod != null) {
Method me = BridgeMethodResolver.findGenericDeclaration(bridgeMethod);
anno= me.getAnnotation(class1);
}
if(anno!=null)return anno;
Class<?>[] params=(bridgeMethod==null)?method.getParameterTypes():bridgeMethod.getParameterTypes();
Class<?> c=method.getDeclaringClass().getSuperclass();
while(c!=null && c!=Object.class){
Method m=null;
try {
m=c.getMethod(method.getName(), params);
} catch (SecurityException e) {
} catch (NoSuchMethodException e) {
}
if(m!=null){
anno=m.getAnnotation(class1);
if(anno!=null)return anno;
}
c=c.getSuperclass();
}
for(Class<?> intf:method.getDeclaringClass().getInterfaces()){
Method m=null;
try {
m=intf.getMethod(method.getName(), params);
} catch (SecurityException e) {
} catch (NoSuchMethodException e) {
}
if(m!=null){
anno=m.getAnnotation(class1);
if(anno!=null)return anno;
}
}
return anno;
}
// public Method[] getSuperMethod(){
// List<Method> result=new ArrayList<Method>();
// Class current=this.method.getDeclaringClass();
// Class superClz=current.getSuperclass();
// String name=method.getName();
//// Class[] paramType=bridgeMethod!=null
//// while(superClz!=null && superClz!=Object.class){
//// Method m=
//// }
// return result.toArray(new Method[result.size()]);
// }
/**
* 返回方法指定序号的参数上的Annotation
*
* @param i 参数序号
* @param annotationCls Annotation类型
* @return 注解(Annotation)对象,如果没有指定类型注解返回ull。
* @throws IllegalArgumentException 如果序号超过参数
*/
public <T extends Annotation> T getParamAnnotation(int i, Class<T> annotationCls) {
return getMethodParamAnnotation(this, i, annotationCls);
}
/**
* 获得位于方法上的Annotation,会到父类和父接口查找
* @param method
* @param i
* @param annotationCls
* @return
*/
@SuppressWarnings("unchecked")
private static <T extends Annotation> T getMethodParamAnnotation(MethodEx method, int i, Class<T> annotationCls) {
Annotation[][] annos = method.getParameterAnnotations();
if (i >= annos.length) {
throw new IllegalArgumentException("the param max index is:" + annos.length + ". the input index " + i + " is out of bound.");
}
Annotation[] anns = annos[i];
if (anns == null || anns.length == 0) {
return null;
}
for (Annotation a : anns) {
if (ArrayUtils.contains(a.getClass().getInterfaces(), annotationCls)) {
return (T) a;
}
}
return null;
}
public java.lang.reflect.Method getBridgeMethod() {
return bridgeMethod;
}
public void setBridgeMethod(java.lang.reflect.Method bridgeMethod) {
this.bridgeMethod = bridgeMethod;
}
/**
* 获取所有的Annotation
*
* @return
*/
public Annotation[] getAnnotations() {
Annotation[] annos = method.getAnnotations();
if (annos.length == 0 && bridgeMethod != null) {
Method me = BridgeMethodResolver.findGenericDeclaration(bridgeMethod);
me.getAnnotations();
}
return annos;
}
/**
* 得到方法的泛型返回值类型
*
* @return
*/
public Type getGenericReturnType() {
return instanceClass.getMethodReturnType(method);
}
/**
* 得到方法的非泛型返回值类型
*
* @return
*/
public Class<?> getReturnType() {
return GenericUtils.getRawClass(getGenericReturnType());
}
/**
* 得到方法的泛型参数
*
* @return
*/
public Type[] getGenericParameterTypes() {
return instanceClass.getMethodParamTypes(method);
}
/**
* 得到方法的非泛型参数
*
* @return
*/
public Class<?>[] getParameterTypes() {
Type[] types = getGenericParameterTypes();
Class<?>[] result = new Class<?>[types.length];
for (int i = 0; i < types.length; i++) {
result[i] = GenericUtils.getRawClass(types[i]);
}
return result;
}
/**
* 获取方法名称
*
* @return
*/
public String getName() {
return method.getName();
}
@Override
public String toString() {
return method.toString();
}
public Class<?> getDeclaringClass() {
return method.getDeclaringClass();
}
public boolean isBridge() {
return method.isBridge();
}
public Annotation[][] getParameterAnnotations() {
Annotation[][] annos= method.getParameterAnnotations();
int n=0;
for(Annotation[] ann:annos){
n+=ann.length;
}
if(n==0 && bridgeMethod!=null){
Method me=BridgeMethodResolver.findGenericDeclaration(bridgeMethod);
return me.getParameterAnnotations();
}
return annos;
}
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
return method.isAnnotationPresent(annotationClass);
}
}