Classworking 工具箱: 注释(Annotation)与 ASM
2010-03-18 00:00:00 来源:WEB开发网J2SE 5.0 的 instrumentation 特性远远不止是我在此所展示的,它包括访问加载到 JVM 中的所有类,甚至重定义已有类(如果 JVM 支持的话)的能力。对于本文,我将跳过其他的特性,继续来看用于处理注释和修改类的 ASM 代码。
累积元数据
ASM 2.0 使处理注释变得更容易了。正如您在 上个月的文章 中了解到的,ASM 使用 visitor 的方法来报告类数据的所有组件。J2SE 5.0 注释是使用 org.objectweb.asm.AnnotationVisitor 接口报告的。该接口定义了几个方法,其中我将只使用两个:visitAnnotation() 是处理注释时调用的方法,而 visit() 是处理注释的特定的名值对时调用的方法。我还需要实际字段信息,这是使用基本 org.objectweb.asm.ClassVisitor 接口中的 visitField() 方法报告的。
实现感兴趣的两个接口的所有方法将是冗长乏味的,但幸运的是 ASM 提供了一个方便的 org.objectweb.asm.commons.EmptyVisitor 类,作为编写自己的 visitor 的基础。EmptyVisitor 只是提供了所有不同种类的 visitor 的空的实现,允许您只对感兴趣的 visitor 方法建子类和重写。清单 5 给出了扩展 EmptyVisitor 类而得到的处理 ToString 注释的 FieldCollector 类。清单中也包含了用来保存收集的字段信息的 FieldInfo 类。
清单 5. 处理类的注释
package com.sosnoski.asm;
import java.util.ArrayList;
import java.util.Arrays;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.EmptyVisitor;
/**
* Visitor implementation to collect field annotation information from class.
*/
public class FieldCollector extends EmptyVisitor
{
private boolean m_isIncluded;
private int m_fieldAccess;
private String m_fieldName;
private Type m_fieldType;
private int m_fieldOrder;
private String m_fieldText;
private ArrayList m_fields = new ArrayList();
// finish field handling, once we're past it
private void finishField() {
if (m_isIncluded) {
m_fields.add(new FieldInfo(m_fieldName, m_fieldType,
m_fieldOrder, m_fieldText));
}
m_isIncluded = false;
}
// return array of included field information
public FieldInfo[] getFields() {
finishField();
FieldInfo[] infos =
(FieldInfo[])m_fields.toArray(new FieldInfo[m_fields.size()]);
Arrays.sort(infos);
return infos;
}
// process field found in class
public FieldVisitor visitField(int access, String name, String desc,
String sig, Object init) {
// finish processing of last field
finishField();
// save information for this field
m_fieldAccess = access;
m_fieldName = name;
m_fieldType = Type.getReturnType(desc);
m_fieldOrder = Integer.MAX_VALUE;
// default text is empty if non-String object, otherwise from field name
if (m_fieldType.getSort() == Type.OBJECT &&
!m_fieldType.getClassName().equals("java.lang.String")) {
m_fieldText = "";
} else {
String text = name;
if (text.startsWith("m_") && text.length() > 2) {
text = Character.toLowerCase(text.charAt(2)) +
text.substring(3);
}
m_fieldText = text;
}
return super.visitField(access, name, desc, sig, init);
}
// process annotation found in class
public AnnotationVisitor visitAnnotation(String sig, boolean visible) {
// flag field to be included in representation
if (sig.equals("Lcom/sosnoski/asm/ToString;")) {
if ((m_fieldAccess & Opcodes.ACC_STATIC) == 0) {
m_isIncluded = true;
} else {
throw new IllegalStateException("ToString " +
"annotation is not supported for static field +" +
" m_fieldName");
}
}
return super.visitAnnotation(sig, visible);
}
// process annotation name-value pair found in class
public void visit(String name, Object value) {
// ignore anything except the pair defined for toString() use
if ("order".equals(name)) {
m_fieldOrder = ((Integer)value).intValue();
} else if ("text".equals(name)) {
m_fieldText = value.toString();
}
}
}
package com.sosnoski.asm;
import org.objectweb.asm.Type;
/**
* Information for field value to be included in string representation.
*/
public class FieldInfo implements Comparable
{
private final String m_field;
private final Type m_type;
private final int m_order;
private final String m_text;
public FieldInfo(String field, Type type, int order,
String text) {
m_field = field;
m_type = type;
m_order = order;
m_text = text;
}
public String getField() {
return m_field;
}
public Type getType() {
return m_type;
}
public int getOrder() {
return m_order;
}
public String getText() {
return m_text;
}
/* (non-Javadoc)
* @see java.lang.Comparable#compareTo(java.lang.Object)
*/
public int compareTo(Object comp) {
if (comp instanceof FieldInfo) {
return m_order - ((FieldInfo)comp).m_order;
} else {
throw new IllegalArgumentException("Wrong type for comparison");
}
}
}
Tags:Classworking 工具箱 注释
编辑录入:爽爽 [复制链接] [打 印]更多精彩
赞助商链接