Active Annotations: dependencies and multiple passes for transformation process

69 views
Skip to first unread message

kirstenk...@gmail.com

unread,
Aug 19, 2015, 3:03:36 PM8/19/15
to Xtend Programming Language
Hi,

I am currently trying to use different active annotations, which should also "help each other".

For example, I am applying the annotation Extract (xtend-annotation-example) in order to "extract an Interface for all locally declared public methods". This means, that a new interface is created/registered during "Phase 1: Register Globals". In "Phase 2: Transformation" this interface is populated with all public methods from the annotated class.

I also want to use the annotation Delegate. For this field annotation an interface can be used as type, in order to automatically create delegation methods during the transformation phase. Now I also want to use the interface, which is automatically derived because of the Extract annotation.

This is only a small example, where the usage of active annotations can depend on each other. I even planned further, but I am struggling hard. I have sometimes trouble with this, especially when I clean a Project, i.e. everything shall be recreated.

In my opinion, the functionality of the delegate processor in the transformation phase can only work correctly, after the interface has been populated, i.e. the transformation Phase for the extract processor has been completed.

Is this assumption correct?
If yes, how can the order of execution be ensured?

I really have no idea how to solve this in a clean way. Would it be a solution to support multiple passes during the transformation phase? This way interfaces could be populated in "pass 1", while delegation is resolved in "pass 2". Or prioritization of active annotations, but is this flexible enough?

I tried solving this problem outside of xtend inside active annotation processor code. I used a simple mechanism to store transformation calls and run them later in the correct order. I failed :)

I am curious, if this topic has already been discussed.
Thanks in advance!

Kirsten

Stefan Oehme

unread,
Aug 20, 2015, 4:14:19 AM8/20/15
to Xtend Programming Language
Hi Kirsten,

the order of annotation processing is as follows: 

- processors are run on a per-file-basis
- files are processed in the order of their dependencies (cyclic dependencies between files can lead to problems on clean builds)
- inside a single file, annotations are processed in the order of first appearance

So for the example of @Extract and @Delegate, everything should work fine as long as
- they are in separate files or
- the @Extract-annotated class comes first in the file

Could you provide an example where you have problems on clean builds?

Cheers,
Stefan

kirstenk...@gmail.com

unread,
Aug 20, 2015, 9:29:23 AM8/20/15
to Xtend Programming Language

Hello Stefan,

your workflow already helps a lot understanding what is going on, thanks.

However, I am wondering how the file dependency can really be derived as long as files do not exist completely before the transformation phase? The dependency is based on imports?
Independently, I have the cyclic dependency you mentioned.

My use case is complicated (at least right now). Everything is a mess, so I have to work on it.

The pattern I need:

Class A (master) and Class B (extension class) need to have an interface with all their public methods
Class A implements the interface of class B
Class B implements the interface of class A
Class A delegates to methods in class B for all methods in B, which are not in A
Class B delegates to methods in class A for all methods in A (interface), which are not in B
Some specific construction of delegates etc.

The needed “boilerplate” code should be created by easy-to-understand active annotations. Therefore, I created own annotations based on @Extract and @Delegate, which also combine them. In addition, the delegation must be a little bit more intelligent.

Simplified, the pattern above allows the possibility to “extend” a class A by some methods from another class B. Thereby, it should be possible to implement the methods in class B as if they would be in class A.

Stefan Oehme

unread,
Aug 20, 2015, 10:14:09 AM8/20/15
to xtend...@googlegroups.com
Hi Kirsten,

my "dependencies" explanation was too vague: It is just a matter of navigating the model. So when you navigate from A to B, then we try to compute the AST for B. If B now refers to A again, then all we can do is return the unfinished AST of A. Otherwise you would get infinite recursion.

So I'm afraid that use case is currently unsupported, because it would need multiple passes.

Maybe you can find a different design that breaks the cyclic dependencies? Otherwise, feel free to open an enhancement request. =)

Cheers,
Stefan

--
You received this message because you are subscribed to a topic in the Google Groups "Xtend Programming Language" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/xtend-lang/t6awI3v3LKA/unsubscribe.
To unsubscribe from this group and all its topics, send an email to xtend-lang+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

kirstenk...@gmail.com

unread,
Sep 28, 2015, 10:39:46 AM9/28/15
to Xtend Programming Language
Hi,

unfortunately, my active annotations, which by the way proved to help us with a lot with boiler plate code, would require such a feature for "integrating smoothly".

We are still happy, because there is no impact, if we share generated files (this means in our SCM) and work in a regular way.

However, there are big problems, if building everything (including all generated files) from scratch. The workaround is to build multiple times without removing the generated sources in between. So after the "major" generation, if you clean a project, you have to open each xtend file, modify (e.g. add a space), save and in the end everything is fine.
I am wondering, if such a workaround can be automated at least. I was trying to find "recent" information how to trigger a Xtend compilation via ANT, for example. However, after trying for several hours with all the libraries in project scope (necessary???) etc, I was not able to. I really do not trust what Google finds here and if this is still valid.

Maybe, you can give me a hint. By clicking somewhere in Eclipse (e.g. by running an ANT file), the Xtend compiler shall be run on it. Completely and twice! Do you know an easy solution?

Stefan Oehme

unread,
Sep 28, 2015, 11:25:02 AM9/28/15
to xtend...@googlegroups.com
Hi Kirsten,

I don' think building twice is a good solution and I have no good advice for how to do that.

Please feel free to open an enhancement request, asking for multiple-pass annotation processing. There is no other way to make these kind of cyclic processors work. Writing one so it doesn't lead to endless builds would still be challenging, though =)

For the use case you described, you could probably get rid of the cycles by generating "base" interfaces that only contain the methods actually written down in the class. Then the Slave class only depends on MasterBase. Of course that means it will not see methods added by Slave2. But you could add a "require" mechanism that allows to include methods from other Slave classes if needed. It is just a small amount of added boilerplate but removes the cycles and reduces the number of files that need to be recompiled on every change, making Eclipse faster.

Cheers,
Stefan
Reply all
Reply to author
Forward
0 new messages