Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

public static void main(String... args) { ObjectGraph objectGraph = buildObjectGraph(); VisitHandler visitHandler = objectGraph.get(VisitHandler.class); visitHandler.visit(); }

Slide 6

Slide 6 text

public class ObjectGraph { public T get(Class key) { throw new UnsupportedOperationException("Not implemented"); } }

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

public static void main(String... args) { ObjectGraph objectGraph = buildObjectGraph(); VisitHandler visitHandler = objectGraph.get(VisitHandler.class); visitHandler.visit(); }

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

private static void installFactories(Linker linker) { linker.install(VisitHandler.class, new Factory() { @Override public VisitHandler get(Linker linker) { Factory counterFactory = linker.factoryFor(Counter.class); Factory 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() { @Override public Logger get(Linker linker) { Factory printStreamFactory = linker.factoryFor(PrintStream.class); PrintStream printStream = printStreamFactory.get(linker); return new Logger(printStreamFactory.get(linker)); } }); linker.install(PrintStream.class, new Factory() {

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

linker.install(Logger.class, new Factory() { @Override public Logger get(Linker linker) { Factory 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() { @Override public Counter get(Linker linker) { return new Counter(); } }); }

Slide 25

Slide 25 text

public class ValueFactory implements Factory { public static Factory 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; } }

Slide 26

Slide 26 text

Logger logger = loggerFactory.get(linker); return new VisitHandler(counter, logger); } }); linker.install(Logger.class, new Factory() { @Override public Logger get(Linker linker) { Factory 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() { @Override public Counter get(Linker linker) { return new Counter(); } }); }

Slide 27

Slide 27 text

Logger logger = loggerFactory.get(linker); return new VisitHandler(counter, logger); } }); linker.install(Logger.class, new Factory() { @Override public Logger get(Linker linker) { Factory 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() { @Override public Counter get(Linker linker) { return new Counter(); } }); }

Slide 28

Slide 28 text

Logger logger = loggerFactory.get(linker); return new VisitHandler(counter, logger); } }); linker.install(Logger.class, new Factory() { @Override public Logger get(Linker linker) { Factory 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() { @Override public Counter get(Linker linker) { return new Counter(); } })); }

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

Logger logger = loggerFactory.get(linker); return new VisitHandler(counter, logger); } }); linker.install(Logger.class, new Factory() { @Override public Logger get(Linker linker) { Factory 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() { @Override public Counter get(Linker linker) { return new Counter(); } })); }

Slide 32

Slide 32 text

