You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Feb 26, 2023. It is now read-only.
Repository navigation
This repository was archived by the owner on Feb 26, 2023. It is now read-only.
Hi, right now in AA an @EBean should be injected only referencing its class. Though, it is a good practice in many different scenarios to provide an inteface to access to a specific implementation (this also facilitates Unit Testings a lot!).
I consider it is not difficult the implementation of an annotation @ImplementedBy which can be placed over interfaces:
In general, a first implementation which at least supports @ImplementedBy could comes quite handy.
The implementation in AA is not that difficult to do. the BeanHandler simply checks if the Interface provided is annotated with @ImplementedBy, if so, then it performs the injection with that class.
There is a second variant, which could be more "solid", but will require a little more of implementation. The issue with annotating the Interface is that in fact, we're forcing the change of the interface. That would be no possible if the interface is in a library for instance.
Though, to be honest, a very simple solution would be don't annotate extra, but permit injection of interfaces automatically. For instance:
On this case, for AA to be able to inject the instance, when the EBeanHandler processes all the @ebeans, it would have to "store" which of the Beans implements a given interface.
With gradle that would be simpler, since all the classes are always processed. But with Ant could be a little problematic due to the incremental compilation of the classes. There is always solutions (like storing in a config file the classes which implements a given interface.
Well, it is an idea of implementing the same functionality without having to modify interfaces. Different mechanism could be used later to resolve the best matching for a given interface.
@smaugho Gradle is also supporting incremental compilation, even with annotation processors. AA always supported it, and we take advantage back in the Eclipse days. So we should really carefully design new behavior that will work well with incremental compilation.
@WonderCsabo , a simple solution (that I"ve implemented before), is to create a configuration file in the project root (not in the generated files).. so a folder ".aa" is created in the Root of the project (or project module), let's say, similar to how the ".idea" folder is created for the project by IntelliJ IDE, and it can save information about previous processed classes. This information can be used later on this type of injections, so that the system is "aware" of what was injected.
A different solution, would force to search for whole the classes which one implemented that Interface and is annotated with @EBean, I guess that one will be no good.
The @ImplementedBy annotation suggested above also solves the problem, but now I don't think that modifying an interface with that is good idea, it "breaks" the purpose of it a little.
Though adding the ability to inject Interfaces could be really beneficial right? Right now Google is making so much effort on Architecture Components and good practices, trying to convince new devs of using it from the beginning. I'm in fact working in a Plugin for AndroidAnnotations called Archiannotations, which makes use of all the AndroidArchitecture components (I hope you like it once done, and we could add it here to the plugins of the framework https://github.com/smaugho/archiannotations).
To have a mechanism to inject interfaces will raise the value of AA in general, no that far then from Dagger. Right now you could inject "interfaces" implemented by the Context (ie. activity) with @rootcontext:
@RootContextMyImplementedInterfacefield;
Extending this to #1636 (which I'm working in), and finally to @Bean would complete the feature.
I could make an implementation which makes an iteration on the classes of the project initially (I think is possible), and detects all the @ebean, in order to register their implemented interfaces. Or we could decide to stay with the @ImplementedBy extra annotation which will reduce the complexity a lot.
Very nice work on archiannotations, we will of course add it to the plugin list.
On the @EBeans: honestly, this part of AA always wanted to be just a very simple injection FW. For large projects, i suggest to use Dagger - it works well with AA, we have documentation how the 2 can work together.
The @Bean annotation already has a parameter so you can tell it what is the actualy class instance to be created. I am not sure why the @ImplementedBy is better than this, but if you think it is valueable feel free to open a PR with the simple version (no string keys etc).
@WonderCsabo I was curious about your claim above of Gradle being able to compile incrementally with the annotation processor. I was looking for that information and found this:
So basically, from Gradle 4.7 this is supported, but the annotation processor should request it. On our case, AA doesn't request this feature. Note, this is just a general doubt (so no about this issue), but it makes me quite interested on requesting this for AA.
I have projects which could take even 6mins to build!
I've reconsidered this, the implementation parameter provided in the @bean is not that different (well, having it in the Interface simplifies its usage when injecting in multiple parts, not having to go to change all those places is the implementation changes, though the benefits are not really that big).
Activity
smaugho commentedon Feb 12, 2019
Here is a very simple implementation of @ImplementedBy. Of course, only something initial:
smaugho@2f0b381
smaugho commentedon Feb 12, 2019
There is a second variant, which could be more "solid", but will require a little more of implementation. The issue with annotating the Interface is that in fact, we're forcing the change of the interface. That would be no possible if the interface is in a library for instance.
Though, to be honest, a very simple solution would be don't annotate extra, but permit injection of interfaces automatically. For instance:
And you could inject normally with:
On this case, for AA to be able to inject the instance, when the EBeanHandler processes all the @ebeans, it would have to "store" which of the Beans implements a given interface.
With gradle that would be simpler, since all the classes are always processed. But with Ant could be a little problematic due to the incremental compilation of the classes. There is always solutions (like storing in a config file the classes which implements a given interface.
Well, it is an idea of implementing the same functionality without having to modify interfaces. Different mechanism could be used later to resolve the best matching for a given interface.
Feedbacks welcome!
smaugho commentedon Feb 12, 2019
A very simple implementation of this second variant could be seen here:
smaugho@3ac65a1
No extra annotation is needed, and
@Beandetects automatically which@EBeanto inject based in the used interface.I did it simply saving the qualified name of the class. Though, for a more robust implementation probably is better to save the TypeMirror.
WonderCsabo commentedon Feb 14, 2019
@smaugho Gradle is also supporting incremental compilation, even with annotation processors. AA always supported it, and we take advantage back in the Eclipse days. So we should really carefully design new behavior that will work well with incremental compilation.
smaugho commentedon Feb 14, 2019
@WonderCsabo , a simple solution (that I"ve implemented before), is to create a configuration file in the project root (not in the generated files).. so a folder ".aa" is created in the Root of the project (or project module), let's say, similar to how the ".idea" folder is created for the project by IntelliJ IDE, and it can save information about previous processed classes. This information can be used later on this type of injections, so that the system is "aware" of what was injected.
A different solution, would force to search for whole the classes which one implemented that Interface and is annotated with
@EBean, I guess that one will be no good.smaugho commentedon Feb 14, 2019
The
@ImplementedByannotation suggested above also solves the problem, but now I don't think that modifying an interface with that is good idea, it "breaks" the purpose of it a little.WonderCsabo commentedon Feb 14, 2019
I do not think a configuration file approach is good either, it adds lots of complexity.
smaugho commentedon Feb 14, 2019
Though adding the ability to inject Interfaces could be really beneficial right? Right now Google is making so much effort on Architecture Components and good practices, trying to convince new devs of using it from the beginning. I'm in fact working in a Plugin for AndroidAnnotations called Archiannotations, which makes use of all the AndroidArchitecture components (I hope you like it once done, and we could add it here to the plugins of the framework https://github.com/smaugho/archiannotations).
To have a mechanism to inject interfaces will raise the value of AA in general, no that far then from Dagger. Right now you could inject "interfaces" implemented by the Context (ie. activity) with @rootcontext:
Extending this to #1636 (which I'm working in), and finally to
@Beanwould complete the feature.I could make an implementation which makes an iteration on the classes of the project initially (I think is possible), and detects all the @ebean, in order to register their implemented interfaces. Or we could decide to stay with the
@ImplementedByextra annotation which will reduce the complexity a lot.Let me know your thoughts about it!.. thanks!
WonderCsabo commentedon Feb 14, 2019
Very nice work on
archiannotations, we will of course add it to the plugin list.On the
@EBeans: honestly, this part of AA always wanted to be just a very simple injection FW. For large projects, i suggest to use Dagger - it works well with AA, we have documentation how the 2 can work together.The
@Beanannotation already has a parameter so you can tell it what is the actualy class instance to be created. I am not sure why the@ImplementedByis better than this, but if you think it is valueable feel free to open a PR with the simple version (no string keys etc).smaugho commentedon Feb 15, 2019
@WonderCsabo I was curious about your claim above of Gradle being able to compile incrementally with the annotation processor. I was looking for that information and found this:
https://docs.gradle.org/current/userguide/java_plugin.html?_gl=1*q9cey8*_ga*MjAxNDcxMjcwOC4xNTQ4NzIyNTEz*_gid*MTM5MzU5MjI3MC4xNTUwMTkwNDU5#example_registering_incremental_annotation_processors
So basically, from Gradle 4.7 this is supported, but the annotation processor should request it. On our case, AA doesn't request this feature. Note, this is just a general doubt (so no about this issue), but it makes me quite interested on requesting this for AA.
I have projects which could take even 6mins to build!
WonderCsabo commentedon Feb 15, 2019
Opting into Gradle specific incremental compilation is already added as a task. :) #2193
smaugho commentedon Feb 17, 2019
I've reconsidered this, the implementation parameter provided in the @bean is not that different (well, having it in the Interface simplifies its usage when injecting in multiple parts, not having to go to change all those places is the implementation changes, though the benefits are not really that big).