Ljava/lang/Object;U:
Ljava/lang/Object;>Ljava/lang/Object;Ljava/lang/Iterable;
m_tValuessignature:
Ljava/util/ArrayList;
m_uValuessignature:
Ljava/util/ArrayList;
addsignature:
(TT;TU;)V
getsignature:
(TT;)TU;
由于清单2中的类为参数化类型,所以类签名需要以二进制类形式表示。
与源代码相比,签名的文本要长一些,但如果您了解到,源代码中省略的类型参数的所有可选组件都包含在签名中,那么理解起来也就不太困难了。
签名的第一部分(位于尖括号‘<...>’内)就是该类的类型参数定义清单。
这些定义的形式都相同,类型参数名称后接类型的类边界和接口边界(若存在)的字段描述符。
各字段描述符前加‘:
’字符。
由于清单2源代码未为类的类型参数指定任何边界,因此其边界均为默认的类边界java.lang.Object。
类签名的第二部分(尖括号外)给出了超类和超接口(若存在)的签名。
在清单2所示的例子中,未指定任何超类,因此签名以java.lang.Object作为超类。
这里指定了超接口,为Iterable。
在签名中可以看到预期结果,源代码中使用的只是‘’,而签名中使用的是‘’。
原因在于签名需要区分类名称和类型变量名称,第一个‘T’标识紧随其后的内容为类型变量名,而结尾的‘;’表示名称结束。
清单2中的字段和方法签名利用了与超接口签名相同的变量格式类型,其他都与前面介绍的内容相同。
回页首
ASM中的泛型
本系列的前几期文章中已介绍过(链接参见参考资料部分),ASM使用了一种访问器(visitor)模式来处理二进制类表示。
这种访问器模式是双向的:
您可以解析一个现有类,得到类组件的处理程序访问器方法的调用序列,也可以实现对类写入器的访问器方法的同类调用序列,以生成一个二进制类表示。
这一解析器/写入器对称使ASM在您仅修改类的特定方面的情况下尤为方便——您可将类写入器作为类解析器事件的处理程序的基础,仅重写基写入器来处理您想更改的事件。
解析器(或读取器)和写入器都是非常有用的独立组件。
ASM2.X全面支持Java5JVM更改,包括读取和写入签名。
签名的基本处理是通过直接传递给恰当的访问器方法的值自动实现的。
另外,ASM2.X还增加了对签名字符串(有时非常复杂)编码进行解析的支持,从而可翻译签名细节。
按照ASM的基本原理,相同的接口还可供写入器使用以按需生成签名字符串。
在这一节中,我将介绍ASM如何将基本签名作为textblob处理,又是如何详细解析基本签名的。
所有部分的签名
ASM中将签名作为textblob处理,这一方式直接内建于基本类、字段和方法的访问器调用中。
清单3展示了org.objectweb.asm.ClassVisitor接口中的相应方法:
清单3.类、字段和方法的访问器方法
publicinterfaceClassVisitor
{
voidvisit(intversion,intaccess,Stringname,Stringsignature,
StringsuperName,String[]interfaces);
FieldVisitorvisitField(intaccess,Stringname,Stringdesc,
Stringsignature,Objectvalue);
MethodVisitorvisitMethod(intaccess,Stringname,Stringdesc,
Stringsignature,String[]exceptions);
...
}
清单中的各访问器方法将签名字符串作为参数。
若相应的类、字段或方法非泛型,则在调用方法时将返回null值。
清单4显示了签名相关方法的实际应用。
其中用mons.EmptyVisitor类作为基础实现了一个访问器类,这样我只需重写想使用的方法即可。
所提供的方法实现仅输出整体签名信息、本清单所示类中各字段和方法的描述符和签名信息。
清单4的末尾处展示了在清单1所示的完整DirInfo类中使用此访问器时所生成的输出:
清单4.签名相关方法的实际应用
publicclassShowSignaturesVisitorextendsEmptyVisitor
{
publicvoidvisit(intversion,intaccess,Stringname,Stringsig,
Stringsname,String[]inames){
System.out.println("Class"+name+"signature:
");
System.out.println(""+sig);
super.visit(version,access,name,sig,sname,inames);
}
publicFieldVisitorvisitField(intaccess,Stringname,Stringdesc,
Stringsig,Objectvalue){
System.out.println("Field"+name+"descriptorandsignature:
");
System.out.println(""+desc);
System.out.println(""+sig);
returnsuper.visitField(access,name,desc,sig,value);
}
publicMethodVisitorvisitMethod(intaccess,Stringname,Stringdesc,
Stringsig,String[]exceptions){
System.out.println("Method"+name+"()descriptorandsignature:
");
System.out.println(""+desc);
System.out.println(""+sig);
returnsuper.visitMethod(access,name,desc,sig,exceptions);
}
}
Classcom/sosnoski/generics/DirInfosignature:
null
Fieldm_filesdescriptorandsignature:
Ljava/util/List;
Ljava/util/List;
Fieldm_directoriesdescriptorandsignature:
Ljava/util/List;
Ljava/util/List;
Fieldm_lastModifydescriptorandsignature:
Ljava/util/Date;
null
Method()descriptorandsignature:
(Ljava/io/File;)V
null
MethodgetDirectories()descriptorandsignature:
()Ljava/util/List;
()Ljava/util/List;
MethodgetFiles()descriptorandsignature:
()Ljava/util/List;
()Ljava/util/List;
MethodgetLastModify()descriptorandsignature:
()Ljava/util/Date;
null
签名分析
除将签名作为字符串处理外,ASM还支持在细节级处理签名。
org.objectweb.asm.signature.SignatureReader类解析一个签名字符串,并生成对org.objectweb.asm.signature.SignatureVisitor接口的调用序列。
org.objectweb.asm.signature.SignatureWriter类实现访问器接口,并从访问器方法调用序列中构建出签名字符串。
很不幸,细节级接口有些复杂,但其原因在于签名定义的复杂性,而不是ASM代码处理不力。
SignatureVisitor接口展现了这一复杂性,它定义了16个可在签名处理过程中包含的独立方法调用。
当然,绝大多数签名仅使用这些方法中的一小部分。
为举例说明ASM的细节级签名处理,我将解析本文前面所讨论的某些签名,从而介绍方法。
为此,我编写了TraceSignatureVisitor类,清单5展示了该类的部分代码,该清单中的AnalyzeSignaturesVisitor用于驱动签名处理。
当AnalyzeSignaturesVisitor用做类的访问器时,它会为所发现的各签名创建一个SignatureReader,将TraceSignatureVisitor类的一个实例作为签名组件访问器调用的目标传递。
用于解析签名的SignatureReader调用取决于签名的形式:
对于类和方法签名,恰当的方法是accept();对于字段签名,应使用acceptType()调用。
清单5.签名分析
publicclassTraceSignatureVisitorimplementsSignatureVisitor
{
publicvoidvisitFormalTypeParameter(Stringname){
System.out.println("visitFormalTypeParameter("+name+")");
}
publicSignatureVisitorvisitClassBound(){
System.out.println("visitClassBound()");
returnthis;
}
publicSignatureVisitorvisitInterfaceBound(){
System.out.println("visitInterfaceBound()");
returnthis;
}
publicSignatureVisitorvisitSuperclass(){
System.out.println("visitSuperclass()");
returnthis;
}
publicSignatureVisitorvisitInterface(){
System.out.println("visitInterface()");
returnthis;
}
publicSignatureVisitorvisitParameterType(){
System.out.println("visitParameterType()");
returnthis;
}
...
}
publicclassAnalyzeSignaturesVisitorextendsEmptyVisitor
{
publicvoidvisit(intversion,intaccess,Stringname,Stringsig,
Stringsname,String[]inames){
if(sig!
=null){
System.out.println("Class"+name+"signature:
");
System.out.println(""+sig);
newSignatureReader(sig).accept(newTraceSignatureVisitor());
}
super.visit(version,access,name,sig,sname,inames);
}
publicFieldVisitorvisitField(intaccess,Stringname,Stringdesc,
Stringsig,Objectvalue){
if(sig!
=null){
System.out.println("Field"+name+"signature:
");
System.out.println(""+sig);
newSignatureReader(sig).acceptType(newTraceSignatureVisitor());
}
r