sapphire gimlets

28
Sapphire Gimlets* Robert Cooper ReachCall.com *no onions

Upload: robert-cooper

Post on 03-Dec-2014

902 views

Category:

Technology


5 download

DESCRIPTION

Gin and Guince

TRANSCRIPT

Page 1: Sapphire Gimlets

Sapphire Gimlets* Robert CooperReachCall.com

*no onions

Page 2: Sapphire Gimlets

Guice

Dependency Injection

Java Source configuration

Convention over configuration

Fast

Page 3: Sapphire Gimlets

Gin

Guice for GWT apps

100% Client Side

Based on Deferred Binding, so some limitations

Fast

Page 4: Sapphire Gimlets

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.

Page 5: Sapphire Gimlets

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!

Page 6: Sapphire Gimlets

Guice 101

Basic Annotations @Inject @ImplementedBy/@ProvidedBy @[Scope] @Named

Page 7: Sapphire Gimlets

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();}

Page 8: Sapphire Gimlets

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() +"!"; }

}

Page 9: Sapphire Gimlets

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; }

}

Page 10: Sapphire Gimlets

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!

Page 11: Sapphire Gimlets

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.

Page 12: Sapphire Gimlets

Guice 101

Making it work on the web…

Page 13: Sapphire Gimlets

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); } } }}

Page 14: Sapphire Gimlets

Guice 101

Warning! Overly complicated coming up!

Page 15: Sapphire Gimlets

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()); }

}

Page 16: Sapphire Gimlets

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.

Page 17: Sapphire Gimlets

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 /*

Page 18: Sapphire Gimlets

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>

Page 19: Sapphire Gimlets

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.

Page 20: Sapphire Gimlets

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);

}

Page 21: Sapphire Gimlets

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!)

Page 22: Sapphire Gimlets

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.

Page 23: Sapphire Gimlets

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.

Page 24: Sapphire Gimlets

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); }}

Page 25: Sapphire Gimlets

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.

Page 26: Sapphire Gimlets

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.

Page 27: Sapphire Gimlets

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.

Page 28: Sapphire Gimlets

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)