Dependency Injection with Guice Technion – Institute of Technology 236700 1 Author: Gal Lalouche - Technion 2016 ©

Slides:



Advertisements
Similar presentations
Spring, Hibernate and Web Services 13 th September 2014.
Advertisements

State of the Art Testability By Chad Parry. Background  The industry offers great advice on testability  Projects that follow that advice look different.
Design Patterns Copyright © Vyacheslav Mukhortov, Nikita Nyanchuk-Tatarskiy, Copyright © INTEKS LLC,
March Ron McFadyen1 Singleton pattern Singleton is designed to restrict instantiation of a class to one (or a few) objects. Useful when exactly.
ECE450 - Software Engineering II1 ECE450 – Software Engineering II Today: Design Patterns VI Composite, Iterator, and Visitor Patterns.
+ Informatics 122 Software Design II Lecture 8 Emily Navarro Duplication of course material for any commercial purpose without the explicit written permission.
CVSQL 2 The Design. System Overview System Components CVSQL Server –Three network interfaces –Modular data source provider framework –Decoupled SQL parsing.
Creational Patterns Making Objects The Smart Way Brent Ramerth Abstract Factory, Builder.
Copyright © The McGraw-Hill Companies, Inc. Permission required for reproduction or display. The Factory Method Design Pattern (1) –A creational design.
Dependency Injection and Model-View-Controller. Overview Inversion of Control Model-View-Controller.
Starting Chapter 4 Starting. 1 Course Outline* Covered in first half until Dr. Li takes over. JAVA and OO: Review what is Object Oriented Programming.
Programming Languages and Paradigms Object-Oriented Programming.
CSM-Java Programming-I Spring,2005 Introduction to Objects and Classes Lesson - 1.
Design Patterns.
CSM-Java Programming-I Spring,2005 Objects and Classes Overview Lesson - 1.
Introduction to Object Oriented Programming. Object Oriented Programming Technique used to develop programs revolving around the real world entities In.
1 Chapter 10: Data Abstraction and Object Orientation Aaron Bloomfield CS 415 Fall 2005.
Programming in Java Unit 2. Class and variable declaration A class is best thought of as a template from which objects are created. You can create many.
Creational Patterns CSE301 University of Sunderland Harry R Erwin, PhD.
CSCI-383 Object-Oriented Programming & Design Lecture 13.
Creative Commons Attribution- NonCommercial-ShareAlike 2.5 License Sakai Programmer's Café Sakai Montreal CRIM Workshop Introduction to Spring Framework,
Tu sca ny 1 Extending The Tuscany Java SCA Runtime 21 August 2006.
Test Isolation and Mocking Technion – Institute of Technology Author: Gal Lalouche © 1 Author: Gal Lalouche - Technion 2015 ©
Dependency Injection Technion – Institute of Technology Author: Gal Lalouche - Technion 2015 ©
Partitioning Patterns How to partition complex actors and concepts into multiple classes. Layered Initialization Filter Composite.
The Factory Patterns SE-2811 Dr. Mark L. Hornick 1.
OOP: Encapsulation,Abstraction & Polymorphism. What is Encapsulation Described as a protective barrier that prevents the code and data being randomly.
Refactoring for Testability (or how I learned to stop worrying and love failing tests) Presented by Aaron Evans.
Object-Oriented Design CSC 212. Announcements This course is speeding up and we are starting new material. Please see me if you feel this is going too.
Objects & Dynamic Dispatch CSE 413 Autumn Plan We’ve learned a great deal about functional and object-oriented programming Now,  Look at semantics.
CSSE501 Object-Oriented Development. Chapter 4: Classes and Methods  Chapters 4 and 5 present two sides of OOP: Chapter 4 discusses the static, compile.
The Strategy Pattern SE-2811 Dr. Mark L. Hornick 1 Class 1-2.
Patterns in programming1. 2 What are patterns? Answers to common design problems. A language used by developers –To discuss answers to design problems.
Design Patterns -- Omkar. Introduction  When do we use design patterns  Uses of design patterns  Classification of design patterns  Creational design.
SE-2811 Software Component Design Week 1, Day 2 (and 1-3 and 2-1) SE-2811 Dr. Josiah Yoder Slide style: Dr. Hornick 1.
Magnus
Design Patterns Definition:
Programming with Java © 2002 The McGraw-Hill Companies, Inc. All rights reserved. 1 McGraw-Hill/Irwin Chapter 5 Creating Classes.
Inheritance Revisited Other Issues. Multiple Inheritance Also called combination--not permitted in Java, but is used in C++ Also called combination--not.
Object Oriented Programming
The Strategy Pattern SE-2811 Dr. Mark L. Hornick 1.
Design Patterns Software Engineering CS 561. Last Time Introduced design patterns Abstraction-Occurrence General Hierarchy Player-Role.
Dependency Injection Frameworks Technion – Institute of Technology Author: Assaf Israel - Technion 2013 ©
The State Pattern (Behavioral) ©SoftMoore ConsultingSlide 1.
The Factory Method Pattern (Creational) ©SoftMoore ConsultingSlide 1.
Advanced Object-oriented Design Patterns Creational Design Patterns.
Principles of Object Oriented Design
Author: DoanNX Time: 45’.  OOP concepts  OOP in Java.
Abstract Factory Pattern Jiaxin Wang CSPP Winter 2010.
COMPOSITE PATTERN NOTES. The Composite pattern l Intent Compose objects into tree structures to represent whole-part hierarchies. Composite lets clients.
Test Isolation and Mocking Technion – Institute of Technology Author: Gal Lalouche © 1 Author: Gal Lalouche - Technion 2016 ©
Copyright © Jim Fawcett Spring 2017
Abstract Factory Pattern
Design Patterns II Technion – Institute of Technology
How to be a Good Developer
MPCS – Advanced java Programming
Test Isolation and Mocking
Low Budget Productions, LLC
Factory Patterns 1.
Inheritance and Polymorphism
Design Patterns I Technion – Institute of Technology
Object-Oriented Programming & Design Lecture 14 Martin van Bommel
Abstract Factory Pattern
Intent (Thanks to Jim Fawcett for the slides)
Advanced Java Programming
Ms Munawar Khatoon IV Year I Sem Computer Science Engineering
Tuesday Brown Bag Inversion of Control with Howard Abrams
Structural Patterns: Adapter and Bridge
Designing For Testability
Threads and concurrency / Safety
Presentation transcript:

