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

10
我们正在开发一个仅在我们的源代码中删除javax.persistence.GeneratedValue注释后才能正常运行的工具(用于内部使用)(我们在工具中设置Id,由于GeneratedValue注释而被拒绝)...但是对于正常操作,我们需要这个注释。
如何在运行时删除Java注释(可能使用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());

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

8
更好的问题应该是问如何让工具在有注释的情况下运作,我认为。 - SpaceTrucker
你能找到解决方案吗?我也在寻找类似的解决方案。 - Nuthan Kumar
2个回答

3
您无法在运行时删除注释。反射只能检查代码。
您可以做的是:
1. 保留包含注释的源代码的主版本,以用于您最初的目的(这是代码的已检入版本)。 2. 在构建步骤中制作一个不包含注释的源代码副本。您在需要时使用此副本;您不会将其检入。
您可以使用字符串处理工具(如Perl或SED)删除使用的注释。这些工具可能非常可靠,但您用于执行此操作的实际命令可能相当难懂。
如果您想以有原则的方式制作修改后的源代码版本,则可以使用程序转换系统(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 ";

这段话的意思是,如果你找到一个包含 GeneratedValue 注释的注释列表,并且它的 'strategy' 属性具有任何值,那么就用不带注释的列表替换该注释。这个方法可行是因为注释列表是可交换的,所以我们总是可以假设一个有趣的成员是列表的最后一个成员。其中引号内的双引号是元引号;它们区分规则语言的语法和 Java 的语法。

0

制作一个新的库,将实体源文件复制并过滤以去除注释。这既不难也不会污染代码。

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


1
这不是长期解决方案。它需要不断维护两个实体类的副本。 - HeavyE
1
是的,它必须被添加到构建基础设施中,就像在Maven中的项目依赖一样。 - Joop Eggen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接