Javassist:创建一个接口,用泛型扩展另一个接口
Javassist: creating an interface that extends another interface with generics
我正在项目中使用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
和 java.lang.Long
作为超级接口的泛型类型。
请注意:
com.example.Cat
:使用 javassist 在运行时创建(没问题,我也测试过并且有效
org.springframework.data.repository.CrudRepository
:来自图书馆 class。
如果有人能对此提供帮助,那就太好了!
谢谢!卢卡
简答
通用信息可以在 Javassist 中使用 SignatureAttribute 进行操作。
长答案(带代码)
您可能已经拥有的代码是这样的:
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 是字节码中定义对象 Class 的标准符号,如果您对 JVM Specification regarding descriptors
感兴趣,可以阅读更多相关信息
';'被用作几个定义之间的分隔符。让我们逐一看看:
- Ljava/lang/Object
- Lorg/springframework/data/repository/CrudRepository
<Lorg/example/Cat;Ljava/lang/Long;>
第一个定义必须存在,因为在 Java 语言中,所有内容都从 java.lang.Object 扩展(无论是 class 还是接口)。
但最有趣的是第二个,那里有完整的 class 名称和通用类型定义的类型,所有内容都使用 L 表示法。这就是你所缺少的:-)
备注
请记住,如果你想从多个接口扩展,你只需将它们添加到列表中,例如,以下签名将使接口不仅从 CrudRepository 扩展,而且从 Serializable 扩展:
Ljava/lang/object;Lorg/springframework/data/repository/CrudRepository<Lorg/example/Cat;Ljava/lang/Long;>;**Ljava/io/Serializable;**
我正在项目中使用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
和 java.lang.Long
作为超级接口的泛型类型。
请注意:
com.example.Cat
:使用 javassist 在运行时创建(没问题,我也测试过并且有效org.springframework.data.repository.CrudRepository
:来自图书馆 class。
如果有人能对此提供帮助,那就太好了!
谢谢!卢卡
简答
通用信息可以在 Javassist 中使用 SignatureAttribute 进行操作。
长答案(带代码)
您可能已经拥有的代码是这样的:
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 是字节码中定义对象 Class 的标准符号,如果您对 JVM Specification regarding descriptors
感兴趣,可以阅读更多相关信息
';'被用作几个定义之间的分隔符。让我们逐一看看:
- Ljava/lang/Object
- Lorg/springframework/data/repository/CrudRepository
<Lorg/example/Cat;Ljava/lang/Long;>
第一个定义必须存在,因为在 Java 语言中,所有内容都从 java.lang.Object 扩展(无论是 class 还是接口)。
但最有趣的是第二个,那里有完整的 class 名称和通用类型定义的类型,所有内容都使用 L 表示法。这就是你所缺少的:-)
备注
请记住,如果你想从多个接口扩展,你只需将它们添加到列表中,例如,以下签名将使接口不仅从 CrudRepository 扩展,而且从 Serializable 扩展:
Ljava/lang/object;Lorg/springframework/data/repository/CrudRepository<Lorg/example/Cat;Ljava/lang/Long;>;**Ljava/io/Serializable;**