10

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.

2
  • 8
    The better question would be to ask how to make the tool work with the annotation present, I think. Commented Jul 21, 2016 at 14:01
  • were you able to find a solution for this..? I am also looking for the similar solution. Commented Jul 8, 2020 at 3:13

2 Answers 2

3

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.)

Sign up to request clarification or add additional context in comments.

Comments

0

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.

2 Comments

This isn't a long term solution though. It requires constantly maintaining two copies of the entity classes.
Yes it must be added to the build infrastructure, like a project dependency in maven.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.