Google Guice Quick Reference
bold marked words in code are derived from guice library
Google
Guice Cheat Sheet
Basic @Inject
- Service Consumer Class
@Inject
RealBillingService(CreditCardProcessor processor,TransactionLog transactionLog) {
this.processor = processor;
this.transactionLog= transactionLog;
}
- Guice Configuration Class
public class BillingModule extends AbstractModule {
@Override
protected void configure() {
// Class binding
bind(TransactionLog.class).to(DatabaseTransactionLog.class).in(Singleton.class);
bind(CreditCardProcessor.class).to(PaypalCreditCardProcessor.class);
//or instance binding
bind(CreditCardProcessor.class).toInstance(new PaypalCreditCardProcessor());
}
}
- Client Class
Injector injector = Guice.createInjector(new BillingModule());
/*
* Now that we've got the injector, we can build objects.
*/
RealBillingService billingService= injector.getInstance(RealBillingService.class);
Extention @Inject
1.Linked Binding
– Link DatabaseTransactionLog to subclass MySqlDatabaseTransactionLog.
You can chain this linking. Injector
will return instance of MySqlDatabaseTransactionLog
public class BillingModule extends AbstractModule {
@Override
protected void configure() {
bind(TransactionLog.class).to(DatabaseTransactionLog.class);
bind(DatabaseTransactionLog.class).to(MySqlDatabaseTransactionLog.class);
}
}
2.Binding Annotation
–
Ø
2a . @Named
@Inject
public RealBillingService(@Named("PayPal") CreditCardProcessor processor)
- Guice
Configuration
bind(CreditCardProcessor.class)
.annotatedWith(Names.named("PayPal"))
.to(PayPalCreditCardProcessor.class);
Ø
2b.Custom Annotation @PayPal
a.Client Guice Configuration
import com.google.inject.BindingAnnotation;
import java.lang.annotation.Target;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
@BindingAnnotation @Target({ FIELD, PARAMETER, METHOD }) @Retention(RUNTIME)
public @interface PayPal {}
b.Service Consumer
@Inject
public RealBillingService(@PayPal CreditCardProcessor processor)
c. Client
bind(CreditCardProcessor.class)
.annotatedWith(PayPal.class)
.to(PayPalCreditCardProcessor.class);
Ø
2c.@Provides –create an object with some code instade of
single line toInstance method
Guice
Configuration
public class BillingModule extends AbstractModule {
// Add any subannotation if required like @PayPal
@Provides
TransactionLog provideTransactionLog() {
DatabaseTransactionLog transactionLog = new DatabaseTransactionLog();
transactionLog.setJdbcUrl("jdbc:mysql://localhost/pizza");
transactionLog.setThreadPoolSize(30);
return transactionLog;
}
}
Ø
2d.Provider
Binding – Alternative to @Provides by moving instance production logic
to a separate class
a.Guice
Configuration
public class BillingModule extends AbstractModule {
@Override
protected void configure() {
bind(TransactionLog.class)
.toProvider(DatabaseTransactionLogProvider.class);
}
b.Provider as
instance creation class
public interface Provider<T> {
T get();
}
public class DatabaseTransactionLogProvider implements Provider<TransactionLog> {
public TransactionLog get() {
DatabaseTransactionLog transactionLog = new DatabaseTransactionLog();
transactionLog.setConnection(connection);
return transactionLog;
}
}
Ø
2e. @ImplementedBy
and @ProvidedBy – Provides default
implementation, can be overriden by the bind() method in guice configuration
module.
@ImplementedBy(PayPalCreditCardProcessor.class)
public interface CreditCardProcessor{…}
Equivalient to
bind(CreditCardProcessor.class).to(PayPalCreditCardProcessor.class);
@ProvidedBy(DatabaseTransactionLogProvider.class)
public interface TransactionLog {…}
Equivalent to
bind(TransactionLog.class).toProvider(DatabaseTransactionLogProvider.class);
Ø
2f. Inject into an existing instance – (for
objects that are already instatiated not by guice)useful in servlets or instances
that you can’t instantiate or already instatiated by container
Injector injector = Guice.createInjector(...);
CreditCardProcessor creditCardProcessor = new PayPalCreditCardProcessor();
injector.injectMembers(creditCardProcessor);
Injecting by Providers (alternative
to direct @Inject)
Usability Criteria - Whenever you need to scope mixing (like
accessing a request scoped object in session scope or singleton scope) or get
instances on demand (lazy loading) or inject more than one instances per type.
Below instead of injecting directly CreditcardProcessor, we
use Provider< CreditcardProcessor > and its get() method call provides an
instance when required. You can call the get() method to provide as many
instances you like and wherever you need inside the code
public class RealBillingService implements BillingService {
private final Provider<CreditCardProcessor> processorProvider;
private final Provider<TransactionLog> transactionLogProvider;
@Inject
public RealBillingService(Provider<CreditCardProcessor> processorProvider,
Provider<TransactionLog> transactionLogProvider) {
this.processorProvider = processorProvider;
this.transactionLogProvider = transactionLogProvider;
}
public Receipt chargeOrder(PizzaOrder order, CreditCard creditCard) {
CreditCardProcessor processor = processorProvider.get();
TransactionLog transactionLog = transactionLogProvider.get();
/* use the processor and transaction log here */
}
}
Guice configuration
public class BillingModule extends AbstractModule {
@Override
protected void configure() {
// Class binding
bind(TransactionLog.class).to(DatabaseTransactionLog.class).in(Singleton.class);
bind(CreditCardProcessor.class).to(PaypalCreditCardProcessor.class);
//or instance binding
bind(CreditCardProcessor.class).toInstance(new PaypalCreditCardProcessor());
}
}
AOP with GUICE
Two concepts – Matcher
and MethodInterceptors
Matchers matches
classes to apply pointcuts (cross cutting concerns), MethodInterceptors implement the cross cutting concern.
Example in steps – stop pizza orders on weekends
1.create an annotation or use builtin @Named annotation
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD)
@interface NotOnWeekends {}
2.Annotate the method where you want to introduce pointcut
public class RealBillingService implements BillingService {
@NotOnWeekends
public Receipt chargeOrder(PizzaOrder order, CreditCard creditCard) {
...
}
3.Implement MethodInterceptors
public class WeekendBlocker implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
Calendar today = new GregorianCalendar();
if (today.getDisplayName(DAY_OF_WEEK, LONG, ENGLISH).startsWith("S")) {
throw new IllegalStateException(
invocation.getMethod().getName() + " not allowed on weekends!");
}
return invocation.proceed();
}
}
4.Wire or configure all
public class NotOnWeekendsModule extends AbstractModule {
protected void configure() {
bindInterceptor(Matchers.only(RealBillingService.class), Matchers.annotatedWith(NotOnWeekends.class),
new WeekendBlocker());
}
}
You can use Matchers.any() or Matchers.subclassesof(BillingService.class)
or if you want the interceptor to be injected with some
objects
public class NotOnWeekendsModule extends AbstractModule {
protected void configure() {
WeekendBlocker weekendBlocker = new WeekendBlocker();
requestInjection(weekendBlocker);
bindInterceptor(Matchers.any(), Matchers.annotatedWith(NotOnWeekends.class),
weekendBlocker);
}
}
Bootstrap for Injecting in http servlets
–
Bootstrap guice
servlet –
1.
<listener>
<listener-class>com.example.MyGuiceServletConfig</listener-class>
</listener>
2.
public class MyGuiceServletConfig extends GuiceServletContextListener {
@Override
protected Injector getInjector() {
return Guice.createInjector(new ServletModule());
}
}
or You can subclass ServletModule class like above
Guice.createInjector(..., new ServletModule() {
@Override
protected void configureServlets() {
filter("/*").through(MyFilter.class);
serve("*.html").with(MyServlet.class);
}
}
3.
<filter>
<filter-name>guiceFilter</filter-name>
<filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>guiceFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
- Injecting inside servlet
if ServletModdule class is installed as above
@Singleton
public class MyServlet extends HttpServlet {
@Inject private Injector injector;
...
}
Or Inside servlet init() method, use the bootstrap class
public void init(ServletConfig config) throws ServletException {
super.init(config);
ServletContext servletContext = config.getServletContext();
Injector injector =
(Injector) servletContext.getAttribute(Injector.class.getName());
injector.injectMembers(this);
}
You can inject ServletContext. You can inject Request
parameters by,
@Inject @RequestParameters Map<String, String[]> params;
GUICE with JERSEY REST Service
Setup –
Step 1 – Use maven dependency
jersey-guice with google guice as shown
below.
<!-- Google Guice
-->
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>3.0</version>
</dependency>
<!-- Jersey Guice
Module -->
<dependency>
<groupId>com.sun.jersey.contribs</groupId>
<artifactId>jersey-guice</artifactId>
<version>1.15</version>
</dependency>
Step 2 - Follow the same
setup as web application, but Instead of creating injector from ServletModule
class, use JerseyServletModule and use jersey GuiceContainer class to bind to
request that will be server by Jersey as REST resources as shown below.
Guice.createInjector(..., new JerseyServletModule() {
@Override
protected void configureServlets() {
filter("/*").through(MyFilter.class);
serve("*.html").with(MyServlet.class);
serve("/rest/*").with(GuiceContainer.class);
}
}