com.venky.reflection.Reflector Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of core Show documentation
Show all versions of core Show documentation
Commonly used programming tasks in java
package com.venky.reflection;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
public class Reflector {
protected final Class reflectedClass;
protected final Class upperBoundClass;
protected final List allMethods ;
protected final List> classHierarchy ;
protected final List> classForest ;
protected Reflector(Class reflectedClass,Class upperBoundClass){
assert(upperBoundClass != null);
assert(reflectedClass != null);
assert(upperBoundClass.isAssignableFrom(reflectedClass));
this.reflectedClass = reflectedClass ;
this.upperBoundClass = upperBoundClass;
this.allMethods = new ArrayList(reflectedClass.getMethods().length);
this.classHierarchy = new ArrayList>();
this.classForest = new ArrayList>();
Class> rClass = reflectedClass;
List> interfaces = new ArrayList>();
do {
loadMethods(rClass);
classHierarchy.add(rClass);
classForest.add(rClass);
Class> parentClass = getParentClass(rClass,upperBoundClass);
for (Class> i : rClass.getInterfaces()){
if (i == parentClass){
continue;
}
interfaces.clear(); //Instead of new ArrayList each time.
loadAllInterfaces(i, interfaces);
for (Class> c : interfaces){
loadMethods(c);
}
classForest.addAll(interfaces);
}
rClass = parentClass;
}while(rClass != null );
}
private void loadMethods(Class> clazz){
int index = 0;
if (clazz == upperBoundClass){
index = allMethods.size();
}
for(Method m:getDeclaredMethods(clazz)){
List methodsForSignature = getMethodsForSignature(getMethodSignature(m));
if (methodsForSignature.isEmpty()){
allMethods.add(index,m);
index++;
}
methodsForSignature.add(m);
}
}
public List> getClassHierarchy(){
return classHierarchy;
}
public List> getClassForest(){
return classForest;
}
public boolean isAnnotationPresent(Class extends Annotation> annotationClass){
boolean present = false;
for (Class> clazz:getClassForest()){
present = clazz.isAnnotationPresent(annotationClass);
if (present){
break;
}
}
return present;
}
public T getAnnotation(Class annotationClass){
T annotation = null;
for (Class> clazz:getClassForest()){
annotation = clazz.getAnnotation(annotationClass);
if (annotation != null){
break;
}
}
return annotation;
}
public boolean isAnnotationPresent(Method method, Class extends Annotation> annotationClass){
if (method.isAnnotationPresent(annotationClass)){
return true;
}
boolean present = false;
List methods = getMethodsForSignature(getMethodSignature(method));
for (int i = 0 ; !present && i < methods.size() ; i ++){
Method m = methods.get(i);
present = m.isAnnotationPresent(annotationClass);
}
return present;
}
public T getAnnotation(Method method,Class annotationClass){
if (method.isAnnotationPresent(annotationClass)){
return method.getAnnotation(annotationClass);
}
T annotation = null;
List methods = getMethodsForSignature(getMethodSignature(method));
for (int i = 0 ; annotation == null && i < methods.size() ; i ++){
Method m = methods.get(i);
annotation = m.getAnnotation(annotationClass);
}
return annotation;
}
private Map methodSignature = new HashMap();
protected String getMethodSignature(Method method){
String ret = methodSignature.get(method);
if (ret != null){
return ret;
}
int modifiers = method.getModifiers();
StringBuilder sign = new StringBuilder();
sign.append(Modifier.isPublic(modifiers) ? "public " : Modifier.isProtected(modifiers) ? "protected " : Modifier.isPrivate(modifiers)? "private " : "");
sign.append(method.getReturnType().toString() + " ");
sign.append(method.getName() + "(");
Class>[] pt = method.getParameterTypes();
for (int i = 0 ; i< pt.length ; i++ ){
if (i > 0){
sign.append(",");
}
sign.append(pt[i]);
}
sign.append(")");
ret = sign.toString();
methodSignature.put(method, ret);
return ret;
}
private Map> methodsWithSameSignature = new HashMap>();
protected List getMethodsForSignature(String signature){
List methods = methodsWithSameSignature.get(signature);
if (methods == null){
methods = new ArrayList();
methodsWithSameSignature.put(signature, methods);
}
return methods;
}
protected List getDeclaredMethods(Class> forClass){
List methods = new ArrayList();
methods.addAll(Arrays.asList(forClass.getDeclaredMethods()));
try {
ClassReader reader = new ClassReader(getClass().getClassLoader().getResourceAsStream(forClass.getName().replace('.', '/')+ ".class"));
ClassVisitorImpl mv = new ClassVisitorImpl();
reader.accept(mv, 0);
final Map mSeq = mv.getMethodSequenceMap();
Collections.sort(methods,new Comparator(){
public int compare(Method o1, Method o2) {
return mSeq.get(o1.getName()).compareTo(mSeq.get(o2.getName()));
}
});
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
return methods;
}
public Class> getParentClass(){
return getParentClass(reflectedClass);
}
public Class> getParentClass(Class clazz){
int i = classHierarchy.indexOf(clazz);
if (i >= 0 && i < classHierarchy.size() - 1){
return classHierarchy.get(i+1);
}
return null;
}
private static class ClassVisitorImpl implements ClassVisitor {
private Map methodSequenceMap = new HashMap();
public Map getMethodSequenceMap() {
return methodSequenceMap;
}
public void visit(int version, int access, String name,
String signature, String superName, String[] interfaces) {
}
public void visitSource(String source, String debug) {
}
public void visitOuterClass(String owner, String name, String desc) {
}
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
return null;
}
public void visitAttribute(Attribute attr) {
}
public void visitInnerClass(String name, String outerName,
String innerName, int access) {
}
public FieldVisitor visitField(int access, String name, String desc,
String signature, Object value) {
return null;
}
public MethodVisitor visitMethod(int access, String name, String desc,
String signature, String[] exceptions) {
methodSequenceMap.put(name,methodSequenceMap.size());
return null;
}
public void visitEnd() {
}
}
public final List getMethods(MethodMatcher matcher){
List methods = new ArrayList();
for (Method method:allMethods){
if (matcher.matches(method)){
methods.add(method);
}
}
return methods;
}
public static interface MethodMatcher {
public boolean matches(Method method);
}
private static void loadAllInterfaces(Class> clazz,List> interfaces){
if (clazz.isInterface()){
interfaces.add(clazz);
}
for (Class> infcClass: clazz.getInterfaces()){
loadAllInterfaces(infcClass, interfaces);
}
}
public static Class> getParentClass(Class clazz,Class> aSuperInfcOrClass){
Class> c = clazz;
if (aSuperInfcOrClass != null && !aSuperInfcOrClass.isAssignableFrom(c)){
throw new RuntimeException(c.getName() + " is not a "+ aSuperInfcOrClass.getName());
}
if (c.isInterface()){
List> interfaces = new ArrayList>();
for (Class> infc: c.getInterfaces()){
if (aSuperInfcOrClass == null || aSuperInfcOrClass.isAssignableFrom(infc)){
interfaces.add(infc);
}
if (interfaces.size() > 1){
break;
}
}
if (interfaces.isEmpty()){
return null;
}else if (interfaces.size() > 1){
throw new RuntimeException ("multiple interfaces implement " + aSuperInfcOrClass.getName());
}else {
return interfaces.get(0);
}
}else {
c = c.getSuperclass();
if (c != null && (aSuperInfcOrClass == null || aSuperInfcOrClass.isAssignableFrom(c))){
return c;
}else {
return null;
}
}
}
}