使用 ASM 访问 class 时,如何在不加载任何 class 的情况下知道该 class 的祖先 class?
When visiting a class using ASM, how to know the ancestor class of that class without loading any class?
我想做的是:我有一个ClassVisitor适配器,当进入visit
方法时,我想知道class AncestorClass
是否是祖先class 那个 class?我试过像这样使用反射(Class.forname(...)
):
MyTransformer.class:
public class MyTransformer implements ClassFileTransformer {
public byte[] transform(ClassLoader loader, String className,
Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
byte[] classfileBuffer) throws IllegalClassFormatException {
if (className == null){
return classfileBuffer;
}
ClassReader cr = new ClassReader(classfileBuffer);
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_FRAMES);
CollectionCVAdapter mca = new MyCVAdapter(cw, className);
cr.accept(mca, 0);
return cw.toByteArray();
}
}
MyCVAdapter.class:
class MyCVAdapter extends ClassVisitor {
private String className;
private boolean isDescendantClass;
CollectionCVAdapter(ClassVisitor classVisitor, String className){
super(Opcodes.ASM5, classVisitor);
this.className = className;
}
@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
// check if this class is a descendant class of AncestorClass.class
try{
Class superClass = Class.forName(superName.replace("/", "."));
do {
if (superClass == AncestorClass.class) {
this.isDescendantClass= true;
break;
}
superClass = superClass.getSuperclass();
} while (superClass != null);
}catch (Exception e){
e.printStackTrace();
}
super.visit(version, access, name, signature, superName, interfaces);
}
...
}
但问题是我还想检测被检测 class 的父 class。我发现一旦Class.forName()
加载父class,父class就不会进入transform
方法。这意味着不能再对父 class 进行检测。那么有没有其他方法可以找出 class 是否是 AncestorClass
的后代 class?
感谢@JohannesKuhn和@Holger,终于找到了静态分析继承关系的方法
@Override
public void visit(int version, int access, String name, String signature, String superSlashName, String[] interfaces) {
String originalSuperName = superSlashName;
// check if this class is a subclass of AncestorClass.class
try{
while (superSlashName != null){
if (superSlashName.equals(AncestorClassName)){
this.isDescendantClass= true;
break;
}else{
InputStream is = this.loader.getResourceAsStream(superSlashName + ".class");
byte[] superBytes = FileUtil.loadByteCode(is);
ClassReader parentCr = new ClassReader(superBytes);
superSlashName = parentCr.getSuperName();
}
}
}catch (Exception e){
e.printStackTrace();
}
super.visit(version, access, name, signature, originalSuperName, interfaces);
}
我想做的是:我有一个ClassVisitor适配器,当进入visit
方法时,我想知道class AncestorClass
是否是祖先class 那个 class?我试过像这样使用反射(Class.forname(...)
):
MyTransformer.class:
public class MyTransformer implements ClassFileTransformer {
public byte[] transform(ClassLoader loader, String className,
Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
byte[] classfileBuffer) throws IllegalClassFormatException {
if (className == null){
return classfileBuffer;
}
ClassReader cr = new ClassReader(classfileBuffer);
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_FRAMES);
CollectionCVAdapter mca = new MyCVAdapter(cw, className);
cr.accept(mca, 0);
return cw.toByteArray();
}
}
MyCVAdapter.class:
class MyCVAdapter extends ClassVisitor {
private String className;
private boolean isDescendantClass;
CollectionCVAdapter(ClassVisitor classVisitor, String className){
super(Opcodes.ASM5, classVisitor);
this.className = className;
}
@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
// check if this class is a descendant class of AncestorClass.class
try{
Class superClass = Class.forName(superName.replace("/", "."));
do {
if (superClass == AncestorClass.class) {
this.isDescendantClass= true;
break;
}
superClass = superClass.getSuperclass();
} while (superClass != null);
}catch (Exception e){
e.printStackTrace();
}
super.visit(version, access, name, signature, superName, interfaces);
}
...
}
但问题是我还想检测被检测 class 的父 class。我发现一旦Class.forName()
加载父class,父class就不会进入transform
方法。这意味着不能再对父 class 进行检测。那么有没有其他方法可以找出 class 是否是 AncestorClass
的后代 class?
感谢@JohannesKuhn和@Holger,终于找到了静态分析继承关系的方法
@Override
public void visit(int version, int access, String name, String signature, String superSlashName, String[] interfaces) {
String originalSuperName = superSlashName;
// check if this class is a subclass of AncestorClass.class
try{
while (superSlashName != null){
if (superSlashName.equals(AncestorClassName)){
this.isDescendantClass= true;
break;
}else{
InputStream is = this.loader.getResourceAsStream(superSlashName + ".class");
byte[] superBytes = FileUtil.loadByteCode(is);
ClassReader parentCr = new ClassReader(superBytes);
superSlashName = parentCr.getSuperName();
}
}
}catch (Exception e){
e.printStackTrace();
}
super.visit(version, access, name, signature, originalSuperName, interfaces);
}