Guice / Gin. How to implement multiple implementations

I have a webapp that uses a GIN to inject dependencies at the entry point.

private InjectorService injector = GWT.create(InjectorService.class); 

 @GinModules({PlaceContollerInject.class, RootViewInject.class}) public interface InjectorService extends Ginjector { RootView getRootView(); PlaceController getPlaceConroller(); } 

 public class RootViewInject extends AbstractGinModule { @Override protected void configure() { bind(RootView.class).to(RootViewImpl.class); } } 

I need a mobile version using a different implementation of RootView. Dependencies are described in the next module.

 public class RootViewMobileInject extends AbstractGinModule { @Override protected void configure() { bind(RootView.class).to(RootViewMobileImpl.class); } } 

The question is how to choose the necessary dependency conditionally, do we need a mobile or standard version. I saw the GWT-GIN Multiple Implementations , but did not understand this solution because the Provider breaks the dependency chain and Factory Pattern breaks testability. In the "Big Modular Java with Guice" video here (12 minutes), the Gibs injector with modules was introduced as a replacement for Factories. So my question is whether I should create different Ginjector for mobile and standard versions (for example, MobileFactory and DefaultFactory) of my application, or it will be bad practice, and I have to configure one instance of Ginjector with all the necessary versions. For example, with annotation bindings like this.

 public class RootViewMobileInject extends AbstractGinModule { @Override protected void configure() { bind(RootView.class).annotatedWith(Mobile.class).to(RootViewMobileImpl.class); } } 

and use @Mobile annotated bindings at the GWT entry point

  @Inject private void setMobileRootView(@Mobile RootView rw) { this.rw = rw; } 

In such a simplified example, as indicated above, this is possible. But if the application has more dependencies that require mobile and standard versions. It seems like a return to the untested “ugly” (as stated in the Guice presentation). Sorry for my English. Any help is appreciated.

+7
source share
2 answers

I believe that you will want to use GWT deferred bindings using class substitution to bind a different version of your InjectorService depending on the user agent. This will ensure that the mobile version only has mobile implementations compiled into (and downloaded)

So, you should have InjectorServiceDesktop, InjectorServiceMobile, which is distributed both from InjectorService and GWT.create (InjectorService.class), and let deferred binding decide which implementation it should use.

http://code.google.com/webtoolkit/doc/latest/DevGuideCodingBasicsDeferred.html#replacement

One instance of Ginjector with all versions seems bad, as it always downloads all the code for both versions (and you, of course, do not want to download all your desktop views into your mobile application)

EDIT: As Thomas points out in the comments, since Injectors are generated classes, you need to put each InjectorServiceXXX in a simple holder class, which is GWT.create () InjectorServiceXXX, and use the replacement to switch between holders.

+9
source

Doing what you want is actually quite difficult, because your common injector interface, which is annotated by your Gin module, cannot point to an abstract Gin module. The Gin module that your Ginjector interface points to must be specific. A particular module cannot perform multiple configurations at once.

So what do you do: (a) Build your Ginjector interface, say ClientGinjector and your ClientModule for the desktop application.

(b) Create a second Ginjector interface, say ClientGinjectorTablet, adding the one you created in (a) but with a GinModule annotation pointing to another module, such as ClientModuletablet.

- Now you have two default Ginjecor interfaces, and the second one for tablets, each of which points to a module with its own Configure () implementations.

(c) Now you want to create a Factory to get an implementation of the Right Ginjector. You can do this because the Ginjector that you studied in (a) and (b) has a common daemon, which is the default interface created in (a). Thus, you create an abstract factoria using a method such as: public annotation ClientGinjector getInjector (); You create two children of specific classes. One to get the Ginjector Desktop / Default, and the other to get the Ginjector Tablet.

(d) Now you configure your gwt.xml module in the same way as Google IO on youtube, explain that you need to get the desired factor at runtime using delayed GWT bindings for each of your Ginjector factory.

(e) At your entry point, you will not receive a Ginjector, but your Factory for Ginjectors using a delayed GWT binding. You call the abstract method that ClientGinjector returns, your set.

(f) Epic failure at the end. Guice will not allow you to bind the same key twice (class plus annotation), even if you use different injectors (one for the desktop and one for the tablet). The key bindings seem to be global once you have two modules redefining the same keys as the end of the adventure.

+1
source

All Articles