Dependency Injection with Guice Technion – Institute of Technology Author: Gal Lalouche - Technion 2016 ©

Class decoupling Consider the following interface: A highly coupled implementation: public interface CreditCardProcessor { void process(PizzaOrder order, CreditCard cc); } class BillingService { private CreditCardProcessor p = new VisaProcessor(); public void chargeOrder(PizzaOrder o, CreditCard cc) { p.process(o, cc); … } 2 Author: Gal Lalouche - Technion 2016 ©

Class decoupling (cont.) What’s the problem? We used interfaces! new always applies dependency/coupling! Although we use interfaces, the implementation is highly coupled with VisaProcessor It is much harder to test using real dependencies How can we replace it with mocks? Solution Pass collaborators (dependencies) to the object This is called Dependency Injection 3 Author: Gal Lalouche - Technion 2016 ©

DI – Constructors We can pass the object at the construction of the object Dependencies are injected upon object instantiation Object is always in a correct state Class can be immutable We can implement default behavior using a default constructor We can use constructor injection to provide a default constructor in an inheriting class We saw this when we discussed about using OOP in tests: we injected the actual object under test to the parent constructor Author: Gal Lalouche - Technion 2016 © 4 public class BillingService { private final CreditCardProcessor processor; public BillingService(CreditCardProcessor p) { processor = p; }

Factories What if we actually want to create objects in our class? new applies dependency/coupling If we could override constructors like in Smalltalk/Squeak… We could fake it by passing a “constructor- interface”, called an Abstract Factory This is an example of favouring composition over inheritance Author: Gal Lalouche - Technion 2016 © 5

Abstract Factory Pattern 6 Processor process(PizzaOrder, CreditCard) ProcessorFactory create(): CreditCardProcessor VisaProcessorFactory create(): CreditCardProcessor VisaProcessor process(PizzaOrder, CreditCard) > Author: Gal Lalouche - Technion 2016 © > implements

Abstract Factory – Participants To change the dependencies, simply send a new factory: Author: Gal Lalouche - Technion 2016 © 7 public class VisaProcessorFactory implements ProcessorFactory { public VisaProcessor create() { return new VisaProcessor(); } public class PayPalProcessorFactory implements ProcessorFactory { public PayPalProcessor create() { return new PayPalProcessor(); } public class MockProcessorFactory implements ProcessorFactory { public MockProcessor create() { return new MockProcessor(); }

Abstract Factory – Client Client: Author: Gal Lalouche - Technion 2016 © 8 class BillingService { private final ProcessorFactory pf; public BillingService(ProcessorFactory pf) { this.pf = pf; } public void chargeOrder(PizzaOrder o, CreditCard cc) { Processor p = pf.create(); p.process(o, cc); … }

Guice A Dependency Injection framework Author: Gal Lalouche - Technion 2016 © 9

Dependency Injection – Drawbacks What happens when we need to perform deep injections with no defaults? Consider the following simple design: A is dependent on B, which is dependent on C, which is dependent on D … In order to create an instance of A, we need to inject it with an instance of B, which needs to be injected with an instance of C which needs to be injected with an instance of D … A a = new AImpl(new BImpl(new CImpl(new DImpl()))); What happens if we have parallel dependencies? e.g., one for local database, another for cloud, one for development It is hard to wire everything up without mistakes We could just put everything in a single Abstract Factory… …but that breaks encapsulation Author: Gal Lalouche - Technion 2016 © 10

Dependency Injection Frameworks Completely separate object configuration from creation, allowing for cleaner code Can inject recursively Easy to manage parallel instantiations Author: Gal Lalouche - Technion 2016 © 11

Guice – Supplier Supplier code (using can be applied to: Constructors Methods All methods annotated Inject will be invoked after the object’s instantiation Fields (not recommended) Author: Gal Lalouche - Technion 2016 © 12 class MyBillingService implements BillingService { private final CreditCardProcessor public MyBillingService(CreditCardProcessor p) { processor = p; } … } That’s it!

Guice – Complex Dependencies Dependencies can also be complex to create: BankAccount may have dependencies of its own TxApprover may be an interface Author: Gal Lalouche - Technion 2016 © 13 class VisaCreditCardProcessor implements CreditCardProcessor { private final BankAccount account; private final TxApprover public VisaCreditCardProcessor(BankAccount a, TxApprover t) { account = a; txApprover = t; } … }

Guice – Module Dependencies are described in a separate Module class: Client code is now: Guice will recursively build the requested binding objects In this case a MyBillingService object will be created with DatabaseTxLog and a VisaProcessor Author: Gal Lalouche - Technion 2016 © 14 public class BillingModule extends AbstractModule protected void configure() { bind(CreditCardProcessor.class).to(VisaCreditCardProcessor.class); bind(TxApprover.class).to(VisaIsraelTxApprover.class); bind(BillingService.class).to(MyBillingService.class); } Injector injector = Guice.createInjector(new BillingModule()); BillingService billingService = injector.getInstance(BillingService.class);

Factories with provider s How do we pass factories? Naïve solution: simply inject an AbstractFactory We have to create an explicit VisaProcessorFactory class to bind to We bind both to VisaProcessor and VisaProcessorFactory ; that’s not very DRY… Author: Gal Lalouche - Technion 2016 © 15 class MyBillingService implements BillingService public MyBillingService(CreditCardProcessorFactory pf) { this.factory = pf; } }… // module: bind(CreditCardProcessor.class).to(VisaProcessor.class); bind(CreditCardProcessorFactory.class).to(VisaProcessorFactory.class);

Factories with provider s (cont.) Using providers achieves just that! We don’t have to bind the provider explicitly, since we already bound VisaProcessor This makes the Guice injector instance in essence a FactoryFactory, but it is okay in this case because we don’t need any extra code to support it! Author: Gal Lalouche - Technion 2016 © 16 class MyBillingService implements BillingService public MyBillingService(Provider pf) { this.factory = pf; } }… // module: bind(CreditCardProcessor.class).to(VisaProcessor.class);

Outcome What we’ve achieved? Both client and supplier are decoupled from implementation details All dependency logic is executed at runtime and is contained in Modules A module encapsulates all creation logic in our program Testing & Mocking is easy – since we’re essentially using constructor injection, we can ignore Guice in our tests if we want Side-note: Other DI frameworks (e.g. Spring) use XML files to define dependencies This enables changing the code’s behavior without recompiling But it also has its disadvantages (e.g. it’s less type safe) Author: Gal Lalouche - Technion 2016 © 17

Dependency Injection – Is it really that important? If we want to write real units tests, then we have to isolate our units If we want to isolate our units, then we have to use mocks If we want to use mocks, we have to inject them somehow But we aren’t doing it (just) for the tests! If we use dependency injection, our code is less coupled, more modular, robust, reusable, cohesive, cleaner and DRYer. Remember, Testable Code Good Code! Author: Gal Lalouche - Technion 2016 © 18 Unit Tests Mock objects Dependency Injection

Don’t over-design A little coupling is okay You should use injection for service objects, and new for data objects generally speaking, it’s okay to use new ArrayList<>() If we replaced every field with a factory our code would blow up Know when to use constructor dependency injection, and when you need a factory Guice can make debugging much harder… Remember, the creational logic needs to be decided somewhere Be careful of creating FactoryFactory ! Author: Gal Lalouche - Technion 2016 © 19

Appendix Guice advanced binding Can bind concrete types by: Type Name Annotation Can bind to: A class (new instance every time) An object (a specific instance) Generic classes Author: Gal Lalouche - Technion 2016 © 20

Annotation binding – annotations Binding to annotated class: Persistent TransactionLogs should bind to SqlTxLog Un-persistent TransactionLogs should bind to StringTxLog Author: Gal Lalouche - Technion 2016 © 21 public class BillingModule extends AbstractModule protected void configure() { bind(TransactionLog.class).to(StringTxLog.class); bind(TransactionLog.class).annotatedWith(Persistent.class).to(SqlTxLog.class); } public class PersistentLogger public TransactionLog l) { this.l = l; }

Binding constants We can use an annotation “shortcut” Bind to specific constant object (instantiated only once) Author: Gal Lalouche - Technion 2016 © 22 class SqlTxLog public URL″) String timeout seconds″) Integer timeout) { … } } public class SqlTxLogModule extends AbstractModule protected void configure() { bind(String.class).annotatedWith(Names.named( " JDBC URL")).toInstance( " jdbc:mysql://localhost/pizza"); bind(Integer.class).annotatedWith(Names.named(″login timeout seconds”)).toInstance(10); }

