【问题标题】:How do you remove a Java Annotation at Runtime (probably using Reflection)?如何在运行时删除 Java 注释(可能使用反射)?
【发布时间】:2016-07-21 13:50:38
【问题描述】:

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

如何在运行时删除 Java 注释(可能使用反射)?

这是我的课:

@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());

如果您可以从字段中获取注释映射,那么同样的解决方案将适用。

【问题讨论】:

  • 我认为,更好的问题是询问如何使该工具与存在的注释一起工作。
  • 您能找到解决方案吗?我也在寻找类似的解决方案。

标签: java reflection


【解决方案1】:

您不能在运行时删除注释。反射只检查代码。

你可以做的是:

  1. 保留包含注释的源的主版本 您最初的目的(这是代码的签入版本)
  2. 作为构建步骤的一部分,制作一个删除了注释的源代码副本。您在需要时使用此副本;你没有签到。

您可以删除使用 Perl 或 SED 等字符串黑客工具的注释。这些可能非常可靠,但您用来执行此操作的实际命令可能非常神秘。

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

一个好的 PTS 可以让你在表面语法方面指定这样的转换:

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

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

(我碰巧构建了这些 PTS 之一)。特定规则(针对我的 PTS)可能如下所示:

 rule remove_Generated_value(a: annotations, e: expression):
          annotations -> annotations =
      " \a @GeneratedValue(strategy = \e) " -> " \a ";

这表示,“如果您发现一个注释列表,其中包含具有任何值的 'strategy' 属性的 GeneratedValue 注释”,请替换该 (->) 注释由没有注释的列表”。[这有效,因为注释列表是可交换的,所以我们总是可以像有趣的成员是列表的最后一个成员一样行事。](“标记是元引用;他们将规则语言的语法与模式中的 Java 语法区分开来。)

【讨论】:

    【解决方案2】:

    使用复制和过滤的实体源创建一个新库以删除注释。这既不硬也不脏。

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

    【讨论】:

    • 这不是一个长期的解决方案。它需要不断维护实体类的两个副本。
    • 是的,它必须添加到构建基础架构中,就像 maven 中的项目依赖项一样。
    猜你喜欢
    • 1970-01-01
    • 2012-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-12
    • 2023-03-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多