简体   繁体   中英

How do you remove a Java Annotation at Runtime (probably using Reflection)?

We are building a tool (for internal use) that only works if the javax.persistence.GeneratedValue annotation is removed from our source code (we are setting the Id in the tool, which is rejected due to the GeneratedValue annotation)... but for normal operations, we require this annotation.

How do you remove a Java Annotation at Runtime (probably using Reflection)?

This is my class:

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

  // ... Other data
}

This is what I would like to be able to change it to, at runtime:

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

  // ... Other data
}

It is possible to do this on the class itself:

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

If you can get the annotations map from a field, then the same solution would apply.

You can't remove an annotation at runtime. Reflection only inspects code.

What you can do is:

  1. Keep a master version of the source containing the annotation for your original purposes (this is the checked in version of the code)
  2. Manufacture a copy of the source with annotations removed, as part of your build step. You use this copy where needed; you don't check it in.

You can remove the annotations used string hacking tools like Perl or SED. These would probably be pretty reliable but the actual commands you use to do this might be pretty cryptic.

If you can to make modified versions of source code in a principled way, you can use a program transformation system (PTS) These are tools that parse source to compiler data structures, let you specify (structured) "transforms" to be applied to the code, applies the transforms to the structures in a reliable way, and then regenerates (valid) source code for the changed program.

A good PTS will let you specify such transforms in terms of surface syntax:

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

where the pattern is essentially a fragment of the target language code (eg, Java).

(I happen to build one of these PTSes). A specific rule (for my PTS) might look like:

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

This says, "if you find a list of annotations containing a GeneratedValue annotation with a 'strategy' property of any value", replace that ( -> ) annotation by the list without the annotation". [This works because the annotation list is commutative so we can always act as if an interesting member was the last member of the list.] (The " marks are metaquotes ; they distinguish the syntax for the rule langauge from the syntax for Java in the patterns.)

Make a new library with the entity sources copied and filtered to remove the annotation. That is neither hard nor unclean.

You could also try yourself on ClassLoader and bytecode manipulation. But class loading is a cesspit.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM