####About Feather#### Feather is an ultra-lightweight dependency injection (JSR-330) library for Java and Android. Dependency injection frameworks are often perceived as "magical" and complex. Feather - with just a few hundred lines of code - is probably the easiest, tiniest, most obvious one, and is quite efficient too (see comparison section below).
<dependency>
<groupId>org.codejargon.feather</groupId>
<artifactId>feather</artifactId>
<version>1.0</version>
</dependency>Javadoc for Feather #####Usage - code examples##### ######Create Feather (the injector)######
Featherfeather = Feather.with();An application typically needs a single Feather instance.
######Instantiating dependencies###### Dependencies with @Inject constructor or a default constructor can be injected by Feather without the need for any configuration. Eg:
publicclassA {
@InjectpublicA(Bb) {
// ...
}
}
publicclassB {
@InjectpublicB(Cc, Dd) {
// ...
}
}
publicclassC {}
@SingletonpublicclassD {
// something expensive or other reasons for being singleton
}Creating an instance of A:
Aa = feather.instance(A.class);######Providing additional dependencies to Feather###### When injecting an interface, a 3rd party class or an object needing custom instantiation, Feather relies on configuration modules providing those dependencies:
publicclassMyModule {
@Provides@Singleton// an app will probably need a single instance DataSourceds() {
DataSourcedataSource = // instantiate some DataSourcereturndataSource;
}
}Setting up Feather with module(s):
Featherfeather = Feather.with(newMyModule());The DataSource dependency will now be available for injection:
publicclassMyApp {
@InjectpublicMyApp(DataSourceds) {
// ...
}
}Feather injects dependencies to @Provides methods aguments. This is particularly useful for binding an implementation to an interface:
publicinterfaceFoo {}
publicclassFooBarimplementsFoo {
@InjectpublicFooBar(Xx, Yy, Zz) {
// ...
}
}
publicclassMyModule {
@ProvidesFoofoo(FooBarfooBar) {
returnfooBar;
}
}
// injecting an instance of Foo interface will work using the MyModule above:publicclassA {
@InjectpublicA(Foofoo) {
// ...
}
}Note that the @Provides method serves just as a binding declaration here, no manual instantiation needed ######Qualifiers###### Feather supports Qualifiers (@Named or custom qualifiers)
publicclassMyModule {
@Provides@Named("greeting")
Stringgreeting() {
return"hi";
}
@Provides@SomeQualifierFoosome(FooSomefooSome) {
returnfooSome;
};
}Injecting:
publicclassA {
@InjectpublicA(@SomeQualifierFoofoo, @Named("greeting") Stringgreet) {
// ...
}
}Or directly from feather:
Stringgreet = feather.instance(String.class, "greeting");
Foofoo = feather.instance(Key.of(Foo.class, SomeQualifier.class));######Provider injection###### Feather injects Providers to facilitate lazy loading or circular dependencies:
publicclassA {
@InjectpublicA(Provider<B> b) {
Bb = b.get(); // fetch a new instance when needed
}
}Or getting a Provider directly from Feather:
Provider<B> bProvider = feather.provider(B.class);######Override modules######
publicclassModule {
@ProvidesDataSourcedataSource() {
// return a mysql datasource
}
// other @Provides methods
}
publicclassTestModuleextendsModule {
@Override@ProvidesDataSourcedataSource() {
// return a h2 datasource
}
}######Field injection###### Feather supports Constructor injection only when injecting to a dependency graph. It inject fields also if it's explicitly triggered for a target object - eg to facilitate testing. A simple example with a junit test:
publicclassAUnitTest {
@InjectprivateFoofoo;
@InjectprivateBarbar;
@BeforepublicvoidsetUp() {
Featherfeather = // obtain a Feather instancefeather.injectFields(this);
}
}######Method injection###### Not supported. The need for it can be generally avoided by a Provider / solid design (favoring immutability, injection via constructor).
#####Android example#####
classExampleApplicationextendsApplication {
privateFeatherfeather;
@OverridepublicvoidonCreate() {
// ...feather = Feather.with( /* modules if needed*/ );
}
publicFeatherfeather() {
returnfeather;
}
}
classExampleActivityextendsActivity {
@InjectprivateFoofoo;
@InjectprivateBarbar;
@OverridepublicvoidonCreate(BundlesavedState) {
// ...
((ExampleApplication) getApplication())
.feather()
.injectFields(this);
}
}For best possible performance, dependencies should be immutable and @Singleton. See full example in android-test. #####Footprint, performance, comparison##### Small footprint and high performance is in Feather's main focus.
- compared to [Guice] (https://github.com/google/guice "Guice"): 1/50 the library size, ~10x startup speed
- compared to Dagger: 1/4 the library size (of just Dagger's run-time part), ~2x startup speed
Note: startup means creation of the container and instantiation of an object graph. Executable comparison including Spring, Guice, Dagger, PicoContainer is in 'performance-test' module.
#####How it works under the hood##### Feather is based on optimal use of reflection to provide dependencies. No code generating, classpath scanning, proxying or anything costly involved.
A simple example with some explanation:
classA {
@InjectA(Bb) {
}
}
classB {
}Without the use of Feather, class A could be instantiated with the following factory methods:
Aa() {
returnnewA(b());
}
Bb() {
returnnewB();
}Most of the information in these factories are redundant and they tend to be hot spots for changes and sources for merge hells. Feather avoids the need for writing such factories - by doing the same thing internally: When an instance of A is injected, Feather calls A's constructor with the necessary arguments - an instance of B. That instance of B is created the same way - a simple recursion, this time with no further dependencies - and the instance of A is created.