private static void installFactories(Linker linker) { linker.install(VisitHandler.class, new Factory() { @Override public VisitHandler get(Linker linker) { Factory counterFactory = linker.factoryFor(Counter.class); Factory 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() { @Override public Logger get(Linker linker) { Factory 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() { @Override public Counter get(Linker linker) { return new Counter(); } })); }

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

So far ● Instantiation and its order automated

Slide 37

Slide 37 text

Good job ?

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

public interface Factory { T get(Linker linker); }

Slide 40

Slide 40 text

public abstract class Factory { public void link(Linker linker) { } public abstract T get(); }

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

private static void installFactories(Linker linker) { linker.install(VisitHandler.class, new Factory() { @Override public VisitHandler get(Linker linker) { Factory counterFactory = linker.factoryFor(Counter.class); Factory 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() { @Override public Logger get(Linker linker) { Factory 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() { @Override public Counter get(Linker linker) { return new Counter(); } })); }

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

private static void installFactories(Linker linker) { linker.install(VisitHandler.class, new Factory() { Factory loggerFactory; Factory 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() { @Override public Logger get(Linker linker) { Factory printStreamFactory = linker.factoryFor(PrintStream.class); PrintStream printStream = printStreamFactory.get(linker);

Slide 51

Slide 51 text

private static void installFactories(Linker linker) { linker.install(VisitHandler.class, new Factory() { Factory loggerFactory; Factory 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() { @Override public Logger get(Linker linker) { Factory printStreamFactory = linker.factoryFor(PrintStream.class); PrintStream printStream = printStreamFactory.get(linker);

Slide 52

Slide 52 text

private static void installFactories(Linker linker) { linker.install(VisitHandler.class, new Factory() { Factory loggerFactory; Factory 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() { @Override public Logger get(Linker linker) { Factory printStreamFactory = linker.factoryFor(PrintStream.class); PrintStream printStream = printStreamFactory.get(linker);

Slide 53

Slide 53 text

private static void installFactories(Linker linker) { linker.install(VisitHandler.class, new Factory() { Factory loggerFactory; Factory 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() { @Override public Logger get(Linker linker) { Factory printStreamFactory = linker.factoryFor(PrintStream.class); PrintStream printStream = printStreamFactory.get(linker);

Slide 54

Slide 54 text

public class Linker { private final Map, Factory>> factories = new HashMap<>(); private final Map, Factory>> linkedFactories = new HashMap<>(); public void install(Class key, Factory factory) { factories.put(key, factory); } public Factory factoryFor(Class 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) factory; } }

Slide 55

Slide 55 text

public class Linker { private final Map, Factory>> factories = new HashMap<>(); private final Map, Factory>> linkedFactories = new HashMap<>(); public void install(Class key, Factory factory) { factories.put(key, factory); } public Factory factoryFor(Class 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) factory; } }

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

So far ● Instantiation and its order automated ● Caching

Slide 58

Slide 58 text

Good job ?

Slide 59

Slide 59 text

private static void installFactories(Linker linker) { linker.install(VisitHandler.class, new Factory() { Factory loggerFactory; Factory 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() { Factory 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() { @Override public Counter get() { return new Counter(); } })); }

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

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

Slide 64

Slide 64 text

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

Slide 65

Slide 65 text

private Factory> loadFactory(Class key) { Factory> factory = factories.get(key); if (factory != null) { return factory; } Constructor 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 Constructor findAtInjectConstructor(Class type) { for (Constructor> constructor : type.getConstructors()) { if (constructor.isAnnotationPresent(Inject.class)) { return (Constructor) constructor; } } return null; }

Slide 66

Slide 66 text

private Factory> loadFactory(Class key) { Factory> factory = factories.get(key); if (factory != null) { return factory; } Constructor 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 Constructor findAtInjectConstructor(Class type) { for (Constructor> constructor : type.getConstructors()) { if (constructor.isAnnotationPresent(Inject.class)) { return (Constructor) constructor; } } return null; }

Slide 67

Slide 67 text

private Factory> loadFactory(Class key) { Factory> factory = factories.get(key); if (factory != null) { return factory; } Constructor 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 Constructor findAtInjectConstructor(Class type) { for (Constructor> constructor : type.getConstructors()) { if (constructor.isAnnotationPresent(Inject.class)) { return (Constructor) constructor; } } return null; }

Slide 68

Slide 68 text

private Factory> loadFactory(Class key) { Factory> factory = factories.get(key); if (factory != null) { return factory; } Constructor 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 Constructor findAtInjectConstructor(Class type) { for (Constructor> constructor : type.getConstructors()) { if (constructor.isAnnotationPresent(Inject.class)) { return (Constructor) constructor; } } return null; }

Slide 69

Slide 69 text

private Factory> loadFactory(Class key) { Factory> factory = factories.get(key); if (factory != null) { return factory; } Constructor 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 Constructor findAtInjectConstructor(Class type) { for (Constructor> constructor : type.getConstructors()) { if (constructor.isAnnotationPresent(Inject.class)) { return (Constructor) constructor; } } return null; }

Slide 70

Slide 70 text

private Factory> loadFactory(Class key) { Factory> factory = factories.get(key); if (factory != null) { return factory; } Constructor 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 Constructor findAtInjectConstructor(Class type) { for (Constructor> constructor : type.getConstructors()) { if (constructor.isAnnotationPresent(Inject.class)) { return (Constructor) constructor; } } return null; }

Slide 71

Slide 71 text

private Factory> loadFactory(Class key) { Factory> factory = factories.get(key); if (factory != null) { return factory; } Constructor 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 Constructor findAtInjectConstructor(Class type) { for (Constructor> constructor : type.getConstructors()) { if (constructor.isAnnotationPresent(Inject.class)) { return (Constructor) constructor; } } return null; }

Slide 72

Slide 72 text

public class ReflectiveFactory extends Factory { private final Constructor constructor; private final ArrayList> factories = new ArrayList<>(); public ReflectiveFactory(Constructor 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); } } }

Slide 73

Slide 73 text

public class ReflectiveFactory extends Factory { private final Constructor constructor; private final ArrayList> factories = new ArrayList<>(); public ReflectiveFactory(Constructor 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); } } }

Slide 74

Slide 74 text

public class ReflectiveFactory extends Factory { private final Constructor constructor; private final ArrayList> factories = new ArrayList<>(); public ReflectiveFactory(Constructor 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); } } }

Slide 75

Slide 75 text

public class ReflectiveFactory extends Factory { private final Constructor constructor; private final ArrayList> factories = new ArrayList<>(); public ReflectiveFactory(Constructor 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); } } }

Slide 76

Slide 76 text

public class ReflectiveFactory extends Factory { private final Constructor constructor; private final ArrayList> factories = new ArrayList<>(); public ReflectiveFactory(Constructor 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); } } }

Slide 77

Slide 77 text

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() {} }

Slide 78

Slide 78 text

private static void installFactories(Linker linker) { linker.install(VisitHandler.class, new Factory() { Factory loggerFactory; Factory 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() { Factory 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() { @Override public Counter get() { return new Counter(); } })); }

Slide 79

Slide 79 text

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

Slide 80

Slide 80 text

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

Slide 81

Slide 81 text

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

Slide 82

Slide 82 text

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

Slide 83

Slide 83 text

private static void installFactories(Linker linker) { linker.install(VisitHandler.class, new Factory() { Factory loggerFactory; Factory 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() { Factory 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() { @Override public Counter get() { return new Counter(); } })); } private static void installFactories(Linker linker) { linker.install(PrintStream.class, ValueFactory.of(System.out)); }

Slide 84

Slide 84 text

So far ● Instantiation and its order automated ● Caching ● No boilerplate

Slide 85

Slide 85 text

No content

Slide 86

Slide 86 text

Good job ?

Slide 87

Slide 87 text

No content

Slide 88

Slide 88 text

linker.install(VisitHandler.class, new Factory() { Factory printStreamFactory; @Override public void link(Linker linker) { printStreamFactory = linker.factoryFor(PrintStream.class); } @Override public Logger get() { return new Logger(printStreamFactory.get()); } });

Slide 89

Slide 89 text

Annotation Processing

Slide 90

Slide 90 text

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

Slide 91

Slide 91 text

public abstract class GeneratedFactory extends Factory { private final boolean singleton; public GeneratedFactory(boolean singleton) { this.singleton = singleton; } } public class Logger$$Factory extends GeneratedFactory { public Logger$$Factory() { super(false); } }

Slide 92

Slide 92 text

private Factory> loadFactory(Class key) { Factory> factory = factories.get(key); if (factory != null) { return factory; } Constructor 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); }

Slide 93

Slide 93 text

public class Linker { private Factory> loadFactory(Class 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); } }

Slide 94

Slide 94 text

public class Linker { private Factory> loadFactory(Class 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); } }

Slide 95

Slide 95 text

public abstract class GeneratedFactory extends Factory { public static Factory loadFactory(Class key) { String generatedClass = key.getName() + "$$Factory"; try { Class> factoryClass = (Class>) Class.forName(generatedClass); GeneratedFactory 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; } }

Slide 96

Slide 96 text

public abstract class GeneratedFactory extends Factory { public static Factory loadFactory(Class key) { String generatedClass = key.getName() + "$$Factory"; try { Class> factoryClass = (Class>) Class.forName(generatedClass); GeneratedFactory 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; } }

Slide 97

Slide 97 text

public abstract class GeneratedFactory extends Factory { public static Factory loadFactory(Class key) { String generatedClass = key.getName() + "$$Factory"; try { Class> factoryClass = (Class>) Class.forName(generatedClass); GeneratedFactory 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; } }

Slide 98

Slide 98 text

So far ● Instantiation and its order automated ● Caching ● No boilerplate ● No reflection

Slide 99

Slide 99 text

BETA

Slide 100

Slide 100 text

Good job ?

Slide 101

Slide 101 text

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

Slide 102

Slide 102 text

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)

Slide 103

Slide 103 text

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 get(Class key) { Factory factory = linker.factoryFor(key); return factory.get(); } public void validate(Class key) { linker.factoryFor(key); } }

Slide 104

Slide 104 text

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 get(Class key) { Factory factory = linker.factoryFor(key); return factory.get(); } public void validate(Class key) { linker.factoryFor(key); } }

Slide 105

Slide 105 text

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

Slide 106

Slide 106 text

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

Slide 107

Slide 107 text

Annotation Processing

Slide 108

Slide 108 text

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

Slide 109

Slide 109 text

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

Slide 110

Slide 110 text

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

Slide 111

Slide 111 text

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

Slide 112

Slide 112 text

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

Slide 113

Slide 113 text

private static ObjectGraph buildObjectGraph(List 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)); }

Slide 114

Slide 114 text

public static void main(String... args) { ObjectGraph objectGraph = buildObjectGraph(); objectGraph.validate(DatabaseManager.class); // … }

Slide 115

Slide 115 text

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

Slide 116

Slide 116 text

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

Slide 117

Slide 117 text

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

Slide 118

Slide 118 text

So far ● Instantiation and its order automated ● Caching ● No boilerplate ● No reflection ● Verification at compile time

Slide 119

Slide 119 text

No content

Slide 120

Slide 120 text

Good job ?

Slide 121

Slide 121 text

So far ● Instantiation and its order automated ● Caching ● No boilerplate ● No reflection ● Verification at compile time ● Scope? ● Great performance? ● Lazy computation?

Slide 122

Slide 122 text

2

Slide 123

Slide 123 text

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

Slide 124

Slide 124 text

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