Would this be possible if the MapBinder had an 'outer' binder and private
binder available?
It's not ideal, but I could see doing something like
install(new MyMapBinderModule(binder());
in an abstract module and the MyMapBinderModule/MapBinder could look
something like
public class MyMapBinderModule extends PrivateModule
{
private final Binder m_publicBinder;
public MyMapBinderModule(Binder publicBinder)
{
m_publicBinder = publicBinder;
}
@Override
protected void configure()
{
MapBinder<String, MessageHandler> mapBinder =
MapBinder.newMapBinder(m_publicBinder, binder(), Foo.class,
Bar.class);
}
{
Alternately, if we could somehow just do
expose(mapBinder) or mapBinder.expose() or something that would be awesome.
I don't know if this is too 'hacky', but it's leagues above the hacks I
have in place to do this right now.
What hacks are you doing now?
Basically, I do this...
public class MyModule extends AbstractModule
{
private final String m_configurationValue;
public MyModule(String configurationValue)
{
m_configurationValue = configurationValue;
}
@Override
protected void configure()
{
MapBinder<String, MessageHandler> mapBinder =
MapBinder.newMapBinder(binder(), Foo.class, Bar.class);
// Great, I'm creating an injector in my configure...
Injector injector = Guice.createInjector(getPrivateModule());
// We could have bound this to an instance of Bar.class instead,
// but that would require remote calls in its providers be executed
// in our unit tests and that would not work correctly. This limits
// our Module unit testing.
mapBinder.addBinding(new Foo()).toProvider(
injector.getInstance(MyBarProvider.class).getProvider());
}
// This class exists just to manipulate an injector within Configure
private static class MyBarProvider {
private @Inject Provider<Bar> provider;
public Provider<Bar> getProvider() {
return provider;
}
}
private Module getPrivateModule()
{
return new PrivateModule() {
@Override
protected void configure()
{
// Bar.class depends on an A provider One, but in other
// modules depends on A provider two because of different
// implementations.
bind(A.class).toProvider(AImplProviderOne.class);
// Bar.class depends on an B provider Three, but in other
// modules depends other providers.
bind(B.class).toProvider(BImplThreeProvider.class);
// B implementations need a parameter passed into the module
// that indicate something, like initial size or file to
read
// or something.
bind(String.class).annotatedWith(BParameter.class).toInstance(configurationValue);
bind(bar.class);
expose(bar.class);
}
}
}
}
Comment #6 on issue 369 by sberlin: Convenient way to expose multibindings
and mapbindings from PrivateModules
http://code.google.com/p/google-guice/issues/detail?id=369
(No comment was entered for this change.)
Comment #7 on issue 369 by sberlin: Convenient way to expose multibindings
In Guice 3, this workaround has another downside. Refer to this:
https://code.google.com/p/google-guice/wiki/ToConstructorBindings
"But there are limitations of that approach: manually constructed instances
do not participate in AOP."
This implies if I bind to the constructor of an object, I can use AOP on
it, even if it's a third-party component.
However, I cannot use this in tandem with the above workaround. If I bind
something with a second injector and providers to work around the
limitations of the MapBinder/MultiBinder, the objects created by that
second injector don't participate in AOP specified in a separate module
created for that express purpose. This is a somewhat limiting problem from
the perspective of using Guice with AOP.