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.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 extends U> rClass = reflectedClass;
List> interfaces = new ArrayList>();
do {
loadMethods(rClass);
classHierarchy.add(rClass);
classForest.add(rClass);
@SuppressWarnings("unchecked")
Class extends U> parentClass = (Class extends U>)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){
return getAnnotation(annotationClass) != null;
}
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){
return getAnnotation(method,annotationClass) != null;
}
public T getAnnotation(Method method,Class 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 MethodSignatureCache signatureCache = new MethodSignatureCache();
public String getMethodSignature(Method method){
return signatureCache.get(method);
}
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 {
ClassLoader cl = forClass.getClassLoader();
if (cl != null){
ClassReader reader = new ClassReader(cl.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;
}
}
}
}