import java.util.*;
import java.lang.*;
import java.io.*;
import java.lang.annotation.*;
import java.lang.reflect.*;
// created for https://p...content-available-to-author-only...e.com/questions/232229/understanding-dependency-injection/232239#232239
// Copyright 2014 by "amon"
// Licensed under CC-BY-SA
// https://c...content-available-to-author-only...s.org/licenses/by-sa/4.0/
class Main {
public static void main
(String[] args
){ try {
// set up some dependencies
Dizzy.DependencyManager dm = new Dizzy.DependencyManager();
dm.set(Foo.class, Foo.class)
.set(Bar.class, Bar.Mocking.class)
.set(Qux.class, Qux.Mocking.class);
// create a Foo instance with all dependencies resolved
dm.make(Foo.class).run();
// change the configuration
dm.set(Bar.class, Bar.Production.class)
.set(Qux.class, Qux.Production.class);
// make another instance with different implementations
dm.make(Foo.class).run();
}
e.
printStackTrace(System.
out); }
}
interface Bar {
public void bar();
class Production implements Bar {
public void bar() {
System.
out.
println("Bar.Production.bar called"); }
}
class Mocking implements Bar {
public void bar() {
System.
out.
println("Bar.Mocking.bar called"); }
}
}
interface Qux {
public void qux();
class Production implements Qux {
public void qux() {
System.
out.
println("Qux.Production.qux called"); }
}
class Mocking implements Qux {
public void qux() {
System.
out.
println("Qux.Mocking.qux called"); }
}
}
static class SuperFoo {
@Dizzy.Dependency(Bar.class)
protected Bar bar;
}
static class Foo extends SuperFoo {
@Dizzy.Dependency(Bar.class)
final private Bar bar = null; // final fields work if we init them to bogus
@Dizzy.Dependency(Qux.class)
private Qux qux;
public void run() {
bar.bar();
qux.qux();
super.bar.bar();
}
}
/**
* Dizzy is a small dependency injection framework.
*/
static class Dizzy {
/**
* Marks instance fields which should be injected
*/
@Target(value=ElementType.FIELD)
@Retention(value=RetentionPolicy.RUNTIME)
public @interface Dependency {
Class value();
}
static class DependencyManager {
private Map<Class<?>, Class<?>> dependencies = new HashMap<>();
/**
* Sets a dependency
*/
public <T> DependencyManager set(
Class<T> dependency,
Class<? extends T> implementation)
{
dependencies.put(dependency, implementation);
return this;
}
/**
* Fetches the currently set dependency for some instance
*/
public <T
> Class
<T
> get
(Class
<T
> dependency
) throws Dizzy.
Exception { Class<T> implementation = (Class<T>) dependencies.get(dependency);
if (implementation == null) {
}
return implementation;
}
/**
* Creates a new instance of the required type and automatically initializes any fields marked as a "@Dizzy.Dependency"
*/
public <T
> T make
(Class
<T
> dependency
) throws Dizzy.
Exception { Class<T> implementation = this.get(dependency);
try {
Constructor<T> ctor = implementation.getDeclaredConstructor();
T instance = ctor.newInstance();
this.initializeFields(implementation, instance);
return instance;
}
{
}
}
private <T> void initializeFields(
Class<T> clazz,
T instance)
{
for (Class<? super T> c = clazz; c != null; c = c.getSuperclass()) {
for (Field f
: c.
getDeclaredFields()) { if (!f.isAnnotationPresent(Dizzy.Dependency.class)) {
continue;
}
try {
Dizzy.Dependency dep = f.getAnnotation(Dizzy.Dependency.class);
f.setAccessible(true);
f.set(instance, this.make(dep.value()));
}
{
}
}
}
}
}
/**
* A wrapper exception type
*/
super(e);
}
}
}
}