Skip to content

Simplest dependency injection library ever! Small and fast, supports java 1.5+, processing @Inject (and optionally @singleton) annotation, JSR-330

License

Notifications You must be signed in to change notification settings

daggerok/daggerok-context

Repository files navigation

daggerok-context java 1.5+

description

Simplest lightly dependency injection library for java ever! Processing @Inject and optionally @Singleton annotations from JSR-330 Minimal supported java version: 1.5

installation

daggerok-context

build.gradle
repositories {
  jcenter()      // available in bintray
  // or
  mavenCentral() // also available in maven central
}

dependencies {
  compile "com.github.daggerok:daggerok-context:1.0.4"
}

daggerok-context

pom.xml
<dependencies>
  <dependency>
    <groupId>com.github.daggerok</groupId>
    <artifactId>daggerok-context</artifactId>
    <version>1.0.4</version>
  </dependency>
</dependencies>

<!-- only for bintray use case: -->
<repositories>
  <repository>
    <id>jcentral</id>
    <url>https://jcenter.bintray.com</url>
  </repository>
</repositories>

usage

MyRepostory.java - let’s say we have repository component (annotation @Singleton is optional)
@Singleton
public class MyRepository {

  public String repositoryMethod() {
    return "MyRepository.repositoryMethod";
  }
}
MyClient.java - we also have another component with auto injectior, i.e: creates new empty HashMap automatically if it’s not exists using default constructor
public class MyClient {

  private final HashMap<String, Object> config;

  @Inject
  public MyClient(HashMap<String, Object> config) {
    this.config = config;
  }

  public String clientMethod() {
    return "MyClient.clientMethod" + config.size();
  }
}
MyService.java - lastly, we have service with two injectors MyRepository / MyClient Annotation @Inject is required. Class can have only one constructor with all injectors configuration
public class MyService {

  private final MyClient myClient;
  private final MyRepository myRepository;

  @Inject
  public MyService(MyClient myClient, MyRepository myRepository) {
    this.myClient = myClient;
    this.myRepository = myRepository;
  }

  public String serviceMethod() {
    return myClient.clientMethod() + myRepository.repositoryMethod();
  }
}
MyAppTest.class - and finally test application
public class MyAppTest {

  @Test
  public void test() {

    DaggerokContext applicationContext = DaggerokContext.create(MyAppTest.class)
                                                        .initialize();
    /*
      initialize() method will do:

      1. scan everithyng in base package of MyAppTest
      2. create MyRepository instance in applicationContext
      3. using default constructor create HashMap instance in applicationContext
      4. inject HashMap and create MyClient instance in applicationContext
      5. inject MyRepository and MyClient and create MyService instance in applicationContext
    */

    MyService myService = applicationContext.getBean(MyService.class);
    String actual = myService.serviceMethod();

    assertTrue(actual.contains("MyClient.clinetMethod"));
    assertTrue(actual.contains("MyRepository.repositoryMethod"));
    assertTrue(actual.contains("0"));

    HashMap config = applicationContext.getBean(HashMap.class);
    config.put("message", "hello");
    assertTrue(myService.serviceMethod().contains("1"));
  }
}

public API overview

Entry point: create uninitialized context using:

  1. DaggerokContext#create()

  2. DaggerokContext#create(Class…​)

  3. DaggerokContext#create(Package…​)

  4. DaggerokContext#create(String…​)

many ways create context
// empty context with single DaggerokContext bean registered:
DaggerokContext.create();

// by base class:
DaggerokContext.create(MyApp.class);

// by base packages:
DaggerokContext.create(MyApp.class.getPackage(), Package.getPackages());

// create context by packages:
DaggerokContext.create("my.app", "my.other.app");

// we are not recommend create context from empty package, but it's possible :)
DaggerokContext.create("");

// we also do not recommend create context for all packages in classpath, and yes, it's possible too :)
DaggerokContext.create(Package.getPackages());

User configurations:

  1. DaggerokContext#withBasePackageClasses(Class…​)

  2. DaggerokContext#withBasePackageNames(String…​)

  3. DaggerokContext#withBasePackages(Package…​)

  4. DaggerokContext#withComponents(Annotation)

  5. DaggerokContext#withInjectors(Annotation)

  6. DaggerokContext#failOnInjectNullRef(boolean)

  7. DaggerokContext#failOnBeanCreationError(boolean)

  8. DaggerokContext#failOnUnknownReflectionsErrors(boolean)

