英文:
When visiting a class using ASM, how to know the ancestor class of that class without loading any class?
问题
以下是翻译好的部分:
我想要做的是:我有一个 ClassVisitor 适配器,在进入 `visit` 方法时,我想要知道类 `AncestorClass` 是否是那个类的祖先类?我尝试使用反射(`Class.forname(...)`)来实现,就像这样:
MyTransformer.class:
```java
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) {
// 检查此类是否是 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.forName()
加载了父类,父类就不会进入 transform
方法。这意味着无法再对父类进行仪器化。那么是否有其他方法来判断一个类是否是 AncestorClass
的子类呢?
<details>
<summary>英文:</summary>
What I want to do is: I have a ClassVisitor adapter, when entering the `visit` method, I want to know if the class `AncestorClass` is the ancestor class of that class? I have tried to use reflection (`Class.forname(...)`) like this:
MyTransformer.class:
```java
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);
}
...
}
but the problem is that I also want to instrument the parent class of the instrumented class. I found that once Class.forName()
loads the parent class, the parent class will not get into the transform
method. Which means the parent class can not be instrumented any more. So is there any alternatives to find out whether the class is a descendant class of AncestorClass
?
答案1
得分: 1
感谢 @JohannesKuhn 和 @Holger,我终于找到了静态分析继承关系的方法。
@Override
public void visit(int version, int access, String name, String signature, String superSlashName, String[] interfaces) {
String originalSuperName = superSlashName;
// 检查这个类是否是 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);
}
英文:
Thanks to @JohannesKuhn and @Holger, I finally found the way to analyze the inheritance relationship statically.
@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);
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论