36
Dagger 2. Right way to do Dependency Injections by Anton Minashkin

Anton Minashkin Dagger 2 light

Embed Size (px)

Citation preview

Page 1: Anton Minashkin Dagger 2 light

Dagger 2. Right way to do Dependency Injections

by Anton Minashkin

Page 2: Anton Minashkin Dagger 2 light

Usual JAVA codepublic class Payroll { ...

public long getWithholding(long payInDollars) { ... return withholding; }

public long getAfterTaxPay(Employee employee) { long basePay = EmployeeDatabase.getInstance() .getBasePay(employee); long withholding = getWithholding(basePay);

return basePay - withholding; }}

Page 3: Anton Minashkin Dagger 2 light

Usual JAVA codepublic class Payroll { ...

public long getWithholding(long payInDollars) { ... return withholding; }

public long getAfterTaxPay(Employee employee) { long basePay = EmployeeDatabase.getInstance() .getBasePay(employee); long withholding = getWithholding(basePay);

return basePay - withholding; }}

Page 4: Anton Minashkin Dagger 2 light

Usual JAVA codepublic class Payroll { ...

public long getWithholding(long payInDollars) { ... return withholding; }

public long getAfterTaxPay(Employee employee) { long basePay = new EmployeeDatabase() .getBasePay(employee); long withholding = getWithholding(basePay);

return basePay - withholding; }}

Page 5: Anton Minashkin Dagger 2 light

What is DI?In software engineering, dependency injection is a software design pattern that implements inversion of control for software libraries.

Page 6: Anton Minashkin Dagger 2 light

What is DI?

Page 7: Anton Minashkin Dagger 2 light

Say “Hi!” to DIpublic class Payroll { ... EmployeeDatabase mEmployeeDatabase; public Payroll(EmployeeDatabase employeeDatabase) { mEmployeeDatabase = employeeDatabase; } public long getWithholding(long payInDollars) { ... return withholding; } public long getAfterTaxPay(Employee employee) { long basePay = mEmployeeDatabase.getBasePay(employee); long withholding = getWithholding(basePay);

return basePay - withholding; }}

Page 8: Anton Minashkin Dagger 2 light

Say “Hi!” to DIpublic class Payroll { ... EmployeeDatabase mEmployeeDatabase; public Payroll(EmployeeDatabase employeeDatabase) { mEmployeeDatabase = employeeDatabase; } public long getWithholding(long payInDollars) { ... return withholding; } public long getAfterTaxPay(Employee employee) { long basePay = mEmployeeDatabase.getBasePay(employee); long withholding = getWithholding(basePay);

return basePay - withholding; }}

Page 9: Anton Minashkin Dagger 2 light

...but!Was:new Payroll().getAfterTaxPay(employee);

Now:new Payroll(EmployeeDatabase.getInstance()) .getAfterTaxPay(employee);

Page 10: Anton Minashkin Dagger 2 light

...but!Was:new Payroll().getAfterTaxPay(employee);

Now:new Payroll(EmployeeDatabase.getInstance()) .getAfterTaxPay(employee);

Page 11: Anton Minashkin Dagger 2 light

Java! To the rescue!

JSR-330

Page 12: Anton Minashkin Dagger 2 light

JSR-330public class Payroll { ... @Inject public Payroll(EmployeeDatabase employeeDatabase) { mEmployeeDatabase = employeeDatabase; }...}

ORpublic class Payroll { ... @Inject EmployeeDatabase mEmployeeDatabase; ...}

Page 13: Anton Minashkin Dagger 2 light

DI frameworks

● Google Guice● Spring DI● Java EE6 CDI● Dagger● etc.

Page 14: Anton Minashkin Dagger 2 light

DI frameworks

● Google Guice● Spring DI● Java EE6 CDI● Dagger● etc.

Page 15: Anton Minashkin Dagger 2 light

Dagger 2. History

Developed by SquareAdopted by Google (Dagger 2)

Page 16: Anton Minashkin Dagger 2 light

Dagger 2. Main features

● Android friendly● JSR-330● Compile-time DI validation● Full stack code generation● User mimic code● Easy to debug & understand

Page 17: Anton Minashkin Dagger 2 light

Dagger 2. APIclass Thermosiphon implements Pump { private final Heater heater;

@Inject Thermosiphon(Heater heater) { this.heater = heater; }

...}

Page 18: Anton Minashkin Dagger 2 light

Dagger 2. APIclass CoffeeMaker { @Inject Heater heater; @Inject Pump pump;

...}

Page 19: Anton Minashkin Dagger 2 light