create simple (empty) context and add base packages configurations for scan
final DaggerokContext applicationContext = DaggerokContext.create();
// ...
applicationContext.withBasePackageNames("my.app");
applicationContext.withBasePackageClasses(my.app.Config);
applicationContext.withBasePackages(Package.getPackage("my.other.app.pkg"));
set custom component annotation
applicationContext.withComponents(Singleton.class);
set custom injector annotation
applicationContext.withInjectors(Inject.class);
fail on inject null bean
applicationContext.failOnInjectNullRef(false);
fail on bean creation error Class.newInstance()
applicationContext.failOnBeanCreationError(false);
fail on unknown Reflections library errors
applicationContext.failOnUnknownReflectionsErrors(false);

Manual beans registration:

  1. DaggerokContext#register(String, Object)

  2. DaggerokContext#register(Class, Object)

manually bean register
// by class:
applicationContext.register(MyRepostory.class, new MyRepository())
                  .register("java.util.Map", singletonMap("hello", "world"))
                  .register(String.class, "Hello, World!");

// by name:
applicationContext.register("my.app.MyBean", new MyBean("custom bean initialization..."))
                  .register("java.lang.String", "Hey, y0!");

Search, create and inject everything we can:

  1. DaggerokContext#initialize()

minimal required configuration
DaggerokContext.create("")
               .initialize();
other possible configuration
DaggerokContext applicationContext = DaggerokContext.create(String.class)
                                                    .failOnInjectNullRef(true)
                                                    .register(String.class, "Hello, World!")
                                                    .initialize();

System.out.println(applicationContext.getBean(String.class));

Get bean from context - could be used before initialize() if bean was previously manually added:

  1. DaggerokContext#getBean(Class)

  2. DaggerokContext#getBean(String, Class)

  3. DaggerokContext#getBean(String)

build application context
// get bean by class
MyRepository myRepository = applicationContext.getBean(MyRepository.class);
Map<String, String> map = applicationContext.getBean(Map.class);
String string = applicationContext.getBean(String.class);

// get named beans
Map<String, String> map = applicationContext.getBean("java.util.Map", Map.class);
HashMap<String, String> myOtherMap = applicationContext.getBean("myOtherMap", HashMap.class);

// get named beans (unchecked)
Map<String, String> map = applicationContext.getBean("java.util.Map");
HashMap<String, String> myOtherMap = applicationContext.getBean("myOtherMap");
String string = applicationContext.getBean("java.lan.String");
String oneMoreString = applicationContext.getBean("oneMoreString");

why?

  • no more magic!

  • no more xml!

  • no more weight dependencies!

  • no more evil field injections!

  • no more abstract modules!

  • no more plugins configurations!

  • no more annotation processing configurations!

  • no more custom annotations clones! use standards, use JSR-330!

  • no more specific build configurations! single dependency only!

it’s really simple

  • JSR-330: supports only @Inject

  • all class-based registration creates singletons

  • supports custom named beans registration

It’s simple. Simple means fast, less bugs, more fun. It’s doing one thing and doing it well …​unless you found a bug :)

other installation variants

gradle bintray.daggerok

gradle setup (build.gradle)
repositories {
  maven { url "https://dl.bintray.com/daggerok/daggerok" }
}

dependencies {
  compile "com.github.daggerok:daggerok-context:1.0.4"
}

gradle jitpack

gradle setup (build.gradle)
repositories {
  maven { url "https://jitpack.io" }
}

dependencies {
  compile "com.github.daggerok:daggerok-context:1.0.4"
}

maven bintray/daggerok

maven setup (pom.xml)
<repositories>
  <repository>
    <id>bintray-daggerok-daggerok</id>
    <url>https://dl.bintray.com/daggerok/daggerok</url>
  </repository>
</repositories>

<dependencies>
  <dependency>
    <groupId>com.github.daggerok</groupId>
    <artifactId>daggerok-context</artifactId>
    <version>1.0.4</version>
  </dependency>
</dependencies>

maven jitpack

maven setup (pom.xml)
<repositories>
  <repository>
    <id>jitpack.io</id>
    <url>https://jitpack.io</url>
  </repository>
</repositories>

<dependencies>
  <dependency>
    <groupId>com.github.daggerok</groupId>
    <artifactId>daggerok-context</artifactId>
    <version>1.0.4</version>
  </dependency>
</dependencies>

TODO

  • short public API description with examples or documentation

  • publish to mavenCentral

contribution

Feel free extend and contribute to add more functionality like Named Qualifier. Personally I’d like to keep it simple as possible. On really big projects therese days you probably would like to use something like Guice, Dagger, CDI from JavaEE or Spring from spring-boot, or maybe even PicoContainer, who knows :))