I typically have this kind of code pattern in my GWT project:
Menu errorMenu = new Menu(user, userController, -1);
Menu searchMenu = new Menu(user, userController, 0);
errorView.setMenu(errorMenu);
searchView.setMenu(searchMenu);
How do I inject a Menu
instance in the ErrorView
and other "views" using Gin/Guice:
public ErrorView implements View {
// Inject menu instance here
private Menu menu;
}
Such that, I don't have to manually create and set objects?
Also for the Menu
class, how can I inject the "user" and "userController" objects so I don't have to pass it on each Menu instance every time it is instantiated.
With help of this tutorial http://code.google.com/p/google-gin/wiki/GinTutorial your problem does not look so difficult. There are several steps you should run for injecting menu instance to the View.
Add @Inject annotation to the menu field.
public ErrorView implements View {
@Inject
private Menu menu;
}
public SearchView implements View {
@Inject
private Menu menu;
}
But in this case menu fields will be null during View object initialization (in constructor). Therefore I prefer to add this field to the constructor parametres.
public ErrorView implements View {
private final Menu menu;
@Inject
public ErrorView(Menu menu) {
this.menu = menu;
}
}
public SearchView implements View {
private final Menu menu;
@Inject
public SearchView(Menu menu) {
this.menu = menu;
}
}
Ofcourse it will not work in case of you have many other parameters in the constructor of ErrorView, because all of them need to be injected as well.
Now we must make sure that GIN knows that menu field in ErrorView should be
injected to new Menu(user, userController, -1)
and another one in
SearchView to - new Menu(user, userController, 0)
. We can do this
by the several ways:
Add annotations @Named("searchMenu")
and @Named("errorMenu")
to your menu fields.
public ErrorView implements View {
@Inject
@Named("errorMenu")
private Menu menu;
}
or
public ErrorView implements View {
private final Menu menu;
@Inject
public ErrorView(@Named("errorMenu") Menu menu) {
this.menu = menu;
}
}
In your GIN module you should provide the definition of this annotation.
public class ApplicationGinModule extends AbstractGinModule {
protected void configure() {
bind(Menu.class).annotatedWith(Names.named("errorMenu")).to(DefaultErrorMenu.class);
bind(Menu.class).annotatedWith(Names.named("searchMenu")).to(DefaultSearchMenu.class);
//assume that User and UserController classes have default constructors
//otherwise you should provide correct injection depending on your business-logic
bind(User.class).in(Singleton.class);
bind(UserController.class).in(Singleton.class);
}
}
public class DefaultErrorMenu extends Menu {
@Inject
public DefaultErrorMenu(User user, UserController userController) {
super(user, userController, -1);
}
}
public class DefaultSearchMenu extends Menu {
@Inject
public DefaultSearchMenu(User user, UserController userController) {
super(user, userController, 0);
}
}
Create your own annotations @SearchMenu
and @ErrorMenu
to your menu fields and define them in your module.
Annotation sample:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD, ElementType.TYPE})
@BindingAnnotation
public @interface ErrorMenu {
}
Usage:
public ErrorView implements View {
@Inject
@ErrorMenu
private Menu menu;
}
or
public ErrorView implements View {
private final Menu menu;
@Inject
public ErrorView(@ErrorMenu Menu menu) {
this.menu = menu;
}
}
Then define annotation the way exactly how you defined @Named("ErrorMenu"):
bind(Menu.class).annotatedWith(ErrorMenu.class).to(DefaultErrorMenu.class);
In some examples I make menu field final and remove setter to it, but if you really need mutable state for menu you can leave it unchanged.