Dagger 2. API@Moduleclass DripCoffeeModule { @Provides Heater provideHeater() { return new ElectricHeater(); }

@Provides Pump providePump(Thermosiphon pump) { return pump; }}

Page 20: Anton Minashkin Dagger 2 light

Dagger 2. API@Component(modules = DripCoffeeModule.class)interface CoffeeShop { CoffeeMaker maker();}

Page 21: Anton Minashkin Dagger 2 light

Dagger 2. APICoffeeShop coffeeShop = DaggerCoffeeShop.builder() .dripCoffeeModule(new DripCoffeeModule()) .build();

...

CoffeeShop coffeeShop = DaggerCoffeeShop.create();

Page 22: Anton Minashkin Dagger 2 light

Dagger 2. APIpublic class CoffeeApp { public static void main(String[] args) { CoffeeShop coffeeShop = DaggerCoffeeShop.create(); coffeeShop.maker().brew(); }}

Page 23: Anton Minashkin Dagger 2 light

Dagger 2. Scope@Provides @Singleton Heater provideHeater() { return new ElectricHeater();}

Page 24: Anton Minashkin Dagger 2 light

Dagger 2. Lazyclass GridingCoffeeMaker { @Inject Lazy<Grinder> lazyGrinder;

public void brew() { while (needsGrinding()) { // Grinder created once on first call to .get() and cached. lazyGrinder.get().grind(); } }}

Page 25: Anton Minashkin Dagger 2 light

Dagger 2. Provider Injectionclass BigCoffeeMaker { @Inject Provider<Filter> filterProvider;

public void brew(int numberOfPots) { ... for (int p = 0; p < numberOfPots; p++) { maker.addFilter(filterProvider.get()); //new filter every time. maker.addCoffee(...); maker.percolate(); ... } }}

Page 26: Anton Minashkin Dagger 2 light

Dagger 2. Qualifiers@Qualifier@Documented@Retention(RUNTIME)public @interface Named { String value() default "";}

Page 27: Anton Minashkin Dagger 2 light

Dagger 2. Qualifiersclass ExpensiveCoffeeMaker { @Inject @Named("water") Heater waterHeater; @Inject @Named("hot plate") Heater hotPlateHeater; ...}

Page 28: Anton Minashkin Dagger 2 light

Dagger 2. Qualifiers@Provides @Named("hot plate") Heater provideHotPlateHeater() { return new ElectricHeater(70);}

@Provides @Named("water") Heater provideWaterHeater() { return new ElectricHeater(93);}

Page 29: Anton Minashkin Dagger 2 light

Dagger 2. Compile-time validation@Moduleclass DripCoffeeModule { @Provides Heater provideHeater(Executor executor) { return new CpuHeater(executor); }}...

[ERROR] COMPILATION ERROR :[ERROR] error: java.util.concurrent.Executor cannot be provided without an @Provides-annotated method.

Page 30: Anton Minashkin Dagger 2 light

Dagger 2. Generated code@Override public DataManager get() { DataManager provided = module.provideDataManager(authApiProvider.get(), articleApiProvider.get(), commentsApiProvider.get()); if (provided == null) { throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method"); } return provided; }

public static Factory<DataManager> create(DataManagerModule module, Provider<AuthApi> authApiProvider, Provider<ArticleApi> articleApiProvider, Provider<CommentApi> commentApiProvider) { return new DataManagerModule_ProvideDataManagerFactory(module, authApiProvider, articleApiProvider, commentApiProvider); }

Page 31: Anton Minashkin Dagger 2 light

Dagger 2. Debugging

Here should be example of Guice stacktrace:VERY-VERY-BAD-STACKTRACE

And here is Dagger stacktrace:Mmmm… What a lovely stacktrace!

Page 32: Anton Minashkin Dagger 2 light

Dagger 2. What should I inject?

● Anything that has constructor parameters● Anything that is out of local scope● Infrastructure● Anything that is shared between >1 objects● Diferent obj-graphs for diferent flavors

Page 33: Anton Minashkin Dagger 2 light

Dagger 2. Where should I inject?public class MyApp extends Application {@Overridepublic void onCreate() {registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {... @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) { inject(activity); }...});}

Page 34: Anton Minashkin Dagger 2 light

Dagger 2

Example

Page 35: Anton Minashkin Dagger 2 light

Dagger 2

Questions?

Page 36: Anton Minashkin Dagger 2 light

RTFM!

http://google.github.io/dagger/https://youtu.be/oK_XtfXPkqw

[email protected]