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.Catjava.lang.Long 作为超级接口的泛型类型。

请注意:

如果有人能对此提供帮助,那就太好了!

谢谢!卢卡

简答

通用信息可以在 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;**