Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does Guice Populate Annotated Fields

For the sake of my own education, I wanted to build a simple Dependency Injection framework that functions similar to the way Google's Guice does. So that when a class is loaded, it pre-populates annotated fields with data from a factory class.

I am using Reflections to scan all my factory classes at compile time and save those classes in a static list so that when it comes time to load my classes, I have a reference to my factories that I can then scan methods and return the appropriate data.

Where i'm stuck at is how to pre-populate my classes annotated fields without actually doing any of the work in the actual class. In other words, when a class is loaded, I need to be able to determine if any of the fields are annotated with a specific annotation, and if they are, retrieve the value from the factory class.

Is there some way of performing reflection on a class right before it is loaded, pre-populate specific fields and then return an instance of that class to be used?

I could extend all of my classes that require dependency injection with a base class that does all of this work, but I figure there must be a better way so that I can simply use an @Inject (or whatever annotation I decide to use to say that this field requires DI) and "magically" all the work is done.

like image 658
ryandlf Avatar asked Mar 05 '12 14:03

ryandlf


1 Answers

The way that Guice approaches this is that it will only populate the fields of an instance that was itself created by Guice1. The injector, after creating the instance, can use the Reflection API to look at the fields of the Class and inspect their annotations with Field.getDeclaredAnnotations().

This is also the reason why, when you want to inject into a static field, you need to use Binder.requestStaticInjection() to populate the static fields.

Guice does not simply scan your code for annotations; all injections recurse from an explicit request (e.g. requestStaticInjection(), Injector.getInstance(), etc). Now often that initial, explicit request will have been made in some library code.

For example, if you're using guice-servlet you let Guice create the instances of your servlet by using the serve().with() calls. But if you didn't do that, and instead left your servlet config in your web.xml, Guice would not inject into your servlet.

1 - You can also request explicit injection using Binder.requestInjection().

like image 104
Mark Peters Avatar answered Oct 20 '22 12:10

Mark Peters