Is it possible to get the currently binded elements of a Multibinder, while we're still in configure()?

109 views
Skip to first unread message

elect...@gmail.com

unread,
Jun 13, 2013, 1:52:57 PM6/13/13
to google...@googlegroups.com
I want to allow third-party modules to be able to bind some custom ISomeInterface elements (well, classes of ISomeInterface in fact : "Class<? extends ISomeInterface >"). I use Multibinder for that and it works great.

But I would like to be able, at the very end of my main module's configure() method, to process the elements that have been binded in the Multibinder to add further bindings for those. More specifically, I'd like to be able to automatically bind an AssistedFactory for each of the elements that have been multibinded.

Is there a way to retrieve the currently binded elements of a Multibinder, without the injector been created yet (while still being in "configure()")?

Something like :

-------------------
Multibinder<Class<? extends ISomeInterface>> myMultibinder = Multibinder.newSetBinder(binder(), new TypeLiteral<Class<? extends ISomeInterface >>(){});
Set<Class<? extends ISomeInterface>> currentBindings = myMultibinder.getBindings();
-------------------

Then I would use the "currentBindings" to bind assisted factories.

Any idea?


Christian Gruber

unread,
Jun 13, 2013, 2:09:03 PM6/13/13
to google...@googlegroups.com
One problem of obtaining this information is that module/binding
resolution order is a brittle thing to rely on, and you have no
guarantee that all or any particular bindings would be resolved by the
time you hit your configure() method.

Now it sounds like you don't need all the bindings, and we could in
theory expose a way to get at the current set of bindings in a multi
binder, but I am concerned to know how you would use this in practice…
how would it be useful if you couldn't know you had the necessary
bindings in place before reading from them? What would you do if later
modules added more bindings?

c.

On 13 Jun 2013, at 10:52, elect...@gmail.com wrote:

> I want to allow third-party modules to be able to bind some custom
> ISomeInterface elements (well,* classes* of ISomeInterface in fact :
> --
> You received this message because you are subscribed to the Google
> Groups "google-guice" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to google-guice...@googlegroups.com.
> To post to this group, send email to google...@googlegroups.com.
> Visit this group at http://groups.google.com/group/google-guice.
> For more options, visit https://groups.google.com/groups/opt_out.


Christian Gruber :: Google, Inc. :: Java Core Libraries :: Dependency
Injection
email: cgr...@google.com :::: mobile: +1 (646) 807-9839
Message has been deleted
Message has been deleted
Message has been deleted

elect...@gmail.com

unread,
Jun 13, 2013, 3:11:16 PM6/13/13
to google...@googlegroups.com
I have to admit I'm not 100% about what is the scope of a Multibinder...

My idea if that by using "final" on my main module's configure() method, I can make sure it is not overriden :
-------------------
public class MainModule extends AbstractModule
{
    @Override
    final protected void configure()
    {
        overridableConfigure();
        manageMultibindedBindings();
    }
   
    protected void overridableConfigure()
    {
        // - standards bindings + third-party modules bindings
        // - can be overriden
    }

    private void manageMultibindedBindings()
    {
        // add more bindings using the Multibinder's elements.
    }
}
-------------------
Then, I'm sure all the elements are binded in the Multibinder when manageMultibindedBindings() is called, right?

But if another module is binded at the same level than MainModule, would the same Multibinder will shared? What exactly is the scope of a Multibinder? (I guess should so some tests by myself to validate that!)

Thanks for the help!

Christian Gruber

unread,
Jun 13, 2013, 3:54:21 PM6/13/13
to google...@googlegroups.com
The same multi binder is given, yes. If I recall correctly, the multi
binder itself has no scope, but the bindings within do. I'd need to
look it up. That said, if you bind several multi binders to the same
key… you're not creating a new one (it's a mis-naming of the
newMultibinder() method). You get a new multi binder if a multi binder
doesn't already exist for that key. I any other case, you contribute
bindings to the already-existing multi binder.

Christian.

On 13 Jun 2013, at 12:10, elect...@gmail.com wrote:

