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).
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 MyAnnotatedType
methods, 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With