PY Ricau: DIY - Build Your Own Dependency Injection Library

1fa9cb8c7997c8c4d3d251fb5e41f749?s=47 Realm
April 13, 2016

PY Ricau: DIY - Build Your Own Dependency Injection Library

1fa9cb8c7997c8c4d3d251fb5e41f749?s=128

Realm

April 13, 2016
Tweet

Transcript

  1. 6.
  2. 7.
  3. 8.

    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());
 }
 }
  4. 9.

    public class Counter {
 
 private int count;
 
 void

    increment() {
 count++;
 }
 
 int getCount() {
 return count;
 }
 }
  5. 10.

    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);
 }
 
 }
  6. 11.

    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. 12.

    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. 13.

    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. 14.

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

    VisitHandler visitHandler = objectGraph.get(VisitHandler.class); 
 visitHandler.visit();
 }
  10. 15.

    public class ObjectGraph {
 
 public <T> T get(Class<T> key)

    {
 throw new UnsupportedOperationException("Not implemented");
 }
 }
  11. 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);
 }
 }
  12. 17.

    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. 18.

    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. 19.

    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);
 }
 }
  15. 20.

    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);
 }
 }
  16. 21.

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

    VisitHandler visitHandler = objectGraph.get(VisitHandler.class); 
 visitHandler.visit();
 }
  17. 22.

    private static ObjectGraph buildObjectGraph() {
 Linker linker = new Linker();


    installFactories(linker);
 return new ObjectGraph(linker);
 }
  18. 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);
 }
 });
 
 linker.install(Logger.class, new Factory<Logger>() {
 @Override public Logger get(Linker linker) {
 Factory<PrintStream> printStreamFactory 
 = linker.factoryFor(PrintStream.class);
 return new Logger(printStreamFactory.get(linker));
 }
 });
 
 linker.install(PrintStream.class, new Factory<PrintStream>() {
 @Override public PrintStream get(Linker linker) {
 return System.out;

  19. 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);
 }
 });
 
 linker.install(Logger.class, new Factory<Logger>() {
 @Override public Logger get(Linker linker) {
 Factory<PrintStream> printStreamFactory 
 = linker.factoryFor(PrintStream.class);
 return new Logger(printStreamFactory.get(linker));
 }
 });
 
 linker.install(PrintStream.class, new Factory<PrintStream>() {
 @Override public PrintStream get(Linker linker) {
 return System.out;

  20. 25.

    });
 
 linker.install(Logger.class, new Factory<Logger>() {
 @Override public Logger get(Linker

    linker) {
 Factory<PrintStream> printStreamFactory 
 = linker.factoryFor(PrintStream.class);
 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();
 }
 });
 }
  21. 26.

    });
 
 linker.install(Logger.class, new Factory<Logger>() {
 @Override public Logger get(Linker

    linker) {
 Factory<PrintStream> printStreamFactory 
 = linker.factoryFor(PrintStream.class);
 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();
 }
 });
 }
  22. 27.

    public final class ValueFactory<T> implements Factory<T> {
 
 public static

    <T> Factory<T> of(T instance) {
 return new ValueFactory<>(instance);
 }
 
 private final T value;
 
 private ValueFactory(T value) {
 this.value = value;
 }
 
 @Override public T get(Linker linker) {
 return value;
 }
 }
  23. 28.

    public final class ValueFactory<T> implements Factory<T> {
 
 public static

    <T> Factory<T> of(T instance) {
 return new ValueFactory<>(instance);
 }
 
 private final T value;
 
 private ValueFactory(T value) {
 this.value = value;
 }
 
 @Override public T get(Linker linker) {
 return value;
 }
 }
  24. 29.
  25. 30.

    });
 
 linker.install(Logger.class, new Factory<Logger>() {
 @Override public Logger get(Linker

    linker) {
 Factory<PrintStream> printStreamFactory 
 = linker.factoryFor(PrintStream.class);
 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();
 }
 });
 }
  26. 31.

    });
 
 linker.install(Logger.class, new Factory<Logger>() {
 @Override public Logger get(Linker

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

    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;
 
 private SingletonFactory(Factory<T> factory) {
 this.factory = factory;
 }
 
 @Override public final T get(Linker linker) {
 if (instance == null) {
 instance = factory.get(linker);
 }
 return instance;
 }
 }
  28. 33.

    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;
 
 private SingletonFactory(Factory<T> factory) {
 this.factory = factory;
 }
 
 @Override public final T get(Linker linker) {
 if (instance == null) {
 instance = factory.get(linker);
 }
 return instance;
 }
 }
  29. 34.

    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);
 }
 }
  30. 35.

    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);
 }
 }
  31. 36.

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

    VisitHandler visitHandler = objectGraph.get(VisitHandler.class); 
 visitHandler.visit();
 }
  32. 37.

    Get factory for class v1.example.VisitHandler Get factory for class v1.example.Counter

    Get factory for class v1.example.Logger Get factory for class java.io.PrintStream
  33. 38.

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

    VisitHandler visitHandler = objectGraph.get(VisitHandler.class); VisitHandler visitHandler2 = objectGraph.get(VisitHandler.class);
 }
  34. 39.

    Get factory for class v1.example.VisitHandler Get factory for class v1.example.Counter

    Get factory for class v1.example.Logger Get factory for class java.io.PrintStream Get factory for class v1.example.VisitHandler Get factory for class v1.example.Counter Get factory for class v1.example.Logger Get factory for class java.io.PrintStream
  35. 42.

    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);
 }
 }
  36. 43.

    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;
 }
 }
  37. 44.

    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;
 }
 }
  38. 45.

    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;
 }
 }
  39. 46.

    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);
 }
 });
  40. 47.

    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());
 }
 });
  41. 48.

    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;
 }
 }
  42. 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) {
 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;
 }
 }
  43. 50.

    Get factory for class v2.example.VisitHandler Link factory for class v2.example.VisitHandler

    Get factory for class v2.example.Counter Link factory for class v2.example.Counter Get factory for class v2.example.Logger Link factory for class v2.example.Logger Get factory for class java.io.PrintStream Link factory for class java.io.PrintStream Get factory for class v2.example.VisitHandler
  44. 51.

    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);

  45. 52.

    
 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();
 }
 }));
 }
  46. 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;
 }
 }
  47. 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 = loadFactory(key);
 factory.link(this);
 linkedFactories.put(key, factory);
 }
 return (Factory<T>) factory;
 }
 }
  48. 55.

    private <T> Factory<?> loadFactory(Class<T> key) {
 Factory<?> factory = factories.get(key);


    
 if (factory != null) {
 return factory;
 }
 throw new IllegalStateException("No factory for " + key);
 }
  49. 56.

    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());
 }
 }
  50. 57.

    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());
 }
 }
  51. 58.

    private <T> Factory<?> loadFactory(Class<T> key) {
 Factory<?> factory = factories.get(key);


    
 if (factory != null) {
 return factory;
 }
 throw new IllegalStateException("No factory for " + key);
 }
  52. 59.

    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);
 }
  53. 60.

    private <T> Constructor<T> findAtInjectConstructor(Class<T> type) {
 for (Constructor<?> constructor :

    type.getConstructors()) {
 if (constructor.isAnnotationPresent(Inject.class)) {
 return (Constructor<T>) constructor;
 }
 }
 return null;
 }
  54. 61.

    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 protected 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();
 }
 

  55. 62.

    this.constructor = constructor;
 }
 
 @Override protected 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);
 }
 }
 }
  56. 64.

    private static void installFactories(Linker linker) {
 linker.install(PrintStream.class, ValueFactory.of(System.out));
 } 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();
 }
 }));
 }
  57. 65.

    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());
 }
 });
  58. 66.

    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());
 }
 }
  59. 67.

    public class Logger$$Factory extends GeneratedFactory<Logger> {
 Factory<PrintStream> printStreamFactory;
 protected Logger$$Factory()

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

    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) {
 return null;
 }
 }
 
 private final boolean singleton;
 
 protected GeneratedFactory(boolean singleton) {
 this.singleton = singleton;
 }

  61. 69.

    private <T> Factory<?> loadFactory(Class<T> key) {
 Factory<?> factory = factories.get(key);


    
 if (factory != null) {
 return factory;
 }
 throw new IllegalStateException("No factory for " + key);
 }
  62. 70.

    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);
 }
  63. 71.
  64. 72.

    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);
 }
 }
  65. 73.

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


    DatabaseManager databaseManager = objectGraph.get(DatabaseManager.class);
 databaseManager.updateVisits(2);
 }
  66. 74.

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


    DatabaseManager databaseManager = objectGraph.get(DatabaseManager.class);
 databaseManager.updateVisits(2);
 } Exception in thread "main" java.lang.IllegalStateException: No factory for class v3.example.Database at v3.Linker.loadFactory(Linker.java:50) at v3.Linker.factoryFor(Linker.java:20) at v3.ReflectiveFactory.link(ReflectiveFactory.java:17) at v3.Linker.factoryFor(Linker.java:21) at v3.ObjectGraph.get(ObjectGraph.java:16) at v3.example.Main.main(Main.java:18)
  67. 75.

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


    objectGraph.validate(DatabaseManager.class);
 // ...
 }
  68. 76.

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


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

  69. 77.
  70. 78.

    private static void installFactories(Linker linker) {
 linker.install(PrintStream.class, ValueFactory.of(System.out));
 } 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();
 }
 }));
 }
  71. 79.

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


    objectGraph.validate(DatabaseManager.class);
 // ...
 } private static void installFactories(Linker linker) {
 linker.install(PrintStream.class, ValueFactory.of(System.out));
 }
  72. 80.

    @Provides ApiClient provideApiClient(ApiClientImpl realApiClient) {
 return realApiClient;
 } private static

    void installFactories(Linker linker) {
 linker.install(PrintStream.class, ValueFactory.of(System.out));
 }
  73. 82.

    
 public class MainModule {
 
 @Provides ApiClient provideApiClient(ApiClientImpl realApiClient)

    {
 return realApiClient;
 }
 
 
 @Provides PrintStream providePrintStream() {
 return System.out;
 }
 }
  74. 83.

    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));
 }
  75. 84.

    private static ObjectGraph buildObjectGraph(List<Class> modulesClasses) {
 Linker linker = new

    Linker();
 linker.loadModuleBindings(modulesClasses);
 return new ObjectGraph(linker);
 }
  76. 85.

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


    objectGraph.validate(DatabaseManager.class);
 // ...
 }
  77. 86.

    
 public class MainModule {
 
 @Provides ApiClient provideApiClient(ApiClientImpl realApiClient)

    {
 return realApiClient;
 }
 
 
 @Provides PrintStream providePrintStream() {
 return System.out;
 }
 }
  78. 87.

    @Module(injects = DatabaseManager.class)
 public class MainModule {
 
 @Provides ApiClient

    provideApiClient(ApiClientImpl realApiClient) {
 return realApiClient;
 }
 
 
 @Provides PrintStream providePrintStream() {
 return System.out;
 }
 }
  79. 88.
  80. 89.
  81. 90.

    public class TransactionHandler {
 
 private final Analytics analytics;
 private

    final TaxCache taxCache;
 
 private Payment paymentInFlight;
 private Order order;
 
 @Inject TransactionHandler(Analytics analytics, TaxCache taxCache) {
 this.analytics = analytics;
 this.taxCache = taxCache;
 }
 
 // ...
 }
  82. 91.
  83. 92.

    public class TransactionHandler {
 
 private final Analytics analytics;
 private

    final TaxCache taxCache;
 
 private Payment paymentInFlight;
 private Order order;
 
 @Inject TransactionHandler(Analytics analytics, TaxCache taxCache) {
 this.analytics = analytics;
 this.taxCache = taxCache;
 }
 
 // ...
 }
  84. 93.

    @Singleton public class TransactionHandler {
 
 private final Analytics analytics;


    private final TaxCache taxCache;
 
 private Payment paymentInFlight;
 private Order order;
 
 @Inject TransactionHandler(Analytics analytics, TaxCache taxCache) {
 this.analytics = analytics;
 this.taxCache = taxCache;
 }
 
 // ...
 }
  85. 95.
  86. 96.
  87. 102.

    public class ObjectGraph {
 
 Linker linker;
 
 public <T>

    T get(Class<T> key) {
 Factory<T> factory = linker.factoryFor(key);
 return factory.get();
 }
 }
  88. 103.

    public class ObjectGraph {
 
 Linker linker;
 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();
 }
 }
  89. 104.

    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;
 }
 }
  90. 105.
  91. 106.

    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());
 }
 }
  92. 107.

    public class Logger$$Factory extends Factory<Logger> {
 final Factory<PrintStream> printStreamFactory;
 


    public Logger$$Factory(Factory<PrintStream> printStreamFactory) {
 this.printStreamFactory = printStreamFactory;
 }
 
 @Override public Logger get() {
 return new Logger(printStreamFactory.get());
 }
 }
  93. 108.

    @Module(injects = DatabaseManager.class)
 public class MainModule {
 
 @Provides ApiClient

    provideApiClient(ApiClientImpl realApiClient) {
 return realApiClient;
 }
 
 
 @Provides PrintStream providePrintStream() {
 return System.out;
 }
 }
  94. 109.

    @Module
 public class MainModule {
 
 @Provides ApiClient provideApiClient(ApiClientImpl realApiClient)

    {
 return realApiClient;
 }
 
 
 @Provides PrintStream providePrintStream() {
 return System.out;
 }
 } @Component(modules = MainModule.class)
 public interface MainComponent {
 DatabaseManager databaseManager();
 }
  95. 110.

    @Component(modules = MainModule.class)
 public interface MainComponent {
 DatabaseManager databaseManager();
 }

    public class Dagger_MainComponent implements MainComponent {
 Factory<PrintStream> printStreamFactory;
 Factory<Logger> loggerFactory;
 Factory<DatabaseManager> databaseManagerFactory;
 
 Dagger_MainComponent() {
 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() {

  96. 111.

    public class Dagger_MainComponent implements MainComponent {
 Factory<PrintStream> printStreamFactory;
 Factory<Logger> loggerFactory;


    Factory<DatabaseManager> databaseManagerFactory;
 
 Dagger_MainComponent() {
 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();
 }
 }
  97. 112.

    public class Dagger_MainComponent implements MainComponent {
 Factory<PrintStream> printStreamFactory;
 Factory<Logger> loggerFactory;


    Factory<DatabaseManager> databaseManagerFactory;
 
 Dagger_MainComponent() {
 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();
 }
 }
  98. 113.
  99. 114.
  100. 115.