Slide 1

Slide 1 text

Guice Breakfast meeting, 28 April 2010 Stein Magnus Jodal

Slide 2

Slide 2 text

Spring Framework according to random guy at Twitter Spring: java+xml > java! Sounds dumb and IS dumb. Protects you from: dependencies!; no protection from: 50% of your code in f’ing xml. :( @jaykreps, 2010-03-31

Slide 3

Slide 3 text

Spring Framework modules according to Wikipedia Inversion of Control container (IoC) Aspect-oriented programming (AOP) Data access Transaction management Model-view-controller web framework Remote Access framework Convention-over-configuration (Roo) Batch processing Authentication and authorization (Acegi) Remote Management (JMX) Messaging (JMS) Testing support classes

Slide 4

Slide 4 text

Guice “lightweight dependency injection framework“ Java 5 and up Created by Google Apache 2.0 license All configuration in code Type-safe. Supports generics and annotations Guice does approximately one sixth of what Spring does (IoC and AOP), . . . but it does its small part well, . . . and without all the XML

Slide 5

Slide 5 text

Dependency Injection in a Context Dependency injection is one way to achieve the software architecture principle Inversion of Control (IoC) .NET typically uses the S L pattern Another way, popular in Java, is the F pattern

Slide 6

Slide 6 text

Service interface public i n t e r f a c e BillingService { / * * * Attempts to charge the order to the c r e d i t card . Both * successful and f a i l e d transactions w i l l be recorded . * * @return a receipt of the transaction . I f the charge was * successful , the receipt w i l l be successful . Otherwise , the * receipt w i l l contain a decline note describing why the * charge f a i l e d . * / Receipt chargeOrder ( PizzaOrder order , CreditCard creditCard ) ; } Examples taken (and slightly modified) from http://code.google.com/p/google-guice/wiki/Motivation

Slide 7

Slide 7 text

Direct constructor calls public class RealBillingService implements BillingService { public Receipt chargeOrder ( PizzaOrder order , CreditCard creditCard ) { CreditCardProcessor processor = new PaypalCreditCardProcessor ( ) ; TransactionLog transactionLog = new DatabaseTransactionLog ( ) ; ChargeResult result = processor . charge ( creditCard , order . getAmount ( ) ) ; transactionLog . logChargeResult ( result ) ; return result . wasSuccessful ( ) ? Receipt . forSuccessfulCharge ( order . getAmount ( ) ) : Receipt . forDeclinedCharge ( result . getDeclineMessage ( ) ) ; } } Note the use of new. How do you test this?

Slide 8

Slide 8 text

Factories public class RealBillingService implements BillingService { public Receipt chargeOrder ( PizzaOrder order , CreditCard creditCard ) { CreditCardProcessor processor = CreditCardProcessorFactory . getInstance ( ) ; TransactionLog transactionLog = TransactionLogFactory . getInstance ( ) ; ChargeResult result = processor . charge ( creditCard , order . getAmount ( ) ) ; transactionLog . logChargeResult ( result ) ; return result . wasSuccessful ( ) ? Receipt . forSuccessfulCharge ( order . getAmount ( ) ) : Receipt . forDeclinedCharge ( result . getDeclineMessage ( ) ) ; } } We replaced constructor calls with factories. Is it better?

Slide 9

Slide 9 text

Factories It is now possible to test the class without charging credit cards for real money. We “just” need to:

Slide 10

Slide 10 text

Factories Add one of these for every dependency you need. public class CreditCardProcessorFactory { private s t a t i c CreditCardProcessor instance ; public s t a t i c void setInstance ( CreditCardProcessor ← creditCardProcessor ) { instance = creditCardProcessor ; } public s t a t i c CreditCardProcessor getInstance ( ) { i f ( instance == n u l l ) { throw new IllegalStateException ( " CreditCardProcessorFactory not i n i t i a l i z e d . " + " Did you forget to c a l l setInstance ( ) ?" ) ; } return instance ; } }

Slide 11

Slide 11 text

Factories And remember to setup and teardown everything in each test case. public class RealBillingServiceTest { / / . . . f i e l d s here . . . @Before public void setUp ( ) { TransactionLogFactory . setInstance ( inMemoryTransactionLog ) ; CreditCardProcessorFactory . setInstance ( fakeCreditCardProcessor ) ; } @After public void tearDown ( ) { TransactionLogFactory . setInstance ( n u l l ) ; CreditCardProcessorFactory . setInstance ( n u l l ) ; } / / . . . tests here . . . }

Slide 12

Slide 12 text

Factories Factories add lots of boilerplate. Let’s not.

Slide 13

Slide 13 text

Manual Dependency Injection public class RealBillingService implements BillingService { private f i n a l CreditCardProcessor processor ; private f i n a l TransactionLog transactionLog ; public RealBillingService ( CreditCardProcessor processor , TransactionLog transactionLog ) { t h i s . processor = processor ; t h i s . transactionLog = transactionLog ; } public Receipt chargeOrder ( PizzaOrder order , CreditCard ← creditCard ) { ChargeResult result = processor . charge ( creditCard , order . ← getAmount ( ) ) ; transactionLog . logChargeResult ( result ) ; / / . . . } }

Slide 14

Slide 14 text

Manual Dependency Injection public class RealBillingServiceTest { / / . . . private f i n a l InMemoryTransactionLog transactionLog = new InMemoryTransactionLog ( ) ; private f i n a l FakeCreditCardProcessor creditCardProcessor = new FakeCreditCardProcessor ( ) ; @Test public void successfulCharge ( ) { RealBillingService billingService = new RealBillingService ( creditCardProcessor , transactionLog ) ; Receipt receipt = billingService . chargeOrder ( order , ← creditCard ) ; assertTrue ( receipt . hasSuccessfulCharge ( ) ) ; } }

Slide 15

Slide 15 text

Manual Dependency Injection What’s the status now? No factories No setup and teardown in tests Easy injection of dependencies through the constructor It’s testable!

Slide 16

Slide 16 text

Dependency Injection with Guice Create a module to tell Guice what implementation to use for each interface. public class BillingModule extends AbstractModule { @Override protected void configure ( ) { bind ( TransactionLog . class ) . to ( DatabaseTransactionLog . class ) ; bind ( CreditCardProcessor . class ) . to ( PaypalCreditCardProcessor . class ) ; bind ( BillingService . class ) . to ( RealBillingService . class ) ; } } If you only have one implementation in your class path, Guice will choose that one for you automatically.

Slide 17

Slide 17 text

Dependency Injection with Guice public class RealBillingService implements BillingService { private f i n a l CreditCardProcessor processor ; private f i n a l TransactionLog transactionLog ; @Inject public RealBillingService ( CreditCardProcessor processor , TransactionLog transactionLog ) { t h i s . processor = processor ; t h i s . transactionLog = transactionLog ; } public Receipt chargeOrder ( PizzaOrder order , CreditCard ← creditCard ) { ChargeResult result = processor . charge ( creditCard , order . ← getAmount ( ) ) ; transactionLog . logChargeResult ( result ) ; / / . . . } }

Slide 18

Slide 18 text

Dependency Injection with Guice Finally, get the injector from Guice, and ask it for an instance of any interface or class which Guice has bound to an implementation. public s t a t i c void main ( String [ ] args ) { Injector injector = Guice . createInjector (new BillingModule ( ) ) ; BillingService billingService = injector . getInstance (← BillingService . class ) ; / / . . . }

Slide 19

Slide 19 text

Dependency Injection with Guice Guice also supports . . . setter injection (@Inject the setter) field injection (@Inject the field) binding to instances creating new instances whenever needed (default) reusing instances within a unit of work (e.g. HTTP request) reusing instances forever (singletons) providing short-lived instances to more long-lived objects through Providers and more . . .

Slide 20

Slide 20 text

Why Dependency Injection? Loosen the coupling between a consumer object and its dependencies Move the decision of what implementation of a dependency to use out of the consuming code Move the responsibility of managing the life cycle of dependencies from the consumer to a dependency injector Improve testability Reduce the amount of boilerplate code for creating objects Boilerplate means tedious Tedious means error prone

Slide 21

Slide 21 text

Why NOT (automatic) Dependency Injection? Object instantiation and initialization happening “somewhere else” may seem “magic” to some developers Needs to understand both the configuration and the code to understand the application The configuration is often in XML, which usually means that you have to maintain it manually when refactoring But not in Guice

Slide 22

Slide 22 text

Guice resources http://code.google.com/p/google-guice/ Database persistence & transaction mangement? See warp-persist at http://www.wideplay.com/guicewebextensions2 JUnit test runner with Guice support? http://cowwoc.blogspot.com/2008/10/ integrating-google-guice-into-junit4.html

Slide 23

Slide 23 text

Try it! No project is too small for some juicy Guice!