Java 使用Asm字节码生成器(ClassWriter)生成泛型类型的方法

Java 使用Asm字节码生成器(ClassWriter)生成泛型类型的方法,java,generics,code-generation,bytecode,java-bytecode-asm,Java,Generics,Code Generation,Bytecode,Java Bytecode Asm,使用Asm定义简单的getter和setter很容易(幸运的是,他们的FAQ中甚至解释了这一点)。但有一件事没有提到,我也找不到相关文档,那就是如何使用泛型类型信息实现这些 实际上,我能够非常轻松地确定泛型类型信息本身(因为代码将采用现有字段和/或方法,并且存在完整的泛型类型处理和解析)。我只需要为包含泛型类型的类型生成泛型版本 我希望这和修改签名Asm ClassWriter/MethodVisitor调用一样容易,但文档中的一些注释表明这可能没有那么容易(因为泛型信息存储在与常规信息稍有不同

使用Asm定义简单的getter和setter很容易(幸运的是,他们的FAQ中甚至解释了这一点)。但有一件事没有提到,我也找不到相关文档,那就是如何使用泛型类型信息实现这些

实际上,我能够非常轻松地确定泛型类型信息本身(因为代码将采用现有字段和/或方法,并且存在完整的泛型类型处理和解析)。我只需要为包含泛型类型的类型生成泛型版本

我希望这和修改签名Asm ClassWriter/MethodVisitor调用一样容易,但文档中的一些注释表明这可能没有那么容易(因为泛型信息存储在与常规信息稍有不同的位置)


编辑:看起来入口点是“ClassWriter.visitField/Method(....,字符串签名)——请注意,它是“description”,包含正常的非泛型类信息,但术语“签名”(在JLS中)特别是指包含类型信息的泛型。

根据我的经验,大多数动态字节码生成库对泛型类型没有很好的支持;但是被擦除的类可以很好地工作(当然,除非您以后想反思这些类)。

您可以使用ASM的类构建签名

例如,假设您希望为此方法编写签名:

public <K> void doSomething(K thing)
public void doSomething(K thing)
您可以使用以下代码:

SignatureWriter signature = new SignatureWriter();
signature.visitFormalTypeParameter("K");

// Ensure that <K> extends java.lang.Object
{
    SignatureVisitor classBound = signature.visitClassBound();
    classBound.visitClassType(Type.getInternalName(Object.class));
    classBound.visitEnd();
}

// The parameter uses the <K> type variable
signature.visitParameterType().visitTypeVariable("K");

// The return type uses the void primitive ('V')
signature.visitReturnType().visitBaseType('V');

signature.visitEnd();

String signatureString = signature.toString();
SignatureWriter签名=新的SignatureWriter();
signature.visitFormalTypeParameter(“K”);
//确保扩展java.lang.Object
{
SignatureVisitor classBound=signature.visitClassBound();
visitClassType(Type.getInternalName(Object.class));
classBound.visitEnd();
}
//该参数使用类型变量
signature.visitParameterType().visitTypeVariable(“K”);
//返回类型使用void原语('V')
signature.visitReturnType().visitBaseType('V');
signature.visitEnd();
String signatureString=signature.toString();
这相当于:

String signatureString = "<K:Ljava/lang/Object;>(TK;)V;"
String signatureString=“(TK;)V;"

不幸的是,我确实需要内省——这就是使用库实际构造序列化器和反序列化器的方式。-/Yes,代码擦除可以正常工作……我可能需要找到另一种方法来工作,也许可以通过添加新类型的注释来有效地复制签名。这很有用,谢谢。我现在的具体问题似乎是生成的签名在某种程度上没有正确地写入类文件,尽管我使用了正确的格式(据我所知)。但也许我应该再次与SignatureWriter确认一下…@StaxMan:我也有同样的问题。也许这篇文章会有所帮助:啊!我终于在我的代码中找到了真正的问题:我在ClassVisitor.visit()中有参数V1_2;对于泛型(和注释),这个参数必须是V1_5或更高需要支持。谢谢你的帮助!@StaxMan:不客气!哇,你使用1.2版有什么特别的原因吗?我从来没有见过支持老虚拟机的那种奉献精神。:)不,一点也不,它可能只是来自一些遗留代码。它肯定不是明确选择的,而是包本身(使用ASM的)无论如何需要1.5,很快可能需要1.6。