WEB开发网
开发学院软件开发Java Classworking 工具箱: 注释(Annotation)与 ASM 阅读

Classworking 工具箱: 注释(Annotation)与 ASM

 2010-03-18 00:00:00 来源:WEB开发网   
核心提示: 清单 5 的代码保存了访问字段时的字段信息,因为如果该字段有注释呈现的话,Classworking 工具箱: 注释(Annotation)与 ASM(8),以后将会需要该信息,当访问注释时,org.objectweb.asm.ClassAdapter 是针对此目的的一个方便的基类,它实现了对提供

清单 5 的代码保存了访问字段时的字段信息,因为如果该字段有注释呈现的话,以后将会需要该信息。当访问注释时,该代码审查它是否是 ToString 注释,如果是,设置一个标志,说明当前字段应该被包含在用于生成 toString() 方法的列表中。当访问一个注释名值对时,该代码审查由 ToString 注释定义的两个名称,当找到时,保存每个名称的值。这些名称的真正默认值(与在注释定义中使用的默认值相对)是在字段的 visitor 方法中设置的,所以任意由用户指定的值都将重写这些默认值。

ASM 首先访问字段,接着访问注释和注释值。因为在处理字段的注释时,没有特定的方法可以调用,所以当处理一个新字段和当需要字段的完成列表时,我会调用一个 finishField() 方法。getFields() 方法向调用者提供字段的完成列表,以由注释值所确定的顺序排列。

转换类

清单 6 展示了实现代码的最后部分,它实际上向类添加了 toString() 方法。该代码与 上个月的文章 中使用 ASM 构造一个类的代码类似,但是需要另外构造以修改一个已有的类。这里,ASM 使用的 visitor 方法增加了复杂性 —— 要修改一个已有的类,需要访问所有的当前类目录,并把它传递给类编写者。org.objectweb.asm.ClassAdapter 是针对此目的的一个方便的基类。它实现了对提供的类编写者实例的传递处理,使您可以只重写需要特殊处理的方法。

清单 6. 添加 toString() 方法

package com.sosnoski.asm; 
import org.objectweb.asm.ClassAdapter; 
import org.objectweb.asm.ClassWriter; 
import org.objectweb.asm.MethodVisitor; 
import org.objectweb.asm.Opcodes; 
import org.objectweb.asm.Type; 
/** 
 * Visitor to add <code>toString</code> method to a class. 
 */ 
public class ToStringGenerator extends ClassAdapter 
{ 
  private final ClassWriter m_writer; 
  private final String m_internalName; 
  private final FieldInfo[] m_fields; 
   
  public ToStringGenerator(ClassWriter cw, String iname, FieldInfo[] props) { 
    super(cw); 
    m_writer = cw; 
    m_internalName = iname; 
    m_fields = props; 
  } 
   
  // called at end of class 
  public void visitEnd() { 
     
    // set up to build the toString() method 
    MethodVisitor mv = m_writer.visitMethod(Opcodes.ACC_PUBLIC, 
      "toString", "()Ljava/lang/String;", null, null); 
    mv.visitCode(); 
     
    // create and initialize StringBuffer instance 
    mv.visitTypeInsn(Opcodes.NEW, "java/lang/StringBuffer"); 
    mv.visitInsn(Opcodes.DUP); 
    mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/StringBuffer", 
      "<init>", "()V"); 
     
    // start text with class name 
    String name = m_internalName; 
    int split = name.lastIndexOf('/'); 
    if (split >= 0) { 
      name = name.substring(split+1); 
    } 
    mv.visitLdcInsn(name + ":"); 
    mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuffer", 
      "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;"); 
     
    // loop through all field values to be included 
    boolean newline = false; 
    for (int i = 0; i < m_fields.length; i++) { 
       
      // check type of field (objects other than Strings need conversion) 
      FieldInfo prop = m_fields[i]; 
      Type type = prop.getType(); 
      boolean isobj = type.getSort() == Type.OBJECT && 
        !type.getClassName().equals("java.lang.String"); 
       
      // format lead text, with newline for object or after object 
      String lead = (isobj || newline) ? "\n " : " "; 
      if (prop.getText().length() > 0) { 
        lead += prop.getText() + "="; 
      } 
      mv.visitLdcInsn(lead); 
      mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, 
        "java/lang/StringBuffer", "append", 
        "(Ljava/lang/String;)Ljava/lang/StringBuffer;"); 
       
      // load the actual field value and append 
      mv.visitVarInsn(Opcodes.ALOAD, 0); 
      mv.visitFieldInsn(Opcodes.GETFIELD, m_internalName, 
        prop.getField(), type.getDescriptor()); 
      if (isobj) { 
         
        // convert objects by calling toString() method 
        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, 
          type.getInternalName(), "toString", 
          "()Ljava/lang/String;"); 
        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, 
          "java/lang/StringBuffer", "append", 
          "(Ljava/lang/String;)Ljava/lang/StringBuffer;"); 
         
      } else { 
         
        // append other types directly to StringBuffer 
        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, 
          "java/lang/StringBuffer", "append", "(" + 
          type.getDescriptor() + ")Ljava/lang/StringBuffer;"); 
         
      } 
      newline = isobj; 
    } 
     
    // finish the method by returning accumulated text 
    mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuffer", 
      "toString", "()Ljava/lang/String;"); 
    mv.visitInsn(Opcodes.ARETURN); 
    mv.visitMaxs(3, 1); 
    mv.visitEnd(); 
    super.visitEnd(); 
  } 
} 

上一页  3 4 5 6 7 8 9 10  下一页

Tags:Classworking 工具箱 注释

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接