Java dependency injection through code.
purejin
is a Java dependency injection library that only uses vanilla Java code to define a container context using a fluent binding API.
It does not use annotations for injection guidance, avoids proxies, bytecode manipulation/interception or any other technique based on conventions that have to be learned.
It only uses vanilla Java code and reflection to build an applications object graph as if it was connected manually based on the bindings made using its fluent API.
Purejin is pure. It does not depend on other languages, other Java libraries or mechanisms that work by convention. It’s just Java with reflection (no unsafe). This has the added benefit that it can be debugged and understood like a standard Java application.
Purejin’s programming style is inspired by pure functional style: Users declare a set of declarative statements about the (container) world. These statements are transformed to a fixed and final container model. Alongside the immutable model there is a pool of managed instances. Calling resolution functions on the container is like a computation on its model state that might create new managed instances in the pool as a “side-effect”. This is easy to reason about and allows for state validation at the end of bootstrapping a container.
Its goal is to organise and modularise what otherwise would be manual wiring without imposing restrictions on the application developer.
The detailed documentation provided earlier – as is so often the case – got outdated when the code evolved. I decided not to explain in words what the code can say so much better.
The following is not much but it will be accurate. If something is not covered ask me.
Dependency management through code. No XML. No annotations. No code dependencies in the wrong direction. Application code is written as if there is no DI library.
This is the goal: wiring up the application had become so simple that no sophisticated library is needed to aid it. Purejin will make sophisticated wiring easier until it is no longer needed and gracefully disappears as simplicity emerges. It is particularly useful for highly configurable and/or modular applications or for application developers that need a small simple tool to make the task of wiring easier.
Existing libraries and frameworks felt like double-edged swords that way too often got in the way of the application developer instead of making their lives easier.
The major frameworks have the tendency to bend the application development into their style which leads to applications becoming highly dependent on the framework. The purejin library is intended as a substitute that in the end gets rid of itself. Confused? It’s just saying: Small is beautiful. We might not need a library for that, but if we decide to use one it should support us, not get in our way or dictate how to code.
If you have already decided to use a container but dislike the way popular frameworks drive you in certain directions and limit you in others purejin is worth a try.
It’s a small, debuggable, straightforward and standalone library that makes common things easy and uncommon ones easy to add or change.
It avoids anything not refactoring-safe, confusing, “invisible” or otherwise hard to maintain like XML, annotations, aspects, bytecode rewirting, classloader magic, code generation, special build tools, etcetera.
It really is just plain old boring code. However, it makes a few strong decisions to keep dependency injection sane. It would be wise to not fight them but ask why and learn how to stay out of trouble especially with large, complex applications.
List<A>
!= List<B>
etcetera)if
s everywhere (built-in concepts)Declare some bindings in a module using a fluent API:
class RobotLegsProblem extends BinderModule {
@Override
protected void declare() {
construct(Robot.class);
//...
bind("left", Leg.class).toConstructor();
bind("right", Leg.class).toConstructor();
injectingInto("left", Leg.class)
.bind(Foot.class).to("left", Foot.class);
injectingInto("right", Leg.class)
.bind(Foot.class).to("right", Foot.class);
}
}
Bootstrap the container:
Injector injector = Bootstrap.injector(RobotLegsProblem.class);
Resolve the root instance:
Robot robot = injector.resolve(dependency(Robot.class));
(or any other instance for that matter)
The tests for the binding API illustrate what can be done and how to do it. It’s all ordinary vanilla code. Read it.
Not very handy but it doesn’t lie. Keep in mind that purejin is a library that is designed as a toolbox. You pick what you need and adjust it to your case. This means there is no such thing as THE way to do things. There are often many ways to reach a goal each having their own pros and cons. The more concepts you know the more possibilities you will see.
There are many more examples and many more concepts. Have a look at other tests in the same folder. Otherwise just ask me for help.
AutoCloseable
s