sapphire gimlets
DESCRIPTION
Gin and GuinceTRANSCRIPT
Sapphire Gimlets* Robert CooperReachCall.com
*no onions
Guice
Dependency Injection
Java Source configuration
Convention over configuration
Fast
Gin
Guice for GWT apps
100% Client Side
Based on Deferred Binding, so some limitations
Fast
Guice vs Spring
Spring Config Hell Promise of simplicity Ever expanding config files Lots of subprojects Becomes more brittle, in that it becomes harder
to extract code for reuse.
Guice vs Spring
Guice Java Source “configuration” Convention over configuration. Annotation based Opposite of Spring in defaults
Prefer constructor injection Prefer new instances (“Prototype”) over Singletons Provider<T> interface encourages mixing scopes
Type Safe – you got static typing, use it!
Guice 101
Basic Annotations @Inject @ImplementedBy/@ProvidedBy @[Scope] @Named
Guice 101
public class MyClass {
private final MyService service;
@Injectpublic MyClass(final MyService service){ this.service = service;}
public String sayHelloToUser(){return this.service.hello();
}
}
@ImplementedBy(MyServiceImpl.class)public interface MyService { public String hello();}
Guice 101
@Singletonpublic class MyServiceImpl implements MyService {
private final Provider<MySessionObject> sessionProvider; public MyServiceImpl(final Provider<MySessionObject> sessionProvider){ this.sessionProvider = sessionProvider; }
@Override public String hello() { return "Hello, "+sessionProvider.get().getName() +"!"; }
}
Guice 101
import com.google.inject.servlet.SessionScoped;
@SessionScoped public class MySessionObject {
private String name; public String getName(){ return this.name; } public void setName(String name){ this.name = name; }
}
Guice 101
What have we done?
MyClass gets a MyService injected.
MyService is implemented by MyServiceImpl as a Singleton
MyServiceImpl gets a Provider<MySessionObject>
The hello() method fetches the Session scoped MySession object, and says Hello!
Guice 101
@ImplementedBy provides defaults for any interface (You don’t need to config these if the default is OK)
Injection is type safe on constructors (Unit tests have obvious requirements)
Scope annotations (@SessionScoped, @Singleton) provide defaults.
Provider<T> hides the scope shift from the Singleton service in a single thread method.
Guice 101
Making it work on the web…
Guice 101
public class GuiceContextListener extends GuiceServletContextListener { @Override protected Injector getInjector() { return Guice.createInjector( new Module() { public void configure(Binder binder) { // Oh Wait, we don’t need anything here! } } }, new ServletModule() { @Override protected void configureServlets() { this.serve(“/myPath/*”).with(MyServlet.class); } } }}
Guice 101
Warning! Overly complicated coming up!
Guice 101
@Singletonpublic class MyServlet extends HttpServlet{
private final Provider<MySessionObject> sessionProvider; private final MyClass myClass;
@Inject public MyServlet(final Provider<MySessionObject> sessionProvider,
MyClass myClass){ this.sessionProvider = sessionProvider; this.myClass = myClass; }
@Override public void doGet(HttpServletRequest req, HttpServletResponse res)
throws IOException { this.sessionProvider.get().setName(req.getParameter("name")); res.getWriter().println(myClass.hello()); }
}
Guice 101
So this is interesting. What happened there?
The SessionScoped object was created, and set on the session.
MyClass was created one off for injection into the servlet. Since it wasn’t a Provider<MyClass> it was implicitly @Singleton with the servlet
But since the MyClass implementation used a provider, it ended up performing a singleton-session scoped op.
Guice 101
What else?
Servlets, Filters, etc must always be @Singleton of course, this just makes sense.
They can *still* get anything injected into them.
You need to add your boostrap GuiceContextListener to your web.xml
For Servlet < 3.0 you need to add a com.google.inject.servlet.GuiceFilter to /*
Guice 201
Why does this rock? (Hint GWT stuff…)
Can you say RemoteServiceServlet?
No more calls to getThreadLocalX() for servlet context stuff. Just use Provider<T>
Guice 201: Warp
The Warp-* projects provide a lot of utility ops for Guice:
@Transactional scope
Transaction per Request
Some stuff not dissimilar to Spring WebFlow or Stripes.
Guice 201: More Config
@Named lets you provide named values in your configuration. (You can also create custom annotations)
You can also use @Provides for factory methods in your modules for simple providers
@Provides public Connection getConnection(@Named(“jdbc-url”) String jdbcUrl) {
DriverManager.forName(whatever); DriverManager.getConnection(jdbcUrl);
}
Guice 201: More Config
binder.bind(String.class).annotatedWith(Names.named(“jdbc-url”)).toInstance(“jdbc:mysql://localhost/mydb”);
Note: @Provides methods could do JNDI lookups, or get other stuff. (This is a stupid example!)
Of Junipers and Bathtubs
Gin is Google Guice for GWT client side apps.
Based on DeferrredBinding.
Certain features lost:
Binding .toInstance() on any module
Anonymous Provider<T> can’t be done (@Provides is *kinda* OK)
Scoping needs to be by hard class reference.
Of Junipers and Bathtubs
That is.. in(Singleton.class) not .asEagerSingleton() or with @Singleton
Gin seems both stupid and too smart. Binding a RemoteServiceAsync class works out
of the box… Unless you want to do @Provides
Gin created classes are new Class() not GWT.create(Class.class); -- except for RemoteServiceAsync, which is a special scope.
Gin 101
@GinModules(MyGinModule.class)public interface Injector extends Ginjector { public static final Injector INSTANCE = GWT.create(Injector.class);
public MyStartupClass startupClass();
}
public class Module extends AbstractGinModule { @Override protected void configure() { this.bind(Resources.class) .toProvider(ResourcesProvider.class) .in(Singleton.class)
}}public static class ResourcesProvider implements Provider<Resources> { @Override public Resources get() { return GWT.create(Resources.class); }}
Gin 101
Does this step on the toes of DeBi? OK, maybe a little bit. Sure you could do a
singleton Resources.INSTANCE but injection makes Unit testing without dropping into GWTTestCase more frequent. (Read: much, much faster)
This reserves DeBi for what it is best for: local environment specific code.
Gin 201
What can’t you do with Gin?
Remember your Injector.INSTANCE is compile-time: No “toInstance()” bindings… ever. No “toProvider(AnonymousProvider(){})”
providers need to be public scoped static classes at the least.
Gin treats RemoteServiceAsync specially. You can do a provider, but if you try @Provides methods in your GinModule classes, you will get a duplicate declaration error.
Gin 201
All this aside, stacked with DeBi, Gin can rock rough and stuff with its Afro Puffs.
Replace your Startup call with a Sync method.
Replace your Async classes with thing that talk to local storage.
Automagically retry onFailure() methods on network errors while your uses if offline.
Way way more
Warp-* is some great stuff: http://code.google.com/p/warp-persist/ http://code.google.com/p/google-sitebricks/
Guice with JAX-WShttps://jax-ws-commons.dev.java.net/guice/
(Strangely harder than JAX-RS)