Skip to content

Instantly share code, notes, and snippets.

@joecheatham
Last active August 14, 2018 07:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joecheatham/74d1c14eee6bcedff35fb476a0c847d3 to your computer and use it in GitHub Desktop.
Save joecheatham/74d1c14eee6bcedff35fb476a0c847d3 to your computer and use it in GitHub Desktop.
simple and inefficient java "dependency injection" utility
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;
public class SimpleDI {
private static final SimpleDI INSTANCE = new SimpleDI();
private final Map <Class<?>, Object> classMap = new HashMap <>();
public static void init(Object...objects) {
for (Object obj: objects) {
insertAll(obj.getClass(), obj);
}
}
public static <T> T inject(Class <T> className) {
try {
if (!INSTANCE.classMap.containsKey(className)) {
Constructor<?> constructor = className.getConstructors()[0];
Class<?> [] args = constructor.getParameterTypes();
Object[] instances = new Object[args.length];
for (int i = 0; i < args.length; i++) {
if (!INSTANCE.classMap.containsKey(args[i])) {
inject(args[i]);
}
instances[i] = INSTANCE.classMap.get(args[i]);
}
T instance = (T) constructor.newInstance(instances);
insertAll(className, instance);
}
return (T) INSTANCE.classMap.get(className);
} catch (Exception e) {
return null;
}
}
private static void insertAll(Class <?> clazz, Object obj) {
Class <?> superClass = clazz.getSuperclass();
if (superClass != null) {
insertAll(superClass, obj);
}
for (Class <?> interf : clazz.getInterfaces()) {
INSTANCE.classMap.put(interf, obj);
}
INSTANCE.classMap.put(clazz, obj);
}
}
@joecheatham
Copy link
Author

joecheatham commented Aug 14, 2018

usage example with POJOs A, B

public class A {
  private B b;
  public A(B b) {
    this.b = b;
  }

  public String toString() {
    return b.toString();
  }
}
public class B {
  public B() {}

  public String toString {
    return "hello, B";
  }
}
public class Main {
  
  A aMethodPojo = inject(A.class);

  public void someMainMethod() {
    A aLocalPojo = inject(A.class);
    System.out.println(aMethodPojo.toString());
    System.out.println(aLocalPojo.toString());
  }
}

calling this main method would print "hello, B" twice.

you can also init the util with any classes you wish, a quick Android example:

public class SomeActivity {
  public void onCreate(...) {
    SimpleDI.init(this);
  }
}

you now have access to any of the implemented interfaces or superclasses of SomeActivity, including Context. this can be seen in the following extended example:

public class Toaster {
  private Context context;
  public Toaster(Context c) {
    context = c;
  }

  public void makeToast() {
    Toast.makeText(context, "some toast", Toast.LENGTH_SHORT).show();
  }
}
public class SomeActivity {
  public void onCreate(...) {
    SimpleDI.init(this);

    Toaster toaster = inject(Toaster.class);
    toaster.makeToast();
  }
}

even though the util was never initialized with a Context, it found the superclass on the SomeActivity instance to inject as a dependency to Toaster. so when makeToast() is called, the toast with text "some toast" is displayed.

this util only supports singleton injection, no additional scopes are planned

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment