fork(4) download
  1. import java.util.*;
  2. import java.lang.*;
  3. import java.io.*;
  4. import java.lang.annotation.*;
  5. import java.lang.reflect.*;
  6.  
  7. // created for https://p...content-available-to-author-only...e.com/questions/232229/understanding-dependency-injection/232239#232239
  8. // Copyright 2014 by "amon"
  9. // Licensed under CC-BY-SA
  10. // https://c...content-available-to-author-only...s.org/licenses/by-sa/4.0/
  11.  
  12. class Main {
  13.  
  14. public static void main (String[] args){
  15. try {
  16. // set up some dependencies
  17. Dizzy.DependencyManager dm = new Dizzy.DependencyManager();
  18. dm.set(Foo.class, Foo.class)
  19. .set(Bar.class, Bar.Mocking.class)
  20. .set(Qux.class, Qux.Mocking.class);
  21.  
  22. // create a Foo instance with all dependencies resolved
  23. dm.make(Foo.class).run();
  24.  
  25. // change the configuration
  26. dm.set(Bar.class, Bar.Production.class)
  27. .set(Qux.class, Qux.Production.class);
  28.  
  29. // make another instance with different implementations
  30. dm.make(Foo.class).run();
  31. }
  32. catch(Exception e) {
  33. e.printStackTrace(System.out);
  34. }
  35. }
  36.  
  37. interface Bar {
  38. public void bar();
  39.  
  40. class Production implements Bar {
  41. public void bar() {
  42. System.out.println("Bar.Production.bar called");
  43. }
  44. }
  45.  
  46. class Mocking implements Bar {
  47. public void bar() {
  48. System.out.println("Bar.Mocking.bar called");
  49. }
  50. }
  51. }
  52.  
  53. interface Qux {
  54. public void qux();
  55.  
  56. class Production implements Qux {
  57. public void qux() {
  58. System.out.println("Qux.Production.qux called");
  59. }
  60. }
  61.  
  62. class Mocking implements Qux {
  63. public void qux() {
  64. System.out.println("Qux.Mocking.qux called");
  65. }
  66. }
  67. }
  68.  
  69. static class SuperFoo {
  70. @Dizzy.Dependency(Bar.class)
  71. protected Bar bar;
  72. }
  73.  
  74. static class Foo extends SuperFoo {
  75. @Dizzy.Dependency(Bar.class)
  76. final private Bar bar = null; // final fields work if we init them to bogus
  77.  
  78. @Dizzy.Dependency(Qux.class)
  79. private Qux qux;
  80.  
  81. public void run() {
  82. bar.bar();
  83. qux.qux();
  84. super.bar.bar();
  85. }
  86. }
  87.  
  88. /**
  89. * Dizzy is a small dependency injection framework.
  90. */
  91. static class Dizzy {
  92. /**
  93. * Marks instance fields which should be injected
  94. */
  95. @Target(value=ElementType.FIELD)
  96. @Retention(value=RetentionPolicy.RUNTIME)
  97. public @interface Dependency {
  98. Class value();
  99. }
  100.  
  101. static class DependencyManager {
  102. private Map<Class<?>, Class<?>> dependencies = new HashMap<>();
  103.  
  104. /**
  105. * Sets a dependency
  106. */
  107. public <T> DependencyManager set(
  108. Class<T> dependency,
  109. Class<? extends T> implementation)
  110. {
  111. dependencies.put(dependency, implementation);
  112. return this;
  113. }
  114.  
  115. /**
  116. * Fetches the currently set dependency for some instance
  117. */
  118. public <T> Class<T> get(Class<T> dependency) throws Dizzy.Exception {
  119. Class<T> implementation = (Class<T>) dependencies.get(dependency);
  120. if (implementation == null) {
  121. throw new Dizzy.Exception(new NullPointerException());
  122. }
  123. return implementation;
  124. }
  125.  
  126. /**
  127. * Creates a new instance of the required type and automatically initializes any fields marked as a "@Dizzy.Dependency"
  128. */
  129. public <T> T make(Class<T> dependency) throws Dizzy.Exception {
  130. Class<T> implementation = this.get(dependency);
  131. try {
  132. Constructor<T> ctor = implementation.getDeclaredConstructor();
  133. T instance = ctor.newInstance();
  134. this.initializeFields(implementation, instance);
  135. return instance;
  136. }
  137. {
  138. throw new Dizzy.Exception(e);
  139. }
  140. }
  141.  
  142. private <T> void initializeFields(
  143. Class<T> clazz,
  144. T instance)
  145. throws Dizzy.Exception
  146. {
  147. for (Class<? super T> c = clazz; c != null; c = c.getSuperclass()) {
  148. for (Field f : c.getDeclaredFields()) {
  149. if (!f.isAnnotationPresent(Dizzy.Dependency.class)) {
  150. continue;
  151. }
  152. try {
  153. Dizzy.Dependency dep = f.getAnnotation(Dizzy.Dependency.class);
  154. f.setAccessible(true);
  155. f.set(instance, this.make(dep.value()));
  156. }
  157. | Exception e)
  158. {
  159. throw new Dizzy.Exception(e);
  160. }
  161. }
  162. }
  163. }
  164. }
  165.  
  166. /**
  167. * A wrapper exception type
  168. */
  169. static class Exception extends java.lang.Exception {
  170. public Exception(java.lang.Exception e) {
  171. super(e);
  172. }
  173. }
  174. }
  175.  
  176. }
Success #stdin #stdout 0.1s 380352KB
stdin
Standard input is empty
stdout
Bar.Mocking.bar called
Qux.Mocking.qux called
Bar.Mocking.bar called
Bar.Production.bar called
Qux.Production.qux called
Bar.Production.bar called