View on GitHub

my-oc-container

This project is supposed to be a very lightweight, easy to use and independent IOC container for small to medium scale projects.

Build Status License

About

MyOcContainer (My IOC Container) is supposed to be a very simple and lightweight IOC container with mandatory features for a not very large project.

How to use

After importing the library into your project, the client code will use an instance of the class Resolver for most of the Configurations and Resolvings.

Configuration:

you can register all your in use classes by calling one of the overloads of the method register(.).

Currently it does ‘constructor injection’s only. You can register different implementations for each class by providing a tag parameter for register method. a tag should be a string conforming to the convention of c-like languages variable names except it can have ‘-‘ and ‘.’ in it.

It also supports a fluent-like syntax. to register classes with you preference via a fluent syntax, you can call the register() method without any arguments. then you can set any of the properties using provided functions:

*) bind(.) sets the class you want to choose an implementation for
*) to(.)   sets the class that would be the implementation
*) taggedAs(.)  will set a tag for this registration
*) livesAsA(.) will take a LifetimeType argument to set the type of lifetime you want to use.
*) withBuilder(.) will register a builder to create the object.

You can perform a small life time management for objects by providing a LifetimeType parameter to the register method. LifetimeType currently can be Transient (default) or Singleton. all singleton objects will be stored inside the Resolver object. and resolver itself is not a singleton so you can have multiple scopes in your application.

You can call withBuilder(.) method, passing it an implementation of Builder interface. you can also call this method by an inline implementation (anonymous class) of the Builder interface. the main difference is that with the dependency created using first approuch can be saved in a config file, but by using an anonymous class (or a lambda expression), it would not be possible, and the dependency will be ommited when you save configurations.

You can create an installer calss by implementing the Installer interface. such a class will contain a configure(Registerer myoc) method where you can put all your configuration lines. the Registerer argument of the configure(.) method provides the fluent syntax registration methods.

Using the Resolver to resolve dependencies

to create an object, you should call on of the resolve methods from Resolver object. different resolve methods will resolve the given type with different strategies. for example, resolveByTagOnly will resolve the class only if it’s pre-registered with the given tag. It’s also possible to save resolver configurations to a file or load them from a file.

To load configurations from a pre-saved file, You can create the Resolver object using its constructor which takes a string filePath parameter. the filePath would be the path to the configuration file. configuration file is a white-space separated text file. each line will register one class. classes which are registered with no tags, will have the default tag: “Default”.

For saving the configurations, you can call the static method save(.) from class ConfigurationFile. it takes a filePath argument and another argument of type DependancyDictionary. a DependancyDictionary object can be created and populated in code or you can get the object from an already configured resolver through its getRegisteredDependancies() method.

There is a resolveAll(.) method in Resolver class wich will return an array of objects. the array contains one resolved object for each dependency registered for a given class.

Example Code

consider we have the class A. which takes an argument of type b and another argument of type c in its constructor. where b and c are your abstractions. then you might have implementations B1 and B2 for b and C1 and C2 for c. a simple demo code would be like this:


//Creating a resolver
Resolver resolver = new Resolver();

// Configuring your resolver - normal argument call

resolver.register(A.class, A.class);
resolver.register(A.class, A.class,"fancyOne",LifetimeType.Singleton);
resolver.register(b.class, B1.class);               // as default
resolver.register(b.class, B2.class,"fancyOne");    // fancy implementation
resolver.register(c.class, C1.class);               // default
resolver.register(c.class, C2.class,"fancyOne");    // fancy

// Configuring your resolver - fluent like syntax

resolver.register().bind(A.class).to(A.class);
resolver.register().bind(A.class).to(A.class).taggedAs("fancyOne").livesAsA(LifetimeType.Singleton);
resolver.register().bind(b.class).to(B1.class);  
resolver.register().bind(b.class).to(B2.class).taggedAs("fancyOne");  
resolver.register().bind(c.class).to(C1.class);  
resolver.register().bind(b.class).to(C2.class).taggedAs("fancyOne");  

// Using resolver


// this will make a transient A object with default implementation.

A aDefaultImplementation = resolver.resolve(A.class);

// this will make an A object with fancy implementation.
// this object will be a singleton.

A aFancyImplementation = resolver.resolve(A.class,"fancyOne"); 


More Examples

If you downloaded the code, you can take a look at test codes in the project in the package test.myoccontainer.*.

Good luck

Mani

Contact:

acidmanic.moayedi@gmail.com