Aha, I think I get it: the way to build an arbitrary structure is
through an instance-specific provider that manually builds the given
object graph. It's the same as building it by hand, but at least the
code is in a separate place, and that is the point.
(And the example about your MainMenuProvider can be improved to use DI
instead of "new", of course).
Thank you all for your help!!!
Luis.
On Dec 23, 11:33 am, "Witold Szczerba" <[email protected]> wrote:
> 2008/12/23 Luis <[email protected]>:
>
> > From the "philosophic" point of view I think the answer is now clear
> > to me. But I am still not sure about how does Guice handle this kind
> > of situations:
>
> > class MenuTree extends MenuElement {
> > @Inject List<MenuElement> items;
> > }
>
> There are many ways, you can do it like this:
> Implement provider of List<MenuElement>:
>
> public class MainMenuProvider implements Provider<List<MenuElement>> {
> @Override
> public List<MenuElement> get() {
> List<MenuElement> result = new ArrayList....
> result.add(....);
> result.add(....);
> result.add(....);
> return result;
> }
>
> }
>
> This class would be equivalent to the Spring XML file, but it is Java,
> so you have all the benefits of working with Java code like type
> safety etc... Now, in your application module you can bind that
> provider to every List<MenuElement> or only to the lists with special
> annotations. This is how you could bind that provider to any list of
> menu elements:
>
> bind(new TypeLiteral<List<MenuElement>>() {})
> .toProvider(new MainMenuProvider());
>
> So whenever you use:
>
> @Inject
> private List<MenuElement> menuElements;
>
> you will get the array list returned by your custom provider.
>
> Or you can bind it like this:
> bind(new TypeLiteral<List<MenuElement>>() {})
> .annotatedWith(Names.named("MainMenu"))
> .toProvider(new MainMenuProvider());
>
> So now, you will get that list only when used @Named annotation:
>
> @Inject @Named("MainMenu")
> private List<MenuElements> mainMenuElements
>
> Actually, you can define your own annotation instead of using @Named
> with String literal.
>
> Another way to declare such a menu would be to create one instance and
> bind instance in module. You can create separate module for that
> purpose or add it to your existing module, like this:
>
> List<MainMenu> mainMenu = Collections.unmodifiableList(Arrays.asList(
> A,
> B,
> C));
> bind(new TypeLiteral<List<MenuElement>>() {})
> .annotatedWith(Names.named("MainMenu"))
> .toInstance(mainMenu);
>
> I think that using provider is more like "the right way". More than
> that, since providers are by default instantiated by Guice, you can
> inject into provider whatever you want, so the result of provider can
> depend on other managed objects, where as a module is to be provided
> to Guice by you, so you would rather not be able to inject things
> there...
>
> Which ever path you choose, notice you can separate that custom
> providers or modules from your application and pack them as separate
> jars. When you do this, you will be able to provide different sets of
> menu items in your application depending on which jar you include into
> classpath (remember, one provider can extends another one asking its
> parent for menu items and adding/removing whatever you want, as all
> this is a java code).
> So you will not have to recompile entire application. In Spring, you
> would replace the XML file to be able to change main menu. In Guice
> you just replace jar with your providers.
>
> Regards,
> Witold Szczerba
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"google-guice" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/google-guice?hl=en
-~----------~----~----~----~------~----~------~--~---