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 >

Usage - code examples Create Feather (the injector) Feather feather = 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:

public class A { @Inject public A ( B b ) { // ... } } public class B { @Inject public B ( C c , D d ) { // ... } } public class C {} @ Singleton public class D { // something expensive or other reasons for being singleton }

Creating an instance of A:

A a = 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:

public class MyModule { @Provides @Singleton // an app will probably need a single instance DataSource ds () { DataSource dataSource = // instantiate some DataSource return dataSource; } }

Setting up Feather with module(s):

Feather feather = Feather . with( new MyModule ());

The DataSource dependency will now be available for injection:

public class MyApp { @Inject public MyApp ( DataSource ds ) { // ... } }

Feather injects dependencies to @Provides methods aguments. This is particularly useful for binding an implementation to an interface:

public interface Foo {} public class FooBar implements Foo { @Inject public FooBar ( X x , Y y , Z z ) { // ... } } public class MyModule { @Provides Foo foo ( FooBar fooBar ) { return fooBar; } } // injecting an instance of Foo interface will work using the MyModule above: public class A { @Inject public A ( Foo foo ) { // ... } }

Note that the @Provides method serves just as a binding declaration here, no manual instantiation needed

Qualifiers

Feather supports Qualifiers (@Named or custom qualifiers)

public class MyModule { @Provides @Named ( " greeting " ) String greeting () { return " hi " ; } @Provides @SomeQualifier Foo some ( FooSome fooSome ) { return fooSome; }; }

Injecting:

public class A { @Inject public A ( @SomeQualifier Foo foo , @Named ( " greeting " ) String greet ) { // ... } }

Or directly from feather:

String greet = feather . instance( String . class, " greeting " ); Foo foo = feather . instance( Key . of( Foo . class, SomeQualifier . class));

Provider injection

Feather injects Providers to facilitate lazy loading or circular dependencies:

public class A { @Inject public A ( Provider< B > b ) { B b = b . get(); // fetch a new instance when needed } }

Or getting a Provider directly from Feather:

Provider< B > bProvider = feather . provider( B . class);

Override modules public class Module { @Provides DataSource dataSource () { // return a mysql datasource } // other @Provides methods } public class TestModule extends Module { @Override @Provides DataSource dataSource () { // 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:

public class AUnitTest { @Inject private Foo foo; @Inject private Bar bar; @Before public void setUp () { Feather feather = // obtain a Feather instance feather . 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

class ExampleApplication extends Application { private Feather feather; @Override public void onCreate () { // ... feather = Feather . with( /* modules if needed*/ ); } public Feather feather () { return feather; } } class ExampleActivity extends Activity { @Inject private Foo foo; @Inject private Bar bar; @Override public void onCreate ( Bundle savedState ) { // ... (( ExampleApplication ) getApplication()) .feather() .injectFields( this ); } }

For best possible performance, dependencies should be immutable and @Singleton. See full example in android-test on GitHub.

Footprint, performance, comparison

Small footprint and high performance is in Feather's main focus.

compared to Guice: 1/50 the library size, about 10x startup speed

compared to Dagger: 1/4 the library size (of just Dagger's run-time part), about 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 on GitHub.

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:

class A { @Inject A ( B b) { } } class B { }

Without the use of Feather, class A could be instantiated with the following factory methods:

A a() { return new A (b()); } B b() { return new B (); }

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.