我在项目中使用javassist,我需要在运行时创建以下接口:
package com.example;
import org.springframework.data.repository.CrudRepository;
import com.example.Cat;
public interface CatRepository extends CrudRepository<Cat, Long> {}
虽然创建扩展CatRepository
的界面CrudRepository
没有问题,但我不明白(从文档和查看源代码),如何指定com.example.Cat
和{ {1}}作为超级接口的泛型类型。
请注意:
java.lang.Long
:在运行时使用javassist创建(没有问题,我也测试了它的工作原理com.example.Cat
:来自图书馆的现有课程。如果任何人可以提供帮助,那就太棒了!
谢谢!卢卡
答案 0 :(得分:6)
可以使用SignatureAttribute在Javassist中处理通用信息。
您可能已经拥有的代码是这样的:
ClassPool defaultClassPool = ClassPool.getDefault();
CtClass superInterface = defaultClassPool.getCtClass(CrudRepository.class
.getName());
CtClass catRepositoryInterface = defaultClassPool.makeInterface("CatRepository", ctClass);
// something is missing here :-(
catRepositoryInterface.toClass()
但是,就像你已经说过的那样,这不会添加有关泛型的信息。为了获得编译源代码所能获得的相同字节码,您需要在注释所在的位置执行以下操作:
SignatureAttribute signatureAttribute = new SignatureAttribute(
classFile.getConstPool(),
"Ljava/lang/Object;Lorg/springframework/data/repository/CrudRepository<Lorg/example/Cat;Ljava/lang/Long;>;");
ClassFile metaInformation = catRepositoryInterface.getClassFile();
classFile.addAttribute(signatureAttribute);
让我们分解签名字符串,以了解那里发生的事情:
你看到几个L [TYPE],它是什么? L是字节码中用于定义对象类的标准符号,如果您对JVM Specification regarding descriptors
';'被用作几个定义之间的分隔符。让我们看看它们中的每一个:
<Lorg/example/Cat;Ljava/lang/Long;>
第一个定义必须存在,因为在Java语言中,一切都从java.lang.Object扩展(如果是类或接口,则无关紧要)。
但最有趣的是第二个,你的类型包含完整的类名和泛型类型定义,所有内容都使用L符号。这就是你所缺少的: - )
注意强>
请记住,如果要从多个接口扩展,只需将它们添加到列表中,例如,以下签名将使接口不仅从CrudRepository扩展而且从Serializable扩展:
Ljava/lang/object;Lorg/springframework/data/repository/CrudRepository<Lorg/example/Cat;Ljava/lang/Long;>;**Ljava/io/Serializable;**