package net.sourceforge.retroweaver.runtime.java.lang.reflect;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import net.sourceforge.retroweaver.runtime.java.lang.TypeNotPresentException;
import net.sourceforge.retroweaver.runtime.java.lang.annotation.AIB;
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;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
public class ReflectionDescriptor implements ClassVisitor {
private static final boolean DEBUG = false;
private static final Map<Class, ReflectionDescriptor> descriptors = new HashMap<Class, ReflectionDescriptor>();
public static ReflectionDescriptor getReflectionDescriptor(Class class_) {
synchronized (descriptors) {
ReflectionDescriptor d = descriptors.get(class_);
if (d == null) {
d = new ReflectionDescriptor(class_);
descriptors.put(class_, d);
if (DEBUG) d.debugMessage("Adding descriptor");
}
return d;
}
}
private final Class class_;
private ReflectionDescriptor(Class class_) {
this.class_ = class_;
String name = class_.getName();
String resource = "/" + name.replace('.', '/') + ".class";
if (DEBUG) System.out.println("Reading class file: " + resource);
InputStream classStream = class_.getResourceAsStream(resource);
try {
ClassReader r = new ClassReader(classStream);
r.accept(this, ClassReader.SKIP_CODE + ClassReader.SKIP_DEBUG
+ ClassReader.SKIP_FRAMES);
} catch (IOException e) {
// Shouldn't generally happen
throw new TypeNotPresentException(
"[Retroweaver] Unable to read reflection data for: " + name, e);
} finally {
try {
if (classStream != null) {
classStream.close();
}
} catch (IOException e) { // NOPMD by xlv
}
}
}
private String internalName;
private String enclosingClassName;
private String enclosingMethodName;
private String enclosingMethodDesc;
public String getEnclosingClassName() {
return enclosingClassName;
}
public void debugMessage(String msg) {
System.out.println(msg +
"\n\tclass: " + class_.getName() +
"\n\tenclosingClassName: " + enclosingClassName +
"\n\tenclosingMethodName: " + enclosingMethodName + ' ' + enclosingMethodDesc);
}
public Class getEnclosingClass() {
//debugMessage("getEnclosingClass");
if (enclosingClassName == null) {
return null;
}
try {
//debugMessage("getEnclosingClass");
String name = enclosingClassName.replace('/', '.');
Class c = class_.getClassLoader().loadClass(name);
return c;
} catch (ClassNotFoundException e) {
return null;
}
}
public Method getEnclosingMethod() {
//debugMessage("getEnclosingMethod");
if (enclosingMethodName == null) {
return null;
}
return getMethod(getEnclosingClass(), enclosingMethodName, enclosingMethodDesc);
}
public Constructor getEnclosingConstructor() {
//debugMessage("getEnclosingMethod");
if (enclosingMethodName == null) {
return null;
}
return getConstructor(getEnclosingClass(), enclosingMethodDesc);
}
private Method getMethod(Class class_, String name, String desc) {
Type[] types = Type.getArgumentTypes(desc);
outer_loop:
for (Method m : class_.getDeclaredMethods()) {
final Type[] methodTypes = Type.getArgumentTypes(m);
if (!m.getName().equals(name)
|| methodTypes.length != types.length) {
continue;
}
for (int i = 0; i < types.length; ++i) {
if (!types[i].equals(methodTypes[i])) {
continue outer_loop;
}
}
return m;
}
return null;
}
private Constructor getConstructor(Class class_, String desc) {
Type[] types = Type.getArgumentTypes(desc);
outer_loop:
for (Constructor c : class_.getDeclaredConstructors()) {
final Class[] constructorTypes = c.getParameterTypes();
if (constructorTypes.length != types.length) {
continue;
}
for (int i = 0; i < types.length; ++i) {
if (!types[i].equals(Type.getType(constructorTypes[i]))) {
continue outer_loop;
}
}
return c;
}
return null;
}
public TypeVariable[] getTypeParameters() throws GenericSignatureFormatError {
throw new UnsupportedOperationException("NotImplemented");
}
public net.sourceforge.retroweaver.runtime.java.lang.reflect.Type getGenericSuperclass() throws GenericSignatureFormatError, TypeNotPresentException, MalformedParameterizedTypeException {
throw new UnsupportedOperationException("NotImplemented");
}
public net.sourceforge.retroweaver.runtime.java.lang.reflect.Type[] getGenericInterfaces() throws GenericSignatureFormatError, TypeNotPresentException, MalformedParameterizedTypeException {
throw new UnsupportedOperationException("NotImplemented");
}
/**
* Visits the header of the class.
*
* @param version the class version.
* @param access the class's access flags (see {@link Opcodes}). This
* parameter also indicates if the class is deprecated.
* @param name the internal name of the class (see
* {@link Type#getInternalName() getInternalName}).
* @param signature the signature of this class. May be <tt>null</tt> if
* the class is not a generic one, and does not extend or implement
* generic classes or interfaces.
* @param superName the internal of name of the super class (see
* {@link Type#getInternalName() getInternalName}). For interfaces,
* the super class is {@link Object}. May be <tt>null</tt>, but
* only for the {@link Object} class.
* @param interfaces the internal names of the class's interfaces (see
* {@link Type#getInternalName() getInternalName}). May be
* <tt>null</tt>.
*/
public void visit(
int version,
int access,
String name,
String signature,
String superName,
String[] interfaces) {
internalName = name;
}
public void visitSource(String source, String debug) {}
/**
* Visits the enclosing class of the class. This method must be called only
* if the class has an enclosing class.
*
* @param owner internal name of the enclosing class of the class.
* @param name the name of the method that contains the class, or
* <tt>null</tt> if the class is not enclosed in a method of its
* enclosing class.
* @param desc the descriptor of the method that contains the class, or
* <tt>null</tt> if the class is not enclosed in a method of its
* enclosing class.
*/
public void visitOuterClass(String owner, String name, String desc) {
enclosingClassName = owner;
enclosingMethodName = name;
enclosingMethodDesc = desc;
//debugMessage("visitOuterClass");
}
/**
* Visits information about an inner class. This inner class is not
* necessarily a member of the class being visited.
*
* @param name the internal name of an inner class (see
* {@link Type#getInternalName() getInternalName}).
* @param outerName the internal name of the class to which the inner class
* belongs (see {@link Type#getInternalName() getInternalName}). May
* be <tt>null</tt>.
* @param innerName the (simple) name of the inner class inside its
* enclosing class. May be <tt>null</tt> for anonymous inner
* classes.
* @param access the access flags of the inner class as originally declared
* in the enclosing class.
*/
public void visitInnerClass(
String name,
String outerName,
String innerName,
int access) {
if (name.equals(internalName)) {
if (outerName != null) {
enclosingClassName = outerName;
}
}
//debugMessage("visitInnerClass");
}
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
return AIB.EMPTY_VISITOR;
}
public void visitAttribute(Attribute attr) {}
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) { return null; }
public void visitEnd() {}
public static class ClassTypeImpl implements net.sourceforge.retroweaver.runtime.java.lang.reflect.Type {
private final String name;
public ClassTypeImpl(String name) {
this.name = name;
}
}
public static class GenericArrayTypeImpl implements GenericArrayType {
public net.sourceforge.retroweaver.runtime.java.lang.reflect.Type getGenericComponentType() throws TypeNotPresentException, MalformedParameterizedTypeException {
throw new UnsupportedOperationException("NotImplemented");
}
}
public static class ParameterizedTypeImpl implements ParameterizedType {
public net.sourceforge.retroweaver.runtime.java.lang.reflect.Type[] getActualTypeArguments() throws TypeNotPresentException, MalformedParameterizedTypeException {
throw new UnsupportedOperationException("NotImplemented");
}
public net.sourceforge.retroweaver.runtime.java.lang.reflect.Type getOwnerType() {
throw new UnsupportedOperationException("NotImplemented");
}
public net.sourceforge.retroweaver.runtime.java.lang.reflect.Type getRawType() {
throw new UnsupportedOperationException("NotImplemented");
}
}
public static class TypeVariableImpl<D extends GenericDeclaration> implements net.sourceforge.retroweaver.runtime.java.lang.reflect.TypeVariable {
private final String name;
public TypeVariableImpl(String name) {
this.name = name;
}
public net.sourceforge.retroweaver.runtime.java.lang.reflect.Type[] getBounds() throws TypeNotPresentException, MalformedParameterizedTypeException {
throw new UnsupportedOperationException("NotImplemented");
}
public D getGenericDeclaration() {
throw new UnsupportedOperationException("NotImplemented");
}
public String getName() {
return name;
}
public String toString() { return name; }
}
public static class WildcardTypeImpl implements WildcardType {
public net.sourceforge.retroweaver.runtime.java.lang.reflect.Type[] getLowerBounds() throws TypeNotPresentException, MalformedParameterizedTypeException {
throw new UnsupportedOperationException("NotImplemented");
}
public net.sourceforge.retroweaver.runtime.java.lang.reflect.Type[] getUpperBounds() throws TypeNotPresentException, MalformedParameterizedTypeException {
throw new UnsupportedOperationException("NotImplemented");
}
}
}