Google Guice Kirill Afanasjev Software Architect jug.lv Riga, Latvia
Google Guice
Kirill AfanasjevSoftware Architect
jug.lvRiga, Latvia
Overview
Dependency Injection Why Guice Getting Guice Using Guice Advanced Guice
Code without DI
public void sendButtonClicked() {
String text = messageArea.getText();
Validator validator = new MailValidator();
validator.validate(text);
MailSender sender = new MailSender();
sender.send(text);
}
Using factories
public void sendButtonClicked() {
String text = messageArea.getText();
Validator validator = ValidatorFactory.get();
validator.validate(text);
MailSender sender = SenderFactory.get();
sender.send(text);
}
Testable now
public void testSendButton() {
MockSender mockSender = new MockSender();
SenderFactory.setInstance(mockSender);
MailForm form = new MailForm();
form.getMessageArea().setText("Some text");
form.sendButtonClicked();
assertEquals("Some text", mockSender.getSentText());
SenderFactory.clearInstance();
}
Well, not really
public void testSendButton() {
MockSender mockSender = new MockSender();
SenderFactory.setInstance(mockSender);
try {
MailForm form = new MailForm();
form.getMessageArea().setText("Some text");
form.sendButtonClicked();
assertEquals("Some text", mockSender.getSentText());
} finally {
SenderFactory.clearInstance();
}
}
Dependency injection
private Validator validator;
private MailSender mailSender;
public MailForm(Validator validator, MailSender mailSender) {
this.validator = validator;
this.mailSender = mailSender;
}
public void sendButtonClicked() {
…..
Testing now
public void testSendButton() {
MockSender mockSender = new MockSender();
Validator validator = new Validator();
MailForm form = new MailForm(validator, mockSender);
form.getMessageArea().setText("Some text");
form.sendButtonClicked();
assertEquals("Some text", mockSender.getSentText());
}
Why DI frameworks
Avoid boilerplate code AOP Integrate your DI with http session/request,
data access APIs, e.t.c Separate dependencies configuration from
code Makes life easier
What is Guice
Open source dependency injection framework License : Apache License 2.0 Developer : Google
Why Guice
Java API for configuration Easier to use Line numbers in error messages Less overhead Less features, too DI in GWT client-side code (using GIN)
Getting Guice
http://code.google.com/p/google-guice/ http://mvnrepository.com/ Small – 865 KB Version without AOP, suitable for Android –
470KB Lacks fast reflection and line numbers in errors
Dependency injection with Guice
private Validator validator;
private MailSender mailSender;
@Inject
public MailForm(Validator validator, MailSender mailSender) {
this.validator = validator;
this.mailSender = mailSender;
}
Creating instance of MailForm
Injector injector =
Guice.createInjector(new YourAppModule());
MailForm mailForm = injector.getInstance(MailForm.class);
Bindings
public class YourAppModule extends AbstractModule {
protected void configure() {
bind(MailService.class).to(MailServiceImpl.class);
bind(Validator.class).to(ValidatorImpl.class);
}
}
Providers
public class YourAppModule extends AbstractModule {
protected void configure() {
bind(Validator.class).to(ValidatorImpl.class);
}
@Provides
MailService getMailService() {
MailService service = new MailService();
return service;
}
….
Injecting fields
@Inject
private Validator validator;
@Inject
private MailSender mailSender;
public MailForm() {
}
Injecting with setter methods
private Validator validator;
public MailForm() {
}
@Inject
public void setValidator(Validator validator) {
this.validator = validator;
}
Optional injection
Inject(optional=true) Ignores values for which no bindings are
avalaible Possible with setter methods only
Bind instance
protected void configure() {
bind(Integer.class).annotatedWith(ThreadCount.class).toInstance(4);
}
..
@ThreadCount
int threadCount;
IDE autocomplete, find usages e.t.c
Two implementations
protected void configure() {
bind(Validator.class).to(ValidatorImpl.class);
bind(Validator.class).to(StrictValidatorImpl.class);
}
Two implementations
Exception in thread "main" com.google.inject.CreationException:
Guice configuration errors:
1) Error at lv.jug.MailService.configure(YourAppModule.java:12):
A binding to lv.jug.MailService was already configured at
lv.jug.YourAppModule.configure(YourAppModule.java:11)
Two implementations
protected void configure() {
bind(Validator.class).to(ValidatorImpl.class);
bind(Validator.class)
.annotatedWith(Strict.class)
.to(StrictValidatorImpl.class);
}
….
@Inject
public MailForm(@Strict Validator validator) {
this.validator = validator;
}
Binding annotation
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.PARAMETER})
@BindingAnnotation
public @interface Strict {}
Implicit binding
@Inject
public MailForm(
@ImplementedBy(StrictValidator.class) Validator Validator validator,
MailSender mailSender) {
this.validator = validator;
this.mailSender = mailSender;
}
Static injection
protected void configure() {
bind(Validator.class).to(ValidatorImpl.class);
requestStaticInjection(OurClass.class);
}
…
…
@Inject static Validator validator;
Scoping
protected void configure() {
bind(Validator.class).to(ValidatorImpl.class)
.in(Scopes.SINGLETON);bind(MailService.class).to(MailServiceImpl.class)
.asEagerSingleton();}
Multibindings
Multibinder<Plugin> pluginBinder = Multibinder.newSetBinder(binder(), Plugin.class);
pluginBinder.addBinding().to(SomePluginImpl.class);
pluginBinder.addBinding().to(AnotherPluginImpl.class);
….
@Inject Set<Plugin> plugins
Grapher
Describe the object graph in detail Show bindings and dependencies from several
classes in a complex application in a unified diagram
Generates .dot file
Advanced Guice
AOP Warp Google Gin Spring integration Using guice with Servlets
Why AOP
Transaction handling Logging Security Exception handling e.t.c
AOP
void bindInterceptor(
Match <? super Class<?>> classMatcher,
Matcher<? super Method> methodMatcher,
MethodInterceptor... interceptors)
public interface MethodInterceptor extends Interceptor {
Object invoke (MethodInvocation invocation) throws Throwable
}
AOP
You can not match on private and final methods due to technical limitations in Java
Only works for objects Guice creates
Warp
http://www.wideplay.com/ Eco-system for Google Guice Thin lightweight modules for Guice applications Persistence Transactions Servlets
Warp-persist
Supports : Hibernate/JPA/Db4Objects Inject DAOs & Repositories Flexible units-of-work Declarative transaction management
( @Transactional ) Your own AOP for transactions management @Finder(query="from Person")
Google Gin
Automatic dependency injection for GWT client-side code
Code generation Little-to-no runtime overhead, compared to
manual DI Uses Guice binding language http://code.google.com/p/google-gin/
Spring integration
http://code.google.com/p/guice-spring/ @Named(”mySpringBean”)
JSR-330
javax.inject @Inject @Named @Qualifier @Scope @Singleton e.t.c Supported by Guice, Spring, EJB
Using Guice with Servlets
@RequestScoped @SessionScoped ServletModule serve(”/admin”).with(AdminPanelServlet.class) serve("*.html", "/my/*").with(MyServlet.class) filter(”/*”).through(MyFilter.class) @Inject @RequestParameters Map<String,
String[]> params;
Thank you
Questions ?