DI:依存性注入ライブラリを自分で作ろう

 DI:依存性注入ライブラリを自分で作ろう

DI は便利だけど、@Injectはどこに付けたらいい?どの場合に付けたらいい?@Singletonは?
それから、うまく行かなかった場合は調査するの大変?
Dependency Injection はブラックボックスにみえるかもしれないけどやっている事はシンプル。
ステップ・バイ・ステップ、依存性注入ライブラリをどうやって作るかをみましょう。

05162bc961c3654218bf1839974a4f35?s=128

Benoît Quenaudon

August 02, 2017
Tweet

Transcript

  1. DI:依存性注入ライブラリを 自分で作ろう Benoît Quenaudon @oldergod

  2. public class VisitHandler { private final Counter counter; private final

    Logger logger; public VisitHandler(Counter counter, Logger logger) { this.counter = counter; this.logger = logger; } public void visit() { counter.increment(); logger.log("Visits increased: " + counter.getCount()); } }
  3. public class Counter { private int count; void increment() {

    count++; } int getCount() { return count; } } public class Logger { private final PrintStream printStream; public Logger(PrintStream printStream) { this.printStream = printStream; } public void log(String log) { printStream.println(log); } }
  4. public static void main(String... args) { Counter counter = new

    Counter(); PrintStream printStream = System.out; Logger logger = new Logger(printStream); VisitHandler visitHandler = new VisitHandler(counter, logger); visitHandler.visit(); }
  5. public static void main(String... args) { Counter counter = new

    Counter(); PrintStream printStream = System.out; Logger logger = new Logger(printStream); VisitHandler visitHandler = new VisitHandler(counter, logger); visitHandler.visit(); }
  6. public static void main(String... args) { Counter counter = new

    Counter(); PrintStream printStream = System.out; Logger logger = new Logger(printStream); VisitHandler visitHandler = new VisitHandler(counter, logger); visitHandler.visit(); }
  7. public static void main(String... args) { Counter counter = new

    Counter(); PrintStream printStream = System.out; Logger logger = new Logger(printStream); VisitHandler visitHandler = new VisitHandler(counter, logger); visitHandler.visit(); }
  8. public static void main(String... args) { Counter counter = new

    Counter(); PrintStream printStream = System.out; Logger logger = new Logger(printStream); VisitHandler visitHandler = new VisitHandler(counter, logger); visitHandler.visit(); }
  9. public static void main(String... args) { Counter counter = new

    Counter(); PrintStream printStream = System.out; Logger logger = new Logger(printStream); VisitHandler visitHandler = new VisitHandler(counter, logger); visitHandler.visit(); }
  10. public static void main(String... args) { ObjectGraph objectGraph = buildObjectGraph();

    VisitHandler visitHandler = objectGraph.get(VisitHandler.class); visitHandler.visit(); }
  11. public class ObjectGraph { public <T> T get(Class<T> key) {

    throw new UnsupportedOperationException("Not implemented"); } }
  12. public interface Factory<T> { T get(Linker linker); } public class

    Linker { private final Map<Class<?>, Factory<?>> factories = new HashMap<>(); public <T> void install(Class<T> key, Factory<T> factory) { factories.put(key, factory); } public <T> Factory<T> factoryFor(Class<T> key) { return (Factory<T>) factories.get(key); } }
  13. public interface Factory<T> { T get(Linker linker); } public class

    Linker { private final Map<Class<?>, Factory<?>> factories = new HashMap<>(); public <T> void install(Class<T> key, Factory<T> factory) { factories.put(key, factory); } public <T> Factory<T> factoryFor(Class<T> key) { return (Factory<T>) factories.get(key); } }
  14. public interface Factory<T> { T get(Linker linker); } public class

    Linker { private final Map<Class<?>, Factory<?>> factories = new HashMap<>(); public <T> void install(Class<T> key, Factory<T> factory) { factories.put(key, factory); } public <T> Factory<T> factoryFor(Class<T> key) { return (Factory<T>) factories.get(key); } }
  15. public interface Factory<T> { T get(Linker linker); } public class

    Linker { private final Map<Class<?>, Factory<?>> factories = new HashMap<>(); public <T> void install(Class<T> key, Factory<T> factory) { factories.put(key, factory); } public <T> Factory<T> factoryFor(Class<T> key) { return (Factory<T>) factories.get(key); } }
  16. public interface Factory<T> { T get(Linker linker); } public class

    Linker { private final Map<Class<?>, Factory<?>> factories = new HashMap<>(); public <T> void install(Class<T> key, Factory<T> factory) { factories.put(key, factory); } public <T> Factory<T> factoryFor(Class<T> key) { return (Factory<T>) factories.get(key); } }
  17. public class ObjectGraph { private final Linker linker; public ObjectGraph(Linker

    linker) { this.linker = linker; } public <T> T get(Class<T> key) { Factory<T> factory = linker.factoryFor(key); return factory.get(linker); } }
  18. public class ObjectGraph { private final Linker linker; public ObjectGraph(Linker

    linker) { this.linker = linker; } public <T> T get(Class<T> key) { Factory<T> factory = linker.factoryFor(key); return factory.get(linker); } }
  19. public static void main(String... args) { ObjectGraph objectGraph = buildObjectGraph();

    VisitHandler visitHandler = objectGraph.get(VisitHandler.class); visitHandler.visit(); }
  20. private static ObjectGraph buildObjectGraph() { Linker linker = new Linker();

    installFactories(linker); return new ObjectGraph(linker); }
  21. private static void installFactories(Linker linker) { linker.install(VisitHandler.class, ...); }

  22. private static void installFactories(Linker linker) { linker.install(VisitHandler.class, new Factory<VisitHandler>() {

    @Override public VisitHandler get(Linker linker) { Factory<Counter> counterFactory = linker.factoryFor(Counter.class); Factory<Logger> loggerFactory = linker.factoryFor(Logger.class); Counter counter = counterFactory.get(linker); Logger logger = loggerFactory.get(linker); return new VisitHandler(counter, logger); } }); }
  23. private static void installFactories(Linker linker) { linker.install(VisitHandler.class, new Factory<VisitHandler>() {

    @Override public VisitHandler get(Linker linker) { Factory<Counter> counterFactory = linker.factoryFor(Counter.class); Factory<Logger> loggerFactory = linker.factoryFor(Logger.class); Counter counter = counterFactory.get(linker); Logger logger = loggerFactory.get(linker); return new VisitHandler(counter, logger); } }); }
  24. private static void installFactories(Linker linker) { linker.install(VisitHandler.class, new Factory<VisitHandler>() {

    @Override public VisitHandler get(Linker linker) { Factory<Counter> counterFactory = linker.factoryFor(Counter.class); Factory<Logger> loggerFactory = linker.factoryFor(Logger.class); Counter counter = counterFactory.get(linker); Logger logger = loggerFactory.get(linker); return new VisitHandler(counter, logger); } }); }
  25. private static void installFactories(Linker linker) { linker.install(VisitHandler.class, new Factory<VisitHandler>() {

    @Override public VisitHandler get(Linker linker) { Factory<Counter> counterFactory = linker.factoryFor(Counter.class); Factory<Logger> loggerFactory = linker.factoryFor(Logger.class); Counter counter = counterFactory.get(linker); Logger logger = loggerFactory.get(linker); return new VisitHandler(counter, logger); } }); }
  26. private static void installFactories(Linker linker) { linker.install(VisitHandler.class, new Factory<VisitHandler>() {

    @Override public VisitHandler get(Linker linker) { Factory<Counter> counterFactory = linker.factoryFor(Counter.class); Factory<Logger> loggerFactory = linker.factoryFor(Logger.class); Counter counter = counterFactory.get(linker); Logger logger = loggerFactory.get(linker); return new VisitHandler(counter, logger); } }); linker.install(Logger.class, new Factory<Logger>() { @Override public Logger get(Linker linker) { Factory<PrintStream> printStreamFactory = linker.factoryFor(PrintStream.class); PrintStream printStream = printStreamFactory.get(linker); return new Logger(printStreamFactory.get(linker)); } }); linker.install(PrintStream.class, new Factory<PrintStream>() {
  27. Factory<Logger> loggerFactory = linker.factoryFor(Logger.class); Counter counter = counterFactory.get(linker); Logger logger

    = loggerFactory.get(linker); return new VisitHandler(counter, logger); } }); linker.install(Logger.class, new Factory<Logger>() { @Override public Logger get(Linker linker) { Factory<PrintStream> printStreamFactory = linker.factoryFor(PrintStream.class); PrintStream printStream = printStreamFactory.get(linker); return new Logger(printStreamFactory.get(linker)); } }); linker.install(PrintStream.class, new Factory<PrintStream>() { @Override public PrintStream get(Linker linker) { return System.out; } }); linker.install(Counter.class, new Factory<Counter>() {
  28. Factory<Logger> loggerFactory = linker.factoryFor(Logger.class); Counter counter = counterFactory.get(linker); Logger logger

    = loggerFactory.get(linker); return new VisitHandler(counter, logger); } }); linker.install(Logger.class, new Factory<Logger>() { @Override public Logger get(Linker linker) { Factory<PrintStream> printStreamFactory = linker.factoryFor(PrintStream.class); PrintStream printStream = printStreamFactory.get(linker); return new Logger(printStreamFactory.get(linker)); } }); linker.install(PrintStream.class, new Factory<PrintStream>() { @Override public PrintStream get(Linker linker) { return System.out; } }); linker.install(Counter.class, new Factory<Counter>() {
  29. Factory<Logger> loggerFactory = linker.factoryFor(Logger.class); Counter counter = counterFactory.get(linker); Logger logger

    = loggerFactory.get(linker); return new VisitHandler(counter, logger); } }); linker.install(Logger.class, new Factory<Logger>() { @Override public Logger get(Linker linker) { Factory<PrintStream> printStreamFactory = linker.factoryFor(PrintStream.class); PrintStream printStream = printStreamFactory.get(linker); return new Logger(printStreamFactory.get(linker)); } }); linker.install(PrintStream.class, new Factory<PrintStream>() { @Override public PrintStream get(Linker linker) { return System.out; } }); linker.install(Counter.class, new Factory<Counter>() {
  30. linker.install(Logger.class, new Factory<Logger>() { @Override public Logger get(Linker linker) {

    Factory<PrintStream> printStreamFactory = linker.factoryFor(PrintStream.class); PrintStream printStream = printStreamFactory.get(linker); return new Logger(printStreamFactory.get(linker)); } }); linker.install(PrintStream.class, new Factory<PrintStream>() { @Override public PrintStream get(Linker linker) { return System.out; } }); linker.install(Counter.class, new Factory<Counter>() { @Override public Counter get(Linker linker) { return new Counter(); } }); }
  31. linker.install(Logger.class, new Factory<Logger>() { @Override public Logger get(Linker linker) {

    Factory<PrintStream> printStreamFactory = linker.factoryFor(PrintStream.class); PrintStream printStream = printStreamFactory.get(linker); return new Logger(printStreamFactory.get(linker)); } }); linker.install(PrintStream.class, ValueFactory.of(System.out)); linker.install(Counter.class, new Factory<Counter>() { @Override public Counter get(Linker linker) { return new Counter(); } }); }
  32. public class ValueFactory<T> implements Factory<T> { public static <T> Factory<T>

    of(T instance) { return new ValueFactory<>(instance); } private final T value; public ValueFactory(T value) { this.value = value; } @Override public T get(Linker linker) { return value; } }
  33. Logger logger = loggerFactory.get(linker); return new VisitHandler(counter, logger); } });

    linker.install(Logger.class, new Factory<Logger>() { @Override public Logger get(Linker linker) { Factory<PrintStream> printStreamFactory = linker.factoryFor(PrintStream.class); PrintStream printStream = printStreamFactory.get(linker); return new Logger(printStreamFactory.get(linker)); } }); linker.install(PrintStream.class, ValueFactory.of(System.out)); linker.install(Counter.class, new Factory<Counter>() { @Override public Counter get(Linker linker) { return new Counter(); } }); }
  34. Logger logger = loggerFactory.get(linker); return new VisitHandler(counter, logger); } });

    linker.install(Logger.class, new Factory<Logger>() { @Override public Logger get(Linker linker) { Factory<PrintStream> printStreamFactory = linker.factoryFor(PrintStream.class); PrintStream printStream = printStreamFactory.get(linker); return new Logger(printStreamFactory.get(linker)); } }); linker.install(PrintStream.class, ValueFactory.of(System.out)); linker.install(Counter.class, new Factory<Counter>() { @Override public Counter get(Linker linker) { return new Counter(); } }); }
  35. Logger logger = loggerFactory.get(linker); return new VisitHandler(counter, logger); } });

    linker.install(Logger.class, new Factory<Logger>() { @Override public Logger get(Linker linker) { Factory<PrintStream> printStreamFactory = linker.factoryFor(PrintStream.class); PrintStream printStream = printStreamFactory.get(linker); return new Logger(printStreamFactory.get(linker)); } }); linker.install(PrintStream.class, ValueFactory.of(System.out)); linker.install(Counter.class, SingletonFactory.of(new Factory<Counter>() { @Override public Counter get(Linker linker) { return new Counter(); } })); }
  36. public class SingletonFactory<T> implements Factory<T> { public static <T> Factory<T>

    of(Factory<T> factory) { return new SingletonFactory<>(factory); } private final Factory<T> factory; private T instance; public SingletonFactory(Factory<T> factory) { this.factory = factory; } @Override public T get(Linker linker) { if (instance == null) { instance = factory.get(linker); } return instance; } }
  37. public class SingletonFactory<T> implements Factory<T> { public static <T> Factory<T>

    of(Factory<T> factory) { return new SingletonFactory<>(factory); } private final Factory<T> factory; private T instance; public SingletonFactory(Factory<T> factory) { this.factory = factory; } @Override public T get(Linker linker) { if (instance == null) { instance = factory.get(linker); } return instance; } }
  38. Logger logger = loggerFactory.get(linker); return new VisitHandler(counter, logger); } });

    linker.install(Logger.class, new Factory<Logger>() { @Override public Logger get(Linker linker) { Factory<PrintStream> printStreamFactory = linker.factoryFor(PrintStream.class); PrintStream printStream = printStreamFactory.get(linker); return new Logger(printStreamFactory.get(linker)); } }); linker.install(PrintStream.class, ValueFactory.of(System.out)); linker.install(Counter.class, SingletonFactory.of(new Factory<Counter>() { @Override public Counter get(Linker linker) { return new Counter(); } })); }
  39. private static void installFactories(Linker linker) { linker.install(VisitHandler.class, new Factory<VisitHandler>() {

    @Override public VisitHandler get(Linker linker) { Factory<Counter> counterFactory = linker.factoryFor(Counter.class); Factory<Logger> loggerFactory = linker.factoryFor(Logger.class); Counter counter = counterFactory.get(linker); Logger logger = loggerFactory.get(linker); return new VisitHandler(counter, logger); } }); linker.install(Logger.class, new Factory<Logger>() { @Override public Logger get(Linker linker) { Factory<PrintStream> printStreamFactory = linker.factoryFor(PrintStream.class); PrintStream printStream = printStreamFactory.get(linker); return new Logger(printStream); } }); linker.install(PrintStream.class, ValueFactory.of(System.out)); linker.install(Counter.class, SingletonFactory.of(new Factory<Counter>() { @Override public Counter get(Linker linker) { return new Counter(); } })); }
  40. public class Linker { private final Map<Class<?>, Factory<?>> factories =

    new HashMap<>(); public <T> void install(Class<T> key, Factory<T> factory) { factories.put(key, factory); } public <T> Factory<T> factoryFor(Class<T> key) { System.out.println("Get factory for " + key); return (Factory<T>) factories.get(key); } }
  41. public class Linker { private final Map<Class<?>, Factory<?>> factories =

    new HashMap<>(); public <T> void install(Class<T> key, Factory<T> factory) { factories.put(key, factory); } public <T> Factory<T> factoryFor(Class<T> key) { System.out.println("Get factory for " + key); return (Factory<T>) factories.get(key); } }
  42. public static void main(String... args) { ObjectGraph objectGraph = buildObjectGraph();

    VisitHandler visitHandler = objectGraph.get(VisitHandler.class); visitHandler.visit(); } Get factory for class VisitHandler Get factory for class Counter Get factory for class Logger Get factory for class java.io.PrintStream Visits increased: 1
  43. So far • Instantiation and its order automated

  44. Good Job !

  45. public static void main(String... args) { ObjectGraph objectGraph = buildObjectGraph();

    VisitHandler visitHandler = objectGraph.get(VisitHandler.class); visitHandler.visit(); VisitHandler visitHandler2 = objectGraph.get(VisitHandler.class); visitHandler2.visit(); } Get factory for class VisitHandler Get factory for class Counter Get factory for class Logger Get factory for class java.io.PrintStream Visits increased: 1 Get factory for class VisitHandler Get factory for class Counter Get factory for class Logger Get factory for class java.io.PrintStream Visits increased: 2
  46. public interface Factory<T> { T get(Linker linker); }

  47. public abstract class Factory<T> { public void link(Linker linker) {

    } public abstract T get(); }
  48. public class Linker { private final Map<Class<?>, Factory<?>> factories =

    new HashMap<>(); public <T> void install(Class<T> key, Factory<T> factory) { factories.put(key, factory); } public <T> Factory<T> factoryFor(Class<T> key) { return (Factory<T>) factories.get(key); } }
  49. public class Linker { private final Map<Class<?>, Factory<?>> factories =

    new HashMap<>(); private final Map<Class<?>, Factory<?>> linkedFactories = new HashMap<>(); public <T> void install(Class<T> key, Factory<T> factory) { factories.put(key, factory); } public <T> Factory<T> factoryFor(Class<T> key) { Factory<?> factory = linkedFactories.get(key); if (factory == null) { factory = factories.get(key); factory.link(this); linkedFactories.put(key, factory); } return (Factory<T>) factory; } }
  50. public class Linker { private final Map<Class<?>, Factory<?>> factories =

    new HashMap<>(); private final Map<Class<?>, Factory<?>> linkedFactories = new HashMap<>(); public <T> void install(Class<T> key, Factory<T> factory) { factories.put(key, factory); } public <T> Factory<T> factoryFor(Class<T> key) { Factory<?> factory = linkedFactories.get(key); if (factory == null) { factory = factories.get(key); factory.link(this); linkedFactories.put(key, factory); } return (Factory<T>) factory; } }
  51. public class Linker { private final Map<Class<?>, Factory<?>> factories =

    new HashMap<>(); private final Map<Class<?>, Factory<?>> linkedFactories = new HashMap<>(); public <T> void install(Class<T> key, Factory<T> factory) { factories.put(key, factory); } public <T> Factory<T> factoryFor(Class<T> key) { Factory<?> factory = linkedFactories.get(key); if (factory == null) { factory = factories.get(key); factory.link(this); linkedFactories.put(key, factory); } return (Factory<T>) factory; } }
  52. public class Linker { private final Map<Class<?>, Factory<?>> factories =

    new HashMap<>(); private final Map<Class<?>, Factory<?>> linkedFactories = new HashMap<>(); public <T> void install(Class<T> key, Factory<T> factory) { factories.put(key, factory); } public <T> Factory<T> factoryFor(Class<T> key) { Factory<?> factory = linkedFactories.get(key); if (factory == null) { factory = factories.get(key); factory.link(this); linkedFactories.put(key, factory); } return (Factory<T>) factory; } }
  53. public class Linker { private final Map<Class<?>, Factory<?>> factories =

    new HashMap<>(); private final Map<Class<?>, Factory<?>> linkedFactories = new HashMap<>(); public <T> void install(Class<T> key, Factory<T> factory) { factories.put(key, factory); } public <T> Factory<T> factoryFor(Class<T> key) { Factory<?> factory = linkedFactories.get(key); if (factory == null) { factory = factories.get(key); factory.link(this); linkedFactories.put(key, factory); } return (Factory<T>) factory; } }
  54. public class Linker { private final Map<Class<?>, Factory<?>> factories =

    new HashMap<>(); private final Map<Class<?>, Factory<?>> linkedFactories = new HashMap<>(); public <T> void install(Class<T> key, Factory<T> factory) { factories.put(key, factory); } public <T> Factory<T> factoryFor(Class<T> key) { Factory<?> factory = linkedFactories.get(key); if (factory == null) { factory = factories.get(key); factory.link(this); linkedFactories.put(key, factory); } return (Factory<T>) factory; } }
  55. public class Linker { private final Map<Class<?>, Factory<?>> factories =

    new HashMap<>(); private final Map<Class<?>, Factory<?>> linkedFactories = new HashMap<>(); public <T> void install(Class<T> key, Factory<T> factory) { factories.put(key, factory); } public <T> Factory<T> factoryFor(Class<T> key) { Factory<?> factory = linkedFactories.get(key); if (factory == null) { factory = factories.get(key); factory.link(this); linkedFactories.put(key, factory); } return (Factory<T>) factory; } }
  56. private static void installFactories(Linker linker) { linker.install(VisitHandler.class, new Factory<VisitHandler>() {

    @Override public VisitHandler get(Linker linker) { Factory<Counter> counterFactory = linker.factoryFor(Counter.class); Factory<Logger> loggerFactory = linker.factoryFor(Logger.class); Counter counter = counterFactory.get(linker); Logger logger = loggerFactory.get(linker); return new VisitHandler(counter, logger); } }); linker.install(Logger.class, new Factory<Logger>() { @Override public Logger get(Linker linker) { Factory<PrintStream> printStreamFactory = linker.factoryFor(PrintStream.class); PrintStream printStream = printStreamFactory.get(linker); return new Logger(printStream); } }); linker.install(PrintStream.class, ValueFactory.of(System.out)); linker.install(Counter.class, SingletonFactory.of(new Factory<Counter>() { @Override public Counter get(Linker linker) { return new Counter(); } })); }
  57. private static void installFactories(Linker linker) { linker.install(VisitHandler.class, new Factory<VisitHandler>() {

    @Override public VisitHandler get(Linker linker) { Factory<Counter> counterFactory = linker.factoryFor(Counter.class); Factory<Logger> loggerFactory = linker.factoryFor(Logger.class); Counter counter = counterFactory.get(linker); Logger logger = loggerFactory.get(linker); return new VisitHandler(counter, logger); } }); linker.install(Logger.class, new Factory<Logger>() { @Override public Logger get(Linker linker) { Factory<PrintStream> printStreamFactory = linker.factoryFor(PrintStream.class); PrintStream printStream = printStreamFactory.get(linker); return new Logger(printStream); } }); linker.install(PrintStream.class, ValueFactory.of(System.out));
  58. private static void installFactories(Linker linker) { linker.install(VisitHandler.class, new Factory<VisitHandler>() {

    Factory<Logger> loggerFactory; Factory<Counter> counterFactory; @Override public void link(Linker linker) { counterFactory = linker.factoryFor(Counter.class); loggerFactory = linker.factoryFor(Logger.class); } @Override public VisitHandler get() { return new VisitHandler(counterFactory.get(), loggerFactory.get()); } }); linker.install(Logger.class, new Factory<Logger>() { @Override public Logger get(Linker linker) { Factory<PrintStream> printStreamFactory = linker.factoryFor(PrintStream.class); PrintStream printStream = printStreamFactory.get(linker);
  59. private static void installFactories(Linker linker) { linker.install(VisitHandler.class, new Factory<VisitHandler>() {

    Factory<Logger> loggerFactory; Factory<Counter> counterFactory; @Override public void link(Linker linker) { counterFactory = linker.factoryFor(Counter.class); loggerFactory = linker.factoryFor(Logger.class); } @Override public VisitHandler get() { return new VisitHandler(counterFactory.get(), loggerFactory.get()); } }); linker.install(Logger.class, new Factory<Logger>() { @Override public Logger get(Linker linker) { Factory<PrintStream> printStreamFactory = linker.factoryFor(PrintStream.class); PrintStream printStream = printStreamFactory.get(linker);
  60. private static void installFactories(Linker linker) { linker.install(VisitHandler.class, new Factory<VisitHandler>() {

    Factory<Logger> loggerFactory; Factory<Counter> counterFactory; @Override public void link(Linker linker) { counterFactory = linker.factoryFor(Counter.class); loggerFactory = linker.factoryFor(Logger.class); } @Override public VisitHandler get() { return new VisitHandler(counterFactory.get(), loggerFactory.get()); } }); linker.install(Logger.class, new Factory<Logger>() { @Override public Logger get(Linker linker) { Factory<PrintStream> printStreamFactory = linker.factoryFor(PrintStream.class); PrintStream printStream = printStreamFactory.get(linker);
  61. private static void installFactories(Linker linker) { linker.install(VisitHandler.class, new Factory<VisitHandler>() {

    Factory<Logger> loggerFactory; Factory<Counter> counterFactory; @Override public void link(Linker linker) { counterFactory = linker.factoryFor(Counter.class); loggerFactory = linker.factoryFor(Logger.class); } @Override public VisitHandler get() { return new VisitHandler(counterFactory.get(), loggerFactory.get()); } }); linker.install(Logger.class, new Factory<Logger>() { @Override public Logger get(Linker linker) { Factory<PrintStream> printStreamFactory = linker.factoryFor(PrintStream.class); PrintStream printStream = printStreamFactory.get(linker);
  62. public class Linker { private final Map<Class<?>, Factory<?>> factories =

    new HashMap<>(); private final Map<Class<?>, Factory<?>> linkedFactories = new HashMap<>(); public <T> void install(Class<T> key, Factory<T> factory) { factories.put(key, factory); } public <T> Factory<T> factoryFor(Class<T> key) { System.out.println("Get factory for " + key); Factory<?> factory = linkedFactories.get(key); if (factory == null) { System.out.println("Link factory for " + key); factory = factories.get(key); factory.link(this); linkedFactories.put(key, factory); } return (Factory<T>) factory; } }
  63. public class Linker { private final Map<Class<?>, Factory<?>> factories =

    new HashMap<>(); private final Map<Class<?>, Factory<?>> linkedFactories = new HashMap<>(); public <T> void install(Class<T> key, Factory<T> factory) { factories.put(key, factory); } public <T> Factory<T> factoryFor(Class<T> key) { System.out.println("Get factory for " + key); Factory<?> factory = linkedFactories.get(key); if (factory == null) { System.out.println("Link factory for " + key); factory = factories.get(key); factory.link(this); linkedFactories.put(key, factory); } return (Factory<T>) factory; } }
  64. Get factory for class VisitHandler Link factory for class VisitHandler

    Get factory for class Counter Link factory for class Counter Get factory for class Logger Link factory for class Logger Get factory for class java.io.PrintStream Link factory for class java.io.PrintStream Visits increased: 1 Get factory for class VisitHandler Visits increased: 2 public static void main(String... args) { ObjectGraph objectGraph = buildObjectGraph(); VisitHandler visitHandler = objectGraph.get(VisitHandler.class); visitHandler.visit(); VisitHandler visitHandler2 = objectGraph.get(VisitHandler.class); visitHandler2.visit(); }
  65. So far • Instantiation and its order automated • Caching

  66. Good Job !

  67. private static void installFactories(Linker linker) { linker.install(VisitHandler.class, new Factory<VisitHandler>() {

    Factory<Logger> loggerFactory; Factory<Counter> counterFactory; @Override public void link(Linker linker) { counterFactory = linker.factoryFor(Counter.class); loggerFactory = linker.factoryFor(Logger.class); } @Override public VisitHandler get() { return new VisitHandler(counterFactory.get(), loggerFactory.get()); } }); linker.install(Logger.class, new Factory<Logger>() { Factory<PrintStream> printStreamFactory; @Override public void link(Linker linker) { printStreamFactory = linker.factoryFor(PrintStream.class); } @Override public Logger get() { return new Logger(printStreamFactory.get()); } }); linker.install(PrintStream.class, ValueFactory.of(System.out)); linker.install(Counter.class, SingletonFactory.of(new Factory<Counter>() { @Override public Counter get() { return new Counter(); } })); }
  68. public class VisitHandler { private final Counter counter; private final

    Logger logger; @Inject public VisitHandler(Counter counter, Logger logger) { this.counter = counter; this.logger = logger; } public void visit() { counter.increment(); logger.log("Visits increased: " + counter.getCount()); } }
  69. public class VisitHandler { private final Counter counter; private final

    Logger logger; @Inject public VisitHandler(Counter counter, Logger logger) { this.counter = counter; this.logger = logger; } public void visit() { counter.increment(); logger.log("Visits increased: " + counter.getCount()); } }
  70. public class Linker { private final Map<Class<?>, Factory<?>> factories =

    new HashMap<>(); private final Map<Class<?>, Factory<?>> linkedFactories = new HashMap<>(); public <T> void install(Class<T> key, Factory<T> factory) { factories.put(key, factory); } public <T> Factory<T> factoryFor(Class<T> key) { Factory<?> factory = linkedFactories.get(key); if (factory == null) { factory = factories.get(key); factory.link(this); linkedFactories.put(key, factory); } return (Factory<T>) factory; } }
  71. public class Linker { private final Map<Class<?>, Factory<?>> factories =

    new HashMap<>(); private final Map<Class<?>, Factory<?>> linkedFactories = new HashMap<>(); public <T> void install(Class<T> key, Factory<T> factory) { factories.put(key, factory); } public <T> Factory<T> factoryFor(Class<T> key) { Factory<?> factory = linkedFactories.get(key); if (factory == null) { factory = factories.get(key); factory.link(this); linkedFactories.put(key, factory); } return (Factory<T>) factory; } }
  72. public class Linker { private final Map<Class<?>, Factory<?>> factories =

    new HashMap<>(); private final Map<Class<?>, Factory<?>> linkedFactories = new HashMap<>(); public <T> void install(Class<T> key, Factory<T> factory) { factories.put(key, factory); } public <T> Factory<T> factoryFor(Class<T> key) { Factory<?> factory = linkedFactories.get(key); if (factory == null) { factory = loadFactory(key); factory.link(this); linkedFactories.put(key, factory); } return (Factory<T>) factory; } }
  73. public class Linker { private final Map<Class<?>, Factory<?>> factories =

    new HashMap<>(); private final Map<Class<?>, Factory<?>> linkedFactories = new HashMap<>(); public <T> void install(Class<T> key, Factory<T> factory) { factories.put(key, factory); } public <T> Factory<T> factoryFor(Class<T> key) { Factory<?> factory = linkedFactories.get(key); if (factory == null) { factory = loadFactory(key); factory.link(this); linkedFactories.put(key, factory); } return (Factory<T>) factory; } }
  74. private <T> Factory<?> loadFactory(Class<T> key) { Factory<?> factory = factories.get(key);

    if (factory != null) { return factory; } Constructor<T> constructor = findAtInjectConstructor(key); if (constructor != null) { factory = new ReflectiveFactory(constructor); if (key.isAnnotationPresent(Singleton.class)) { factory = SingletonFactory.of(factory); } return factory; } throw new IllegalStateException("No factory for " + key); } private <T> Constructor<T> findAtInjectConstructor(Class<T> type) { for (Constructor<?> constructor : type.getConstructors()) { if (constructor.isAnnotationPresent(Inject.class)) { return (Constructor<T>) constructor; } } return null; }
  75. None
  76. private <T> Factory<?> loadFactory(Class<T> key) { Factory<?> factory = factories.get(key);

    if (factory != null) { return factory; } Constructor<T> constructor = findAtInjectConstructor(key); if (constructor != null) { factory = new ReflectiveFactory(constructor); if (key.isAnnotationPresent(Singleton.class)) { factory = SingletonFactory.of(factory); } return factory; } throw new IllegalStateException("No factory for " + key); } private <T> Constructor<T> findAtInjectConstructor(Class<T> type) { for (Constructor<?> constructor : type.getConstructors()) { if (constructor.isAnnotationPresent(Inject.class)) { return (Constructor<T>) constructor; } } return null; }
  77. private <T> Factory<?> loadFactory(Class<T> key) { Factory<?> factory = factories.get(key);

    if (factory != null) { return factory; } Constructor<T> constructor = findAtInjectConstructor(key); if (constructor != null) { factory = new ReflectiveFactory(constructor); if (key.isAnnotationPresent(Singleton.class)) { factory = SingletonFactory.of(factory); } return factory; } throw new IllegalStateException("No factory for " + key); } private <T> Constructor<T> findAtInjectConstructor(Class<T> type) { for (Constructor<?> constructor : type.getConstructors()) { if (constructor.isAnnotationPresent(Inject.class)) { return (Constructor<T>) constructor; } } return null; }
  78. private <T> Factory<?> loadFactory(Class<T> key) { Factory<?> factory = factories.get(key);

    if (factory != null) { return factory; } Constructor<T> constructor = findAtInjectConstructor(key); if (constructor != null) { factory = new ReflectiveFactory(constructor); if (key.isAnnotationPresent(Singleton.class)) { factory = SingletonFactory.of(factory); } return factory; } throw new IllegalStateException("No factory for " + key); } private <T> Constructor<T> findAtInjectConstructor(Class<T> type) { for (Constructor<?> constructor : type.getConstructors()) { if (constructor.isAnnotationPresent(Inject.class)) { return (Constructor<T>) constructor; } } return null; }
  79. private <T> Factory<?> loadFactory(Class<T> key) { Factory<?> factory = factories.get(key);

    if (factory != null) { return factory; } Constructor<T> constructor = findAtInjectConstructor(key); if (constructor != null) { factory = new ReflectiveFactory(constructor); if (key.isAnnotationPresent(Singleton.class)) { factory = SingletonFactory.of(factory); } return factory; } throw new IllegalStateException("No factory for " + key); } private <T> Constructor<T> findAtInjectConstructor(Class<T> type) { for (Constructor<?> constructor : type.getConstructors()) { if (constructor.isAnnotationPresent(Inject.class)) { return (Constructor<T>) constructor; } } return null; }
  80. private <T> Factory<?> loadFactory(Class<T> key) { Factory<?> factory = factories.get(key);

    if (factory != null) { return factory; } Constructor<T> constructor = findAtInjectConstructor(key); if (constructor != null) { factory = new ReflectiveFactory(constructor); if (key.isAnnotationPresent(Singleton.class)) { factory = SingletonFactory.of(factory); } return factory; } throw new IllegalStateException("No factory for " + key); } private <T> Constructor<T> findAtInjectConstructor(Class<T> type) { for (Constructor<?> constructor : type.getConstructors()) { if (constructor.isAnnotationPresent(Inject.class)) { return (Constructor<T>) constructor; } } return null; }
  81. private <T> Factory<?> loadFactory(Class<T> key) { Factory<?> factory = factories.get(key);

    if (factory != null) { return factory; } Constructor<T> constructor = findAtInjectConstructor(key); if (constructor != null) { factory = new ReflectiveFactory(constructor); if (key.isAnnotationPresent(Singleton.class)) { factory = SingletonFactory.of(factory); } return factory; } throw new IllegalStateException("No factory for " + key); } private <T> Constructor<T> findAtInjectConstructor(Class<T> type) { for (Constructor<?> constructor : type.getConstructors()) { if (constructor.isAnnotationPresent(Inject.class)) { return (Constructor<T>) constructor; } } return null; }
  82. public class ReflectiveFactory<T> extends Factory<T> { private final Constructor<T> constructor;

    private final ArrayList<Factory<?>> factories = new ArrayList<>(); public ReflectiveFactory(Constructor<T> constructor) { this.constructor = constructor; } @Override public void link(Linker linker) { for (Class<?> parameterType : constructor.getParameterTypes()) { factories.add(linker.factoryFor(parameterType)); } } @Override public T get() { Object[] dependencies = new Object[factories.size()]; for (int i = 0; i < dependencies.length; i++) { Factory<?> factory = factories.get(i); dependencies[i] = factory.get(); } try { return constructor.newInstance(dependencies); } catch (Exception e) { throw new RuntimeException(e); } } }
  83. public class ReflectiveFactory<T> extends Factory<T> { private final Constructor<T> constructor;

    private final ArrayList<Factory<?>> factories = new ArrayList<>(); public ReflectiveFactory(Constructor<T> constructor) { this.constructor = constructor; } @Override public void link(Linker linker) { for (Class<?> parameterType : constructor.getParameterTypes()) { factories.add(linker.factoryFor(parameterType)); } } @Override public T get() { Object[] dependencies = new Object[factories.size()]; for (int i = 0; i < dependencies.length; i++) { Factory<?> factory = factories.get(i); dependencies[i] = factory.get(); } try { return constructor.newInstance(dependencies); } catch (Exception e) { throw new RuntimeException(e); } } }
  84. public class ReflectiveFactory<T> extends Factory<T> { private final Constructor<T> constructor;

    private final ArrayList<Factory<?>> factories = new ArrayList<>(); public ReflectiveFactory(Constructor<T> constructor) { this.constructor = constructor; } @Override public void link(Linker linker) { for (Class<?> parameterType : constructor.getParameterTypes()) { factories.add(linker.factoryFor(parameterType)); } } @Override public T get() { Object[] dependencies = new Object[factories.size()]; for (int i = 0; i < dependencies.length; i++) { Factory<?> factory = factories.get(i); dependencies[i] = factory.get(); } try { return constructor.newInstance(dependencies); } catch (Exception e) { throw new RuntimeException(e); } } }
  85. public class ReflectiveFactory<T> extends Factory<T> { private final Constructor<T> constructor;

    private final ArrayList<Factory<?>> factories = new ArrayList<>(); public ReflectiveFactory(Constructor<T> constructor) { this.constructor = constructor; } @Override public void link(Linker linker) { for (Class<?> parameterType : constructor.getParameterTypes()) { factories.add(linker.factoryFor(parameterType)); } } @Override public T get() { Object[] dependencies = new Object[factories.size()]; for (int i = 0; i < dependencies.length; i++) { Factory<?> factory = factories.get(i); dependencies[i] = factory.get(); } try { return constructor.newInstance(dependencies); } catch (Exception e) { throw new RuntimeException(e); } } }
  86. public class ReflectiveFactory<T> extends Factory<T> { private final Constructor<T> constructor;

    private final ArrayList<Factory<?>> factories = new ArrayList<>(); public ReflectiveFactory(Constructor<T> constructor) { this.constructor = constructor; } @Override public void link(Linker linker) { for (Class<?> parameterType : constructor.getParameterTypes()) { factories.add(linker.factoryFor(parameterType)); } } @Override public T get() { Object[] dependencies = new Object[factories.size()]; for (int i = 0; i < dependencies.length; i++) { Factory<?> factory = factories.get(i); dependencies[i] = factory.get(); } try { return constructor.newInstance(dependencies); } catch (Exception e) { throw new RuntimeException(e); } } }
  87. public class VisitHandler { @Inject public VisitHandler(Counter counter, Logger logger)

    { this.counter = counter; this.logger = logger; } } public class Logger { @Inject public Logger(PrintStream printStream) { this.printStream = printStream; } } @Singleton public class Counter { @Inject public Counter() {} }
  88. private static void installFactories(Linker linker) { linker.install(VisitHandler.class, new Factory<VisitHandler>() {

    Factory<Logger> loggerFactory; Factory<Counter> counterFactory; @Override public void link(Linker linker) { counterFactory = linker.factoryFor(Counter.class); loggerFactory = linker.factoryFor(Logger.class); } @Override public VisitHandler get() { return new VisitHandler(counterFactory.get(), loggerFactory.get()); } }); linker.install(Logger.class, new Factory<Logger>() { Factory<PrintStream> printStreamFactory; @Override public void link(Linker linker) { printStreamFactory = linker.factoryFor(PrintStream.class); } @Override public Logger get() { return new Logger(printStreamFactory.get()); } }); linker.install(PrintStream.class, ValueFactory.of(System.out)); linker.install(Counter.class, SingletonFactory.of(new Factory<Counter>() { @Override public Counter get() { return new Counter(); } })); }
  89. private static void installFactories(Linker linker) { linker.install(VisitHandler.class, new Factory<VisitHandler>() {

    ... }); linker.install(Logger.class, new Factory<Logger>() { ... }); linker.install(PrintStream.class, ValueFactory.of(System.out)); linker.install(Counter.class, SingletonFactory.of(new Factory<Counter>() { ... })); }
  90. private static void installFactories(Linker linker) { linker.install(Logger.class, new Factory<Logger>() {

    ... }); linker.install(PrintStream.class, ValueFactory.of(System.out)); linker.install(Counter.class, SingletonFactory.of(new Factory<Counter>() { ... })); }
  91. private static void installFactories(Linker linker) { linker.install(PrintStream.class, ValueFactory.of(System.out)); linker.install(Counter.class, SingletonFactory.of(new

    Factory<Counter>() { ... })); }
  92. private static void installFactories(Linker linker) { linker.install(PrintStream.class, ValueFactory.of(System.out)); }

  93. private static void installFactories(Linker linker) { linker.install(VisitHandler.class, new Factory<VisitHandler>() {

    Factory<Logger> loggerFactory; Factory<Counter> counterFactory; @Override public void link(Linker linker) { counterFactory = linker.factoryFor(Counter.class); loggerFactory = linker.factoryFor(Logger.class); } @Override public VisitHandler get() { return new VisitHandler(counterFactory.get(), loggerFactory.get()); } }); linker.install(Logger.class, new Factory<Logger>() { Factory<PrintStream> printStreamFactory; @Override public void link(Linker linker) { printStreamFactory = linker.factoryFor(PrintStream.class); } @Override public Logger get() { return new Logger(printStreamFactory.get()); } }); linker.install(PrintStream.class, ValueFactory.of(System.out)); linker.install(Counter.class, SingletonFactory.of(new Factory<Counter>() { @Override public Counter get() { return new Counter(); } })); } private static void installFactories(Linker linker) { linker.install(PrintStream.class, ValueFactory.of(System.out)); }
  94. So far • Instantiation and its order automated • Caching

    • No boilerplate
  95. None
  96. Good Job !

  97. None
  98. linker.install(VisitHandler.class, new Factory<Logger>() { Factory<PrintStream> printStreamFactory; @Override public void link(Linker

    linker) { printStreamFactory = linker.factoryFor(PrintStream.class); } @Override public Logger get() { return new Logger(printStreamFactory.get()); } });
  99. Annotation Processing

  100. public class Logger$$Factory extends Factory<Logger> { Factory<PrintStream> printStreamFactory; @Override public

    void link(Linker linker) { printStreamFactory = linker.factoryFor(PrintStream.class); } @Override public Logger get() { return new Logger(printStreamFactory.get()); } }
  101. public abstract class GeneratedFactory<T> extends Factory<T> { private final boolean

    singleton; public GeneratedFactory(boolean singleton) { this.singleton = singleton; } } public class Logger$$Factory extends GeneratedFactory<Logger> { public Logger$$Factory() { super(false); } }
  102. private <T> Factory<?> loadFactory(Class<T> key) { Factory<?> factory = factories.get(key);

    if (factory != null) { return factory; } Constructor<T> constructor = findAtInjectConstructor(key); if (constructor != null) { factory = new ReflectiveFactory(constructor); if (key.isAnnotationPresent(Singleton.class)) { factory = SingletonFactory.of(factory); } return factory; } throw new IllegalStateException("No factory for " + key); }
  103. public class Linker { private <T> Factory<?> loadFactory(Class<T> key) {

    Factory<?> factory = factories.get(key); if (factory != null) { return factory; } factory = GeneratedFactory.loadFactory(key); if (factory != null) { return factory; } throw new IllegalStateException("No factory for " + key); } }
  104. public class Linker { private <T> Factory<?> loadFactory(Class<T> key) {

    Factory<?> factory = factories.get(key); if (factory != null) { return factory; } factory = GeneratedFactory.loadFactory(key); if (factory != null) { return factory; } throw new IllegalStateException("No factory for " + key); } }
  105. public abstract class GeneratedFactory<T> extends Factory<T> { public static <T>

    Factory<T> loadFactory(Class<T> key) { String generatedClass = key.getName() + "$$Factory"; try { Class<GeneratedFactory<T>> factoryClass = (Class<GeneratedFactory<T>>) Class.forName(generatedClass); GeneratedFactory<T> factory = factoryClass.newInstance(); if (factory.singleton) { return SingletonFactory.of(factory); } else { return factory; } } catch (Exception e) { System.err.println("Error for " + key); e.printStackTrace(); return null; } } private final boolean singleton; public GeneratedFactory(boolean singleton) { this.singleton = singleton; } }
  106. public abstract class GeneratedFactory<T> extends Factory<T> { public static <T>

    Factory<T> loadFactory(Class<T> key) { String generatedClass = key.getName() + "$$Factory"; try { Class<GeneratedFactory<T>> factoryClass = (Class<GeneratedFactory<T>>) Class.forName(generatedClass); GeneratedFactory<T> factory = factoryClass.newInstance(); if (factory.singleton) { return SingletonFactory.of(factory); } else { return factory; } } catch (Exception e) { System.err.println("Error for " + key); e.printStackTrace(); return null; } } private final boolean singleton; public GeneratedFactory(boolean singleton) { this.singleton = singleton; } }
  107. public abstract class GeneratedFactory<T> extends Factory<T> { public static <T>

    Factory<T> loadFactory(Class<T> key) { String generatedClass = key.getName() + "$$Factory"; try { Class<GeneratedFactory<T>> factoryClass = (Class<GeneratedFactory<T>>) Class.forName(generatedClass); GeneratedFactory<T> factory = factoryClass.newInstance(); if (factory.singleton) { return SingletonFactory.of(factory); } else { return factory; } } catch (Exception e) { System.err.println("Error for " + key); e.printStackTrace(); return null; } } private final boolean singleton; public GeneratedFactory(boolean singleton) { this.singleton = singleton; } }
  108. So far • Instantiation and its order automated • Caching

    • No boilerplate • No reflection
  109. BETA

  110. Good Job !

  111. public class DatabaseManager { private final Database database; @Inject public

    DatabaseManager(Database database) { this.database = database; } public void updateVisits(int count) { database.execute("UPDATE count_table SET count = " + count); } }
  112. public static void main(String... args) { ObjectGraph objectGraph = buildObjectGraph();

    DatabaseManager databaseManager = objectGraph.get(DatabaseManager.class); databaseManager.updateVisits(3); } Exception in thread "main" java.lang.IllegalStateException: No factory for interface app.db.Database at injection.Linker.loadFactory(Linker.java:41) at injection.Linker.factoryFor(Linker.java:21) at app.db.DatabaseManager$$Factory.link(DatabaseManager$$Factory.java:17) at injection.factory.SingletonFactory.link(SingletonFactory.java:20) at injection.Linker.factoryFor(Linker.java:22) at injection.ObjectGraph.get(ObjectGraph.java:13) at Main.main(Main.java:11)
  113. public static void main(String... args) { ObjectGraph objectGraph = buildObjectGraph();

    objectGraph.validate(DatabaseManager.class); DatabaseManager databaseManager = objectGraph.get(DatabaseManager.class); databaseManager.updateVisits(3); } public class ObjectGraph { private final Linker linker; public <T> T get(Class<T> key) { Factory<T> factory = linker.factoryFor(key); return factory.get(); } public <T> void validate(Class<T> key) { linker.factoryFor(key); } }
  114. public static void main(String... args) { ObjectGraph objectGraph = buildObjectGraph();

    objectGraph.validate(DatabaseManager.class); DatabaseManager databaseManager = objectGraph.get(DatabaseManager.class); databaseManager.updateVisits(3); } public class ObjectGraph { private final Linker linker; public <T> T get(Class<T> key) { Factory<T> factory = linker.factoryFor(key); return factory.get(); } public <T> void validate(Class<T> key) { linker.factoryFor(key); } }
  115. static void installFactories(Linker linker) { linker.install(PrintStream.class, ValueFactory.of(System.out)); }

  116. public static void main(String... args) { ObjectGraph objectGraph = buildObjectGraph();

    objectGraph.validate(DatabaseManager.class); // … } public static void installFactories(Linker linker) { linker.install(PrintStream.class, ValueFactory.of(System.out)); }
  117. Annotation Processing

  118. public static void main(String... args) { ObjectGraph objectGraph = buildObjectGraph();

    objectGraph.validate(DatabaseManager.class); // … } public static void installFactories(Linker linker) { linker.install(PrintStream.class, ValueFactory.of(System.out)); }
  119. public class Module { @Provides public Database provideDatabase(DatabaseImpl database) {

    return database; } @Provides public PrintStream providePrintStream() { return System.out; } }
  120. public class Module { @Provides public Database provideDatabase(DatabaseImpl database) {

    return database; } @Provides public PrintStream providePrintStream() { return System.out; } }
  121. @Module public class MainModule { @Provides public Database provideDatabase(DatabaseImpl database)

    { return database; } @Provides public PrintStream providePrintStream() { return System.out; } }
  122. private static ObjectGraph buildObjectGraph() { Linker linker = new Linker();

    installFactories(linker); return new ObjectGraph(linker); } private static void installFactories(Linker linker) { linker.install(PrintStream.class, ValueFactory.of(System.out)); }
  123. private static ObjectGraph buildObjectGraph(List<Class> moduleClasses) { Linker linker = new

    Linker(); linker.loadModuleBindings(moduleClasses); return new ObjectGraph(linker); } private static void installFactories(Linker linker) { linker.install(PrintStream.class, ValueFactory.of(System.out)); }
  124. public static void main(String... args) { ObjectGraph objectGraph = buildObjectGraph();

    objectGraph.validate(DatabaseManager.class); // … }
  125. @Module public class MainModule { @Provides public Database provideDatabase(DatabaseImpl database)

    { return database; } @Provides public PrintStream providePrintStream() { return System.out; } }
  126. @Module public class MainModule { @Provides public Database provideDatabase(DatabaseImpl database)

    { return database; } @Provides public PrintStream providePrintStream() { return System.out; } }
  127. @Module(injects = DatabaseManager.class) public class MainModule { @Provides public Database

    provideDatabase(DatabaseImpl database) { return database; } @Provides public PrintStream providePrintStream() { return System.out; } }
  128. So far • Instantiation and its order automated • Caching

    • No boilerplate • No reflection • Verification at compile time
  129. None
  130. Good Job !

  131. Object Graph Linker @Singleton Factory Factory @Singleton Factory VisitHandler Database

    Manager Counter
  132. Object Graph Linker @Singleton Factory Factory @Singleton Factory VisitHandler Database

    Manager Counter
  133. Object Graph @Singleton Database Manager @Singleton Counter

  134. Object Graph @Singleton Database Manager @Singleton Counter

  135. Object Graph @Singleton Database Manager @Singleton Counter Object Graph

  136. Object Graph @Singleton Database Manager @Singleton Counter Object Graph

  137. Object Graph @Singleton Database Manager @Singleton Counter Object Graph Object

    Graph @Singleton App
  138. Object Graph @Singleton Database Manager @Singleton Counter Object Graph Object

    Graph @Singleton App
  139. @Singleton Database Manager Object Graph Object Graph @Singleton App

  140. Object Graph @Singleton Database Manager @Singleton Counter Object Graph Object

    Graph @Singleton App
  141. Scoped Instance

  142. public class ObjectGraph { final Linker linker; final ObjectGraph parentGraph;

    public <T> T get(Class<T> key) { if (parentGraph != null) { T instance = parentGraph.get(key); if (instance != null) { return instance; } } Factory<T> factory = linker.factoryFor(key); return factory.get(); } }
  143. public class ObjectGraph { final Linker linker; final ObjectGraph parentGraph;

    public <T> T get(Class<T> key) { if (parentGraph != null) { T instance = parentGraph.get(key); if (instance != null) { return instance; } } Factory<T> factory = linker.factoryFor(key); return factory.get(); } }
  144. public class ObjectGraph { final Linker linker; final ObjectGraph parentGraph;

    public <T> T get(Class<T> key) { if (parentGraph != null) { T instance = parentGraph.get(key); if (instance != null) { return instance; } } Factory<T> factory = linker.factoryFor(key); return factory.get(); } }
  145. public class ObjectGraph { final Linker linker; final ObjectGraph parentGraph;

    public <T> T get(Class<T> key) { if (parentGraph != null) { T instance = parentGraph.get(key); if (instance != null) { return instance; } } Factory<T> factory = linker.factoryFor(key); return factory.get(); } }
  146. public class Linker { private final Map<Class<?>, Factory<?>> factories =

    new HashMap<>(); private final Map<Class<?>, Factory<?>> linkedFactories = new HashMap<>(); public <T> void install(Class<T> key, Factory<T> factory) { factories.put(key, factory); } public <T> Factory<T> factoryFor(Class<T> key) { Factory<?> factory = linkedFactories.get(key); if (factory == null) { factory = loadFactory(key); factory.link(this); linkedFactories.put(key, factory); } return (Factory<T>) factory; } }
  147. So far • Instantiation and its order automated • Caching

    • No boilerplate • No reflection • Verification at compile time • Scope
  148. Good Job !

  149. public class Logger$$Factory extends GeneratedFactory<Logger> { private Factory<PrintStream> printStreamFactory; public

    Logger$$Factory() {} @Override public void link(Linker linker) { printStreamFactory = linker.factoryFor(PrintStream.class); } @Override public Logger get() { return new Logger(printStreamFactory.get()); } }
  150. public class Logger$$Factory extends GeneratedFactory<Logger> { private Factory<PrintStream> printStreamFactory; public

    Logger$$Factory() {} @Override public Logger get() { return new Logger(printStreamFactory.get()); } }
  151. public class Logger$$Factory extends GeneratedFactory<Logger> { private final Factory<PrintStream> printStreamFactory;

    public Logger$$Factory(Factory<PrintStream> printStreamFactory) { this.printStreamFactory = printStreamFactory; } @Override public Logger get() { return new Logger(printStreamFactory.get()); } }
  152. @Module(injects = DatabaseManager.class) public class MainModule { @Provides public Database

    provideDatabase(DatabaseImpl database) { return database; } @Provides public PrintStream providePrintStream() { return System.out; } } @Component(modules = MainModule.class) public interface MainComponent { DatabaseManager databaseManager(); }
  153. @Module public class MainModule { @Provides public Database provideDatabase(DatabaseImpl database)

    { return database; } @Provides public PrintStream providePrintStream() { return System.out; } } @Component(modules = MainModule.class) public interface MainComponent { DatabaseManager databaseManager(); }
  154. public class DaggerMainComponent implements MainComponent { Factory<PrintStream> printStreamFactory; Factory<Logger> loggerFactory;

    Factory<DatabaseManager> databaseManagerFactory; public DaggerMainComponent() { final MainModule mainModule = new MainModule(); printStreamFactory = new Factory<PrintStream>() { @Override public PrintStream get() { return mainModule.providePrintStream(); } }; loggerFactory = new Logger$$Factory(printStreamFactory); databaseManagerFactory = new DatabaseManager$$Factory(loggerFactory); } @Override public DatabaseManager databaseManager() { return databaseManagerFactory.get(); } }
  155. public class DaggerMainComponent implements MainComponent { Factory<PrintStream> printStreamFactory; Factory<Logger> loggerFactory;

    Factory<DatabaseManager> databaseManagerFactory; public DaggerMainComponent() { final MainModule mainModule = new MainModule(); printStreamFactory = new Factory<PrintStream>() { @Override public PrintStream get() { return mainModule.providePrintStream(); } }; loggerFactory = new Logger$$Factory(printStreamFactory); databaseManagerFactory = new DatabaseManager$$Factory(loggerFactory); } @Override public DatabaseManager databaseManager() { return databaseManagerFactory.get(); } }
  156. public class DaggerMainComponent implements MainComponent { Factory<PrintStream> printStreamFactory; Factory<Logger> loggerFactory;

    Factory<DatabaseManager> databaseManagerFactory; public DaggerMainComponent() { final MainModule mainModule = new MainModule(); printStreamFactory = new Factory<PrintStream>() { @Override public PrintStream get() { return mainModule.providePrintStream(); } }; loggerFactory = new Logger$$Factory(printStreamFactory); databaseManagerFactory = new DatabaseManager$$Factory(loggerFactory); } @Override public DatabaseManager databaseManager() { return databaseManagerFactory.get(); } }
  157. public class DaggerMainComponent implements MainComponent { Factory<PrintStream> printStreamFactory; Factory<Logger> loggerFactory;

    Factory<DatabaseManager> databaseManagerFactory; public DaggerMainComponent() { final MainModule mainModule = new MainModule(); printStreamFactory = new Factory<PrintStream>() { @Override public PrintStream get() { return mainModule.providePrintStream(); } }; loggerFactory = new Logger$$Factory(printStreamFactory); databaseManagerFactory = new DatabaseManager$$Factory(loggerFactory); } @Override public DatabaseManager databaseManager() { return databaseManagerFactory.get(); } }
  158. public class DaggerMainComponent implements MainComponent { Factory<PrintStream> printStreamFactory; Factory<Logger> loggerFactory;

    Factory<DatabaseManager> databaseManagerFactory; public DaggerMainComponent() { final MainModule mainModule = new MainModule(); printStreamFactory = new Factory<PrintStream>() { @Override public PrintStream get() { return mainModule.providePrintStream(); } }; loggerFactory = new Logger$$Factory(printStreamFactory); databaseManagerFactory = new DatabaseManager$$Factory(loggerFactory); } @Override public DatabaseManager databaseManager() { return databaseManagerFactory.get(); } }
  159. DatabaseManager databaseManager = new DaggerMainComponent().databaseManager();

  160. So far • Instantiation and its order automated • Caching

    • No boilerplate • No reflection • Verification at compile time • Scope • Great performance
  161. 2

  162. Good Job !

  163. Fin Slides: goo.gl/nceQmc Benoît Quenaudon @oldergod

  164. Reference • DIY: Build Your Own Dependency Injection Library ◦

    https://news.realm.io/news/android-pierre-yves-ricau-build-own-dependency-injection/ • Dagger ◦ https://google.github.io/dagger