Blazingly fast and lightweight dependency injection framework for Java. Supported operations:
- Creating a new instance of the specified type using Injector (constructors)
- Invoking methods using Injector (methods)
- Reflection based field injection during instance creation (fields)
Library is available in panda-repository
:
<repository>
<id>panda-repository</id>
<url>https://maven.reposilite.com/releases</url>
</repository>
To use annotations
, declare the dependency in your pom.xml
<dependency>
<groupId>org.panda-lang.utilities</groupId>
<artifactId>di</artifactId>
<version>1.8.0</version>
</dependency>
<!-- Codegen module -->
<dependency>
<groupId>org.panda-lang.utilities</groupId>
<artifactId>di-codegen</artifactId>
<version>1.8.0</version>
</dependency>
Firstly, you have to create Injector
which keeps all the registered bindings (injected values)
Injector injector = DependencyInjection.createInjector()
// If you are able to register binding at the init time, it's also recommended to use the following structure
Injector injector = DependencyInjection.createInjector(resources -> {
// bind resources
});
Injector supports three main ways to bind with a value:
- Binding to the specified type
resources.on(<Type>)
- Binding to the specified annotation
resources.annotatedWith(<Annotation>)
- Binding to the verified annotation
resources.annotatedWithTested(<Annotation>)
(safer but slower alternative toannotatedWith
)
Each binding supports three ways of assigning value:
assignInstance(<Object>)
/assignInstance(Supplier<Object>)
- binds the specified value/some kind of lazy valuesassignHandler((<Expected Type Of Value>, <Annotation>) -> { /* logic */ })
- binds custom handler
The most common use of DI comes down to some kind of instance assignation:
public static class Bean { }
public interface Custom { }
static class CustomImpl implements Custom { }
static class Service {
public Service(Bean bean, Custom custom) {
assertNotNull(bean);
assertNotNull(custom);
}
}
To create Service
class, just invoke its constructor:
Injector injector = DependencyInjection.createInjector();
// some logic, a few hours later...
injector.getResources().on(Custom.class).assignInstance(new CustomImpl()); // singleton
injector.getResources().on(Bean.class).assignInstance(Bean::new); // new instance per call
Service service = injector.forConstructor(Service.class).newInstance();
Full example: DependencyInjectionInstancesTest.java
class Service {
@Inject
private String fieldOne;
@Inject
private Integer fieldTwo;
}
Injector injector = DependencyInjection.createInjector(resources -> {
resources.on(String.class).assignInstance("Hello Field");
resources.on(Integer.class).assignInstance(7);
});
Service service = injector.newInstanceWithFields(Service.class);
Full example: DependencyInjectionFieldsTest.java
Let's build a random example based on these methods using a custom annotation:
@Injectable // mark annotation as DI ready annotation
@Retention(RetentionPolicy.RUNTIME) // make sure that the annotation is visible at runtime
@interface AwesomeRandom { }
static final class Entity {
private final UUID id;
private Entity(@AwesomeRandom UUID random) {
this.id = random;
}
public UUID getId() {
return id;
}
}
We'd like to generate a new id per each Entity
instance with a private constructor. It's also important for us, to support id in two forms:
- String
- UUID
Injector injector = DependencyInjection.createInjector(resources -> {
resources.annotatedWith(AwesomeRandom.class).assignHandler((expectedType, annotation) -> {
if (expectedType.equals(String.class)) {
return UUID.randomUUID().toString();
}
if (expectedType.equals(UUID.class)) {
return UUID.randomUUID();
}
throw new IllegalArgumentException("Unsupported type " + expectedType);
});
});
// Create entities using the injector instance
Entity entityA = injector.newInstance(Entity.class);
Entity entityB = injector.newInstance(Entity.class);
// Print generated values
System.out.println(entityA.getId());
System.out.println(entityB.getId());
The output produces some random identifiers as intended π
e23442b2-f695-41fa-9290-0f1192118a1a
9f92121c-096e-4bdb-b6ad-0901974bbe37
Process finished with exit code 0
Full example is available here -> DependencyInjectionWikiTest.java