如何在运行时删除Java Annotation(可能使用Reflection)?

时间:2016-07-21 13:50:38

标签: java reflection

我们正在构建一个工具(供内部使用),只有在从源代码中删除javax.persistence.GeneratedValue注释时才会起作用(我们在工具中设置了Id,由于GeneratedValue注释而被拒绝)。 ..但是对于正常操作,我们需要这个注释。

如何在运行时删除Java Annotation(可能使用Reflection)?

这是我的班级:

@Entity
public class PersistentClass{
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private long id;

  // ... Other data
}

这是我希望能够在运行时将其更改为:

@Entity
public class PersistentClass{
  @Id
  private long id;

  // ... Other data
}

可以在类本身上执行此操作:

// for some reason this for-loop is required or an Exception is thrown
for (Annotation annotation : PersistentClass.class.getAnnotations()) {
    System.out.println("Annotation: " + annotation);
}

Field field = Class.class.getDeclaredField("annotations");
field.setAccessible(true);
Map<Class<? extends Annotation>, Annotation> annotations = (Map<Class<? extends Annotation>, Annotation>) field.get(PersistentClass.class);
System.out.println("Annotations size: " + annotations.size());
annotations.remove(Entity.class);
System.out.println("Annotations size: " + annotations.size());

如果您可以从字段中获取注释图,则应用相同的解决方案。

2 个答案:

答案 0 :(得分:2)

您无法在运行时删除注释。反思只检查代码。

你能做的是:

  1. 保留包含注释的源的主版本 您的原始目的(这是代码的签入版本)
  2. 制作已删除注释的源副本,作为构建步骤的一部分。你需要的时候使用这个副本;你不要检查它。
  3. 您可以删除使用字符串黑客工具(如Perl或SED)的注释。这些可能非常可靠,但用于执行此操作的实际命令可能非常神秘。

    如果您能够以原则方式修改源代码版本,可以使用program transformation system (PTS)这些是将源解析为编译器数据结构的工具,让您指定(结构化)要应用的“转换”代码,以可靠的方式将变换应用于结构,然后为已更改的程序重新生成(有效)源代码。

    一个好的PTS可以让你根据表面语法指定这样的变换:

    <progress max="45" value="30"></progress>

    其中模式本质上是目标语言代码的片段(例如,Java)。

    (我碰巧构建了其中一个PTS)。特定规则(对于我的PTS)可能如下所示:

      if you see *this* pattern, replace it by *that* pattern
    

    这说,“如果您找到包含带有任何值的'策略'属性的GeneratedValue注释的注释的列表,请替换它( - &gt; )没有注释的列表注释“。[这是因为注释列表是可交换的,所以我们总是可以表现为有趣的成员是列表的最后一个成员。](”标记是 metaquotes ;它们将规则语言的语法与模式中的Java语法区分开来。)

答案 1 :(得分:0)

创建一个新的库,复制并过滤实体源以删除注释。这既不硬也不干净。

您也可以尝试使用ClassLoader和字节码操作。但是类加载是一个粪坑。