> I have to admit I'm not 100% about what is the *scope* of a
> Multibinder...
>
> My idea if that by using "final" on my main module's configure()
> method, I
> can make sure it is not overriden :
> -------------------
> public class MainModule extends AbstractModule
> {
> @Override
> *final* protected void configure()
> {
> overridableConfigure();
> manageMultibindedBindings();
> }
>
> protected void overridableConfigure()
> {
> // - standards bindings + third-party modules bindings
> // - can be overriden
> }
>
> *final *protected void manageMultibindedBindings()
> {
> // add more bindings using the Multibinder's elements.
> }
> }
> -------------------
> Then, I'm sure all the elements are binded in the Multibinder when
> manageMultibindedBindings() is called, right?
>
> But if another module is binded *at the same level* than MainModule,
> would
> the same Multibinder will shared? What exactly is the scope of a
> Multibinder? (I guess should so some tests by myself to validate
> that!)
>
> Thanks for the help!
>
>
>
> On Thursday, June 13, 2013 2:09:03 PM UTC-4, Christian Gruber wrote:
>>
>> One problem of obtaining this information is that module/binding
>> resolution order is a brittle thing to rely on, and you have no
>> guarantee that all or any particular bindings would be resolved by
>> the
>> time you hit your configure() method.
>>
>> Now it sounds like you don't need all the bindings, and we could in
>> theory expose a way to get at the current set of bindings in a multi
>> binder, but I am concerned to know how you would use this in
>> practice…
>> how would it be useful if you couldn't know you had the necessary
>> bindings in place before reading from them? What would you do if
>> later
>> modules added more bindings?
>>
>> c.
>>
>>> an email to google-guice...@googlegroups.com <javascript:>.
>>> To post to this group, send email to
>>> google...@googlegroups.com<javascript:>.
>>
>>> Visit this group at http://groups.google.com/group/google-guice.
>>> For more options, visit https://groups.google.com/groups/opt_out.
>>
>>
>> Christian Gruber :: Google, Inc. :: Java Core Libraries :: Dependency
>> Injection
>> email: cgr...@google.com <javascript:> :::: mobile: +1 (646) 807-9839

elect...@gmail.com

unread,
Jun 14, 2013, 12:38:15 PM6/14/13
to google...@googlegroups.com
It would be useful to have some kind of hook which would be called once all modules are configured and that would allow some final configuration.

But I guess there is a better way to implement what I'm trying to do. I'll think about it...

Thank you for the help!

Sam Berlin

unread,
Jun 24, 2013, 8:36:46 AM6/24/13
to google...@googlegroups.com
If the purpose of the final configuration would be to do more configuration, it'd be a nightmare to manage.  Who gets to have the "last" say in the final configuration?

If you want to process your modules and do stuff to them, I suggest writing something like:
  createInjector(new DoStuffFromProcessingModule(new MyModule()), new MyModule());

... where "MyModule" is your real Module, and DoStuffFromProcessingModule uses the Elements SPI (and the Multibinders SPI specifically, if you're interested in Multibindings) to do stuff you're interested in.

 sam


Message has been deleted

elect...@gmail.com

unread,
Jun 24, 2013, 11:52:24 AM6/24/13
to google...@googlegroups.com
Thanks for the idea Sam.

Actually, I found another solution which works great in my situation. I had this idea by looking at the code for the assisted factories, com.google.inject.
assistedinject
.FactoryProvider2 in particular.

- The modules bind instances of Class<? extends ISomeInterface> (it's a little bit more complex then that, as they actually bind wrapper objects with a name (a String) in addition to the Class itself)
- I have an object "MyMetaFactory" that has a constructor that is injected with the Set<Class<? extends ISomeInterface>> from the multibinding, and with the Injector itself.
- In this MyMetaFactory's constructor, I create a child injector using an anonymous Module which creates assisted factories for each of the ISomeInterfaces.
- All assisted factories, created using the child injector, are stored in a MyMetaFactory's local variable. So when the MyMetaFactory's constructor exits, all the required assisted factories are created.
- Then, the rest of the code will use MyMetaFactory to get an instance of the particular ISomeInterface they need (by passing its "name", remember that was also multibinded!). MyMetaFactory will uses the appropriate assisted factory to create the instance.

I'm pretty happy with this pattern (How do you call it? The "AssistedInject Multibindings" pattern ?)

elect...@gmail.com

unread,
Jun 24, 2013, 11:53:48 AM6/24/13
to google...@googlegroups.com
Sorry about the delete/repost.
I hate the fact that you can't edit your posts (even for like 5 minutes) on Google Groups!
Reply all
Reply to author
Forward
0 new messages