The problem I've always had with DI frameworks, be it Spring or Guice, is they create this nasty dependency tree. If you don't want to use GlobalApplicationContext.getBean() or Injector.getInstance() then you'll need to inject all your dependencies at the root. It annoys the crap out of me, but I suppose there's just no way around it...
This is dealt with in Qi4j by allowing objects to be instantiated without having direct access to all the dependencies needed by the object. If you have a class Foo that requires a Bar service, like this:
then you can instantiate it wherever you want by simply doing:
public class Foo
@Service Bar bar;
Foo foo = objectBuilderFactory.newObject(Foo.class);which will instantiate Foo and provide all the dependencies it needs, without the caller having to provide them explicitly.
It is also possible to use service locators in Qi4j, like this:
public class Foo
@Structure ServiceFinder finder;
public void doStuff()
ServiceReference<Bar> barRef = finder.findService(Bar.class);
Bar bar = barRef.get();
Another issue pointed out is the ability to say "realize an object of type X, but I don't know what concrete type it should be". This is so that application code only has to be aware of the base class or interface X, which in runtime can be bound to XImpl or XMock or some other implementation. This is supported in Qi4j since all classes that are to be instantiated must be registered upfront. You can therefore register an implementation like this in the Assembler:
public void assemble(ModuleAssembly module)
module.addObjects(XImpl.class); // XImpl implements X interface
and instantiate it with:
X x = objectBuilderFactory.newObject(X.class);Based on what you registered the appropriate implementation will be chosen. In the above case XImpl will be instantiated, and if you instead registered XMock which also implements X, then that would be instantiated. If many possibilities exist, an AmbiguousTypeException will be thrown to avoid non-deterministic behaviour.
That should take care of most of the issues pointed out in the post I think. Also note that all of the above mechanism considers visibility rules of the Layers and Modules in the Application, which can be used to further control what types are "seen" by application code in various parts of your app.