Determine type stability in a Java annotation handler

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

This works overall, but I'm afraid to do it right if other annotation processors are around. In particular, such a different processor can generate a superclass for the type processed by my processor, so I also need to consider the properties of the supertype. In the next round, a superclass for this superclass can be generated, etc.

This means that I should not generate my source code until the hierarchy of the type of interest to me is stable, i.e. in subsequent rounds (or in the same round after my processor no additional supertypes will be created) by other processors.

How can I find out if this is so? I know RoundEnvironment#processingOver() and the ability to generate my code in the last final round, but I understand that this is bad practice (the compiler will give a warning).

+6
source share
2 answers

To answer my own question:

An annotated type can be considered stable or complete if all of its supertypes are not erroneous. Example:

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

Suppose there is one A annotation handler for @GenBase that generates the specified class, Base in this case. And another processor B is interested in the entire MyAnnotatedType hierarchy, for example. he wants to create some kind of descriptor for all MyAnnotatedType methods, including those inherited.

If B runs to A, the Base class does not exist yet, so when B examines the MyAnnotatedType hierarchy, the superclass type mirror will be of type ERROR . B may take this as an indication to defer processing of MyAnnotatedType to a later round.

When starting A, it will generate the Base class, which will lead to another round of processing.

If B now works a second time, it can handle all types deferred in the previous round. Since Base exists now, it will no longer be of type ERROR . For this, I noticed (using javac) that it is important to get a fresh Element representing the type and not save it in the first round, which still contains a link to the erroneous supertype.

If Base does not have the erroneous supertypes themselves, the hierarchy for MyAnnotatedType complete, and B can proceed to process it. Otherwise, processing should again be delayed until the hierarchy ends. If the supertype is never generated, compilation will have an error anyway, for B it should be good so as not to generate code in this case either.

+3
source

When you say that you want to initiate source generation based on a set of JavaBeans properties, I assume that you mean getter / setter pairs, anyway this is not your question.

Typically, the JSR 269 specification is not implemented so that multiple annotation processors can be coordinated. This is by design, and all processors should be idempotent (which means that the record -> the same output).

So, things like “I should not generate source code until the type hierarchy is stable,” is simply impossible to achieve without breaking into the legal process. Responsibility of javac for detecting stability.

The generation of code in the last round is prohibited, since the only purpose of the last round is to ensure that your processor frees up unused resources. If other processors do the same, you are in danger! So for me no.

The only possible solution I can think of is to declare that your processor processes all annotations (this is possible by specifying "*" as the processed annotation). I am not sure if this will not block another processor that needs to be checked. But if that works, your processor will be called every time new files are generated. Then you processed them normally, and the subject of convergence would be normally detected by javac.

I am not 100% sure about this solution, but it might be worth a try.

-1
source

All Articles