<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<dependency>
<groupid>com.github.jwdeveloper.DepenDance</groupid>
<artifactid>DepenDance-Full</artifactid>
<version>0.0.20-Release</version>
</dependency>
Depandance is the dependency injection container library. Is is quite compacts and has a lot of features you can find in the more popular DI container libraries. ## What are the dependecies? Dependecies is the fancy word for a class consturctor parameters. So the objects certain class depends on/ ## What is the dependecy injection? Is is one of the programming design patters, watch great video about it Video ## What is the dependecy injection container? It is library that helps to create instance of object with all its dependecines
. At the beggining you need to register the dependecines classess to the container, then any class that was registed, can be obtained for the container.
-
Injecting object via constructor
-
Method object providers
-
Class Scanner to avoid manual registration Scanner
-
You need to get List of objects in the constructor, no problem
-
Create object instance by yourself and register it to container!
-
Object lifetimes [SINGLETON, TRANSIENT] see
-
Highly customizable, adjust container with build in events system
public class _01_Basic {
public static void main(String[] args) {
/*
- Singleton There will be only one instance of object created by container
- Transient everytime `container.find` is used new instance of object is created
*/
DependanceContainer container = Dependance.newContainer()
.registerTransient(Shop.class, LocalShop.class) //registration interface to implementation
.registerSingleton(Config.class)
.registerSingleton(ShopManager.class)
.build();
ShopManager shopManager1 = container.find(ShopManager.class);
ShopManager shopManager2 = container.find(ShopManager.class);
Shop shop1 = container.find(Shop.class);
Shop shop2 = container.find(Shop.class);
Assert.assertEquals(shopManager1, shopManager2);
System.out.println("There always same instance of shop manager");
Assert.assertEquals(shopManager1.getConfig(), shopManager2.getConfig());
System.out.println("There always same instance of config");
Assert.assertNotEquals(shop1, shop2);
System.out.println("There are different instances of shop");
}
}
public class _02_Object_Instances
{
public static void main(String[] args)
{
Config myConfigInstance = new Config();
DependanceContainer container = Dependance.newContainer()
.registerSingleton(Config.class, myConfigInstance) //in case we want to make instance manually we can put object as second argument
.registerTransient(LocalShop.class,(di)->
{
//more complex case, we want to find or put manually arguments to created instance
//for that we can use lamda resolver that has container as input, and object instance as output
var config = (Config)di.find(Config.class);
var shop = new LocalShop(config);
System.out.println("Shop has been created: "+shop);
return shop;
})
.build();
Config config = container.find(Config.class);
LocalShop shop1 = container.find(LocalShop.class);
LocalShop shop2 = container.find(LocalShop.class);
Assert.assertEquals(myConfigInstance,config);
System.out.println("Config has same instance");
Assert.assertNotEquals(shop1,shop2);
System.out.println("Shops has different instances");
}
}
public class _03_Lists {
public static void main(String[] args) {
DependanceContainer container = Dependance.newContainer()
.registerSingleton(Config.class)
.registerTransient(Shop.class, OnlineShop.class)
.registerTransient(Shop.class, LocalShop.class)
.registerTransientList(Shop.class)
.build();
List<Shop> shops = (List<Shop>) container.find(List.class, Shop.class);
for (var shop : shops) {
System.out.println("Shops: " + shop.getClass().getSimpleName());
}
Assert.assertEquals(2, shops.size());
}
}
public class _04_Events {
public static void main(String[] args) {
DependanceContainer container = Dependance.newContainer()
.registerSingleton(Shop.class, LocalShop.class)
.registerSingleton(Shop.class, OnlineShop.class)
.configure(config ->
{
config.onInjection(_04_Events::onInjection);
config.onRegistration(_04_Events::onRegistration);
})
.build();
Object shops = container.find(Shop.class, String.class);
}
private static Boolean onRegistration(OnRegistrationEvent event) {
System.out.println("onRegistration event: " + event.registrationInfo().implementation().getSimpleName());
return true; //If false `container.find` injection is not registered to container
}
private static Object onInjection(OnInjectionEvent event) {
var inputType = event.input();// searched class type provided as first parameters
var genericTypes = event.inputGenericParameters(); //list of generic types provided as second parameter
var outputObject = event.output(); //Target object instance type has not been found then output value is null
var container = event.container(); //access to DI container
var injectonMetadata = event.injectionInfo();
System.out.println("OnInjection input class: " + inputType.getSimpleName());
System.out.println("OnInjection output class: " + outputObject.getClass().getSimpleName());
System.out.println("OnInjection genericTypes: " + genericTypes.length);
System.out.println("OnInjection metadata: " + injectonMetadata.toString());
return outputObject;
}
}
public class _05_Generic_Types {
public static void main(String[] args) {
var container = Dependance.newContainer()
.registerTransient(ExampleGenericsTypes.class)
.configure(configuration ->
{
/*
* Since java is not storing information about generic type after compilation
* we can not assign class with generic type to variable, so Repository<MyGenericType>.class is not possible
* Therefor all cases with generic types (besides lists) must be handled manually in onInjection event
*/
configuration.onInjection(injection ->
{
if (!injection.input().isAssignableFrom(Repository.class)) {
return injection.output();
}
var genericParameter = injection.inputGenericParameters()[0];
if (genericParameter.equals(OnlineShop.class)) {
return new Repository<OnlineShop>();
}
if (genericParameter.equals(LocalShop.class)) {
return new Repository<LocalShop>();
}
return new Repository();
});
})
.build();
//first parameter is class, second one is its generic parameter
var exampleGenericsTypes = container.find(ExampleGenericsTypes.class);
Assert.assertNotNull(exampleGenericsTypes);
Assert.assertNotNull(exampleGenericsTypes.getLocalShopRepository());
Assert.assertNotNull(exampleGenericsTypes.getOnlineShopRepository());
}
public static class ExampleGenericsTypes {
@Getter
private Repository<OnlineShop> onlineShopRepository;
@Getter
private Repository<LocalShop> localShopRepository;
public ExampleGenericsTypes(Repository<OnlineShop> onlineShopRepository,
Repository<LocalShop> localShopRepository) {
this.onlineShopRepository = onlineShopRepository;
this.localShopRepository = localShopRepository;
}
}
}
public class _06_AutoScan {
/**
* To avoid boring manually registering Types to container
* use `scan` method that is looking for all Classes and Methods
* with annotation @Injection and register it automatically
*/
public static void main(String[] args) {
/*
* package under which code will be scanned should be scanned
* scanner is looking for all Method and Classes that are having @Injection annotation
*/
Class<?> rootClass = _06_AutoScan.class;
DependanceContainer container = Dependance.newContainer()
.scan(rootClass)
.scan(options ->
{
options.setRootPackage(rootClass);
options.excludeClass("org.example.ExampleClass");
options.excludePackage(String.class.getPackageName());
})
.scan(rootClass, (scannedClasses, containerBuilder) ->
{
System.out.println("Hello from scanner those are found classes");
for (var clazz : scannedClasses)
{
System.out.println(clazz.getSimpleName());
}
System.out.println("============================================");
})
.build();
Config config = container.find(Config.class);
ExampleClass exampleClass = container.find(ExampleClass.class);
OnlineShop onlineShop = container.find(OnlineShop.class);
ExampleScannClass exampleScannClass = container.find(ExampleScannClass.class);
Assert.assertNotNull(config);
Assert.assertNotNull(exampleClass);
Assert.assertNotNull(onlineShop);
Assert.assertNotNull(exampleScannClass);
}
/**
* This is equivalent of
* <p>
* container.registerTransient(OnlineShop.class,container1 ->
* {
* System.out.println("Hello from the online shop factory");
* return new OnlineShop();
* })
*/
@Injection(lifeTime = LifeTime.TRANSIENT)
private static OnlineShop onlineShopFactory() {
System.out.println("Hello from the online shop factory");
return new OnlineShop();
}
/**
* This is equivalent of
* <p>
* container.registerSingleton(ExampleScannClass.class);
*/
@Injection(lifeTime = LifeTime.SINGLETON)
public static class ExampleScannClass {
public ExampleScannClass() {
System.out.println("Hello world!");
}
}
}
public class _07_Overriding {
public static void main(String[] args) {
DependanceContainer container = Dependance.newContainer()
.registerTransient(Shop.class, OnlineShop.class)
.registerTransient(Shop.class, OfflineShop.class)
/**
* By again declaring Shop but with different implementation (OnlineShop)
* We are telling container to Override (OfflineShop) and always returns (OnlineShop)
*/
.build();
Shop shop = container.find(Shop.class);
Assert.assertEquals(OfflineShop.class, shop.getClass());
System.out.println("shop object is instance of OfflineShop Class");
}
}
public class _08_ManyConstructors
{
/**
* By the default the first constructor is always targeted for injecting parameters
* However, sometimes class can have more than one constructor, or we want to use
* specific one.
*
* To do that use @Inject annotation over wanted constructor
*
*/
public static void main(String[] args) {
DependanceContainer container = Dependance.newContainer()
.registerTransient(ExampleClass.class)
.registerTransient(ManyConstructorsExample.class)
.build();
ManyConstructorsExample example = container.find(ManyConstructorsExample.class);
Assert.assertNotNull(example);
System.out.println("It works!");
}
public static class ManyConstructorsExample
{
public ManyConstructorsExample(String a, int b, boolean c)
{
}
@Inject
public ManyConstructorsExample(ExampleClass c)
{
System.out.println("Hello from constructor with ExampleClass parameter");
}
}
public static class ExampleClass
{
}
}
public class _09_Fields {
public static void main(String[] args) {
DependanceContainer container = Dependance.newContainer()
.registerTransient(_09_Fields.ExampleSerivce.class)
.registerTransient(_09_Fields.ExampleClass.class)
.build();
_09_Fields.ExampleSerivce example = container.find(_09_Fields.ExampleSerivce.class);
Assert.assertNotNull(example);
example.exampleClass.sayIt();
}
public static class ExampleSerivce {
@Inject
ExampleClass exampleClass;
}
public static class ExampleClass {
public void sayIt() {
System.out.println("Hello world!");
}
}
}
public class _10_Methods
{
public static void main(String[] args) {
DependanceContainer container = Dependance.newContainer()
.registerTransient(_10_Methods.ExampleSerivce.class)
.registerTransient(_10_Methods.ExampleClass.class)
.build();
_10_Methods.ExampleClass example = container.find(_10_Methods.ExampleClass.class);
Assert.assertNotNull(example);
example.sayIt();
}
public static class ExampleSerivce
{
@Injection
_09_Fields.ExampleClass exampleClassProvider()
{
return new _09_Fields.ExampleClass();
}
}
public static class ExampleClass {
public void sayIt() {
System.out.println("Hello world!");
}
}
}
public class _11_ResolveParameters {
public static void main(String[] args) throws Exception {
DependanceContainer container = Dependance.newContainer()
.registerTransient(_11_ResolveParameters.ExampleWithGenerics.class)
.registerTransient(_11_ResolveParameters.ExampleClass.class)
.configure(config ->
{
config.onInjection(onInjectionEvent ->
{
if (!onInjectionEvent.input().equals(ExampleWithGenerics.class)) {
return onInjectionEvent.output();
}
var geneicsTyles = onInjectionEvent.inputGenericParameters()[0];
if (!String.class.equals(geneicsTyles)) {
return onInjectionEvent.output();
}
return new ExampleWithGenerics<String>();
});
})
.build();
var method = _11_ResolveParameters.class.getDeclaredMethod(
"sayHello",
_11_ResolveParameters.ExampleWithGenerics.class,
_11_ResolveParameters.ExampleClass.class);
var parameters = container.resolveParameters(method);
method.invoke(null, parameters);
}
public static void sayHello(_11_ResolveParameters.ExampleWithGenerics<String> exampleService,
_11_ResolveParameters.ExampleClass exampleClass) {
System.out.println("Hello world");
}
public static class ExampleWithGenerics<T> {
}
public static class ExampleClass {
}
}