More on Binding to Instance There are two ways to bind an instance: Using.toInstance passing an instance Using.to(SomeClass.class).in(Singleton.class) A single instance is created by Guice Dependencies are injected according to the Module We can also on the bound class Author: Gal Lalouche - Technion 2016 © 23 bind(SqlConnection.class).toInstance(new SqlConnection()); // eager bind(BillingService.class).to(MyBillingService.class).in(Singleton.class); // lazy

Creational logic If we have some non-trivial creational logic we can write it in method in the Module If this method receives any arguments they will be injected We can also annotate the return type Author: Gal Lalouche - Technion 2016 © 24 public class MyPaymentModule extends AbstractModule protected void configure() { … // will be provided to dependencies annotated TransactionLog URL″) String conURL) { DatabaseTxLog transactionLog = new DatabaseTxLog(); transactionLog.setJdbcUrl(conURL); transactionLog.setThreadPoolSize(30); return transactionLog; } }

Binding Generics Binding generics is complicated by type erasure Binding classes with generic dependencies: Binding generic classes: Author: Gal Lalouche - Technion 2016 © 25 class A public A(List list) {…} } … bind(new TypeLiteral >(){}).to(new TypeLiteral >(){}); … injector.getInstance(A.class); // A will be injected an ArrayList class B public B(List list) {…} } … bind(new TypeLiteral >(){}).to(new TypeLiteral >(){}); … injector.getInstance(new Key >(){}); // B will be injected an ArrayList