Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 226
HeavyE Avatar asked Jul 21 '16 13:07

HeavyE


People also ask

How do you remove annotations in Java?

You can remove annotations in your source code by using the Annotations view. You can remove annotations in your source code by directly deleting the annotation in the Java editor or by using the Annotations view.

How annotations are obtained at runtime by use of reflection?

If annotations specify a retention policy of RUNTIME, then they can be queried at run time by any Java program through the use of reflection. Reflection is the feature that enables information about a class to be obtained at run time.

Is Java Reflection can be used to inspect Java classes at runtime?

With Java reflection, we can inspect constructors of any class and even create class objects at runtime. This is made possible by the java. lang.

What is Java reflection?

Reflection is a feature in the Java programming language. It allows an executing Java program to examine or "introspect" upon itself, and manipulate internal properties of the program. For example, it's possible for a Java class to obtain the names of all its members and display them.


1 Answers

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 (e.g., 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.)

like image 50
Ira Baxter Avatar answered Oct 26 '22 15:10

Ira Baxter