美文网首页
11 - ASM之FieldVisitor

11 - ASM之FieldVisitor

作者: 舍是境界 | 来源:发表于2022-01-21 07:11 被阅读0次

    通过调用ClassVisitor类的visitField()方法,会返回一个FieldVisitor类型的对象。在本文当中,我们就对FieldVisitor类进行介绍。

    public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value);
    

    FieldVisitor类

    在学习FieldVisitor类的时候,可以与ClassVisitor类进行对比,这两个类在结构上有很大的相似性:两者都是抽象类,都定义了两个字段,都定义了两个构造方法,都定义了visitXxx()方法。

    class info

    FieldVisitor类是一个abstract类。

    public abstract class FieldVisitor {
    }
    
    fields

    FieldVisitor字段如下:

    public abstract class FieldVisitor {
        protected final int api;
        protected FieldVisitor fv;
    }
    
    constructors

    FieldVisitor类定义的两种构造方法。

    public abstract class FieldVisitor {
        public FieldVisitor(final int api) {
            this(api, null);
        }
    
        public FieldVisitor(final int api, final FieldVisitor fieldVisitor) {
            this.api = api;
            this.fv = fieldVisitor;
        }
    }
    
    methods

    FieldVisitor类定义的方法有哪些。在FieldVisitor类当中,一共定义了4个visitXxx()方法,但是,我们只需要关注其中的visitEnd()方法就可以了,对于一些非必要的方法,我们就暂时忽略它;将visitXxx()方法精简到一个最小的认知集合,那么就只剩下visitEnd()方法了。

    public abstract class FieldVisitor {
        // ......
    
        public void visitEnd() {
            if (fv != null) {
                fv.visitEnd();
            }
        }
    }
    

    在FieldVisitor类内定义的多个visitXxx()方法,也需要遵循一定的调用顺序,如下所示:

    (
     visitAnnotation |
     visitTypeAnnotation |
     visitAttribute
    )*
    visitEnd
    

    由于我们只关注visitEnd()方法,那么,这个调用顺序就变成如下这样:

    visitEnd
    

    FieldVisitor类示例

    字段常量

    预期目标:

    public interface HelloWorld {
        int intValue = 100;
        String strValue = "ABC";
    }
    

    编码实现:

    import lsieun.utils.FileUtils;
    import org.objectweb.asm.ClassWriter;
    import org.objectweb.asm.FieldVisitor;
    
    import static org.objectweb.asm.Opcodes.*;
    
    public class HelloWorldGenerateCore {
        public static void main(String[] args) throws Exception {
            String relative_path = "sample/HelloWorld.class";
            String filepath = FileUtils.getFilePath(relative_path);
    
            // (1) 生成byte[]内容
            byte[] bytes = dump();
    
            // (2) 保存byte[]到文件
            FileUtils.writeBytes(filepath, bytes);
        }
    
        public static byte[] dump() throws Exception {
            // (1) 创建ClassWriter对象
            ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
    
            // (2) 调用visitXxx()方法
            cw.visit(V1_8, ACC_PUBLIC + ACC_ABSTRACT + ACC_INTERFACE, "sample/HelloWorld", null, "java/lang/Object", null);
    
            {
                FieldVisitor fv1 = cw.visitField(ACC_PUBLIC | ACC_FINAL | ACC_STATIC, "intValue", "I", null, 100);
                fv1.visitEnd();
            }
    
            {
                FieldVisitor fv2 = cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "strValue", "Ljava/lang/String;", null, "ABC");
                fv2.visitEnd();
            }
    
            cw.visitEnd();
    
            // (3) 调用toByteArray()方法
            return cw.toByteArray();
        }
    }
    

    验证结果:

    import java.lang.reflect.Field;
    
    public class HelloWorldRun {
        public static void main(String[] args) throws Exception {
            Class<?> clazz = Class.forName("sample.HelloWorld");
            Field[] declaredFields = clazz.getDeclaredFields();
            if (declaredFields.length > 0) {
                System.out.println("fields:");
                for (Field f : declaredFields) {
                    Object value = f.get(null);
                    System.out.println("    " + f.getName() + ": " + value);
                }
            }
        }
    }
    

    输出结果:

    fields:
        intValue: 100
        strValue: ABC
    

    注意点:在得到一个FieldVisitor对象之后,要记得调用它的visitEnd()方法。

    visitAnnotation

    无论是ClassVisitor类,还是FieldVisitor类,又或者是MethodVisitor类,总会有一些visitXxx()方法是在课程当中不会涉及到的。但是,在日后的工作和学习当中,很可能,在某一天你突然就对一个visitXxx()方法产生了兴趣,那该如何学习这个visitXxx()方法呢?我们可以借助于ASMPrint类。

    预期目标:假如我们想生成如下HelloWorld类:

    public interface HelloWorld {
        @MyTag(name = "tomcat", age = 10)
        int intValue = 100;
    }
    

    MyTag定义如下

    public @interface MyTag {
        String name();
        int age();
    }
    

    编码实现:

    import lsieun.utils.FileUtils;
    import org.objectweb.asm.AnnotationVisitor;
    import org.objectweb.asm.ClassWriter;
    import org.objectweb.asm.FieldVisitor;
    
    import static org.objectweb.asm.Opcodes.*;
    
    public class HelloWorldGenerateCore {
        public static void main(String[] args) throws Exception {
            String relative_path = "sample/HelloWorld.class";
            String filepath = FileUtils.getFilePath(relative_path);
    
            // (1) 生成byte[]内容
            byte[] bytes = dump();
    
            // (2) 保存byte[]到文件
            FileUtils.writeBytes(filepath, bytes);
        }
    
        public static byte[] dump() throws Exception {
            // (1) 创建ClassWriter对象
            ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
    
            // (2) 调用visitXxx()方法
            cw.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, "sample/HelloWorld", null, "java/lang/Object", null);
    
            {
                FieldVisitor fv1 = cw.visitField(ACC_PUBLIC | ACC_FINAL | ACC_STATIC, "intValue", "I", null, 100);
    
                {
                    AnnotationVisitor anno = fv1.visitAnnotation("Lsample/MyTag;", false);
                    anno.visit("name", "tomcat");
                    anno.visit("age", 10);
                    anno.visitEnd();
                }
    
                fv1.visitEnd();
            }
    
            cw.visitEnd();
    
            // (3) 调用toByteArray()方法
            return cw.toByteArray();
        }
    }
    

    小结

    • FieldVisitor类,从结构上来说,与ClassVisitor很相似;对于FieldVisitor类的各个不同部分进行介绍,以便从整体上来理解FieldVisitor类。
    • 对于FieldVisitor类定义的方法,我们只需要关心FieldVisitor.visitEnd()方法就可以了。
    • 我们可以借助于ASMPrint类来帮助我们学习新的visitXxx()方法。

    相关文章

      网友评论

          本文标题:11 - ASM之FieldVisitor

          本文链接:https://www.haomeiwen.com/subject/txygcrtx.html