Javassist:创建一个使用泛型扩展另一个接口的接口

时间:2015-06-25 12:31:04

标签: java javassist

我在项目中使用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:来自图书馆的现有课程。

如果任何人可以提供帮助,那就太棒了!

谢谢!卢卡

1 个答案:

答案 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

  • 感兴趣,可以阅读更多相关信息。
  • ';'被用作几个定义之间的分隔符。让我们看看它们中的每一个:

    • Ljava /郎/对象
    • Lorg / springframework的/数据/库/ CrudRepository <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;**