Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Identify stability of types in Java annotation processor

I would like to write an annotation processor that generates source code based on the set of JavaBeans properties of processed types.

This works in general, but I am struggling with doing so correctly if other annotation processors are around. Specifically, such other processor may generate a super-class for a type processed by my processor, so I need to take that super-type's properties into account as well. In a subsequent round, a super-class for that super-class may be generated and so on.

This means I must not generate my source code until the hierarchy of the type I am interested is stable, i.e. no further super-types will be generated in subsequent rounds (or in the same round, after my processor has been run) by other processors.

How may I find out if that is the case? I am aware of RoundEnvironment#processingOver() and the possibility of generating my code in that last final round, but I understand this to be a bad practice (the compiler will issue a warning).

like image 585
Gunnar Avatar asked Dec 14 '15 09:12

Gunnar


1 Answers

To answer my own question:

An annotated type can be considered stable or complete if all its super-types are non-erroneous. An example:

@GenClass("Base")
class MyAnnotatedType extends Base {}

Let's assume there is one annotation processor A for @GenBase which generates the specified class, Base in this case. And another processor B is interested in the entirety of MyAnnotatedType's hierarchy, e.g. it wants to generate some kind of descriptor for all of MyAnnotatedTypemethods, including inherited ones.

If B runs before A, the Base class will not yet exist, so when B examines the hierarchy of MyAnnotatedType, the super-class type mirror will have type kind ERROR. B can take this as indication to defer the handling of MyAnnotatedType to a later round.

As A runs, it will generate the Base class, leading to another processing round.

If now B runs the second time, it can process all the types deferred from the previous round. As Base exists now, it will not have type kind ERROR any more. For that I noticed (using javac) that it is important to get a fresh Element representing the type and not keep the one from the first round which still contains the reference to the erroneous super-type.

If Base has no erroneous super-types itself, the hierarchy for MyAnnotatedType is complete and B can proceed to handle it. Otherwise, the processing would again have to be deferred until the hierarchy finally is complete. If a super-type never is generated, the compilation will end up with an error anyways, for B it should be alright to not generate its code in this case, too.

like image 122
Gunnar Avatar answered Oct 15 '22 04:10

Gunnar