Open GoogleCodeExporter opened 9 years ago
A few wrinkles for the implementation...
- we need to avoid binding the Set/Map in the private module, since that would conflict with the same binding
in the outer module
- we need to somehow bind the Set/Map in the outer module if it doesn't exist already
Original comment by limpbizkit
on 7 May 2009 at 7:15
Why not just expose the Set/Map binding?
Original comment by net...@gmail.com
on 7 May 2009 at 7:20
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.
Original comment by Industri...@gmail.com
on 18 Feb 2011 at 6:54
What hacks are you doing now?
Original comment by sberlin
on 18 Feb 2011 at 6:59
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);
}
}
}
}
Original comment by Industri...@gmail.com
on 18 Feb 2011 at 7:25
Original comment by sberlin
on 22 Feb 2011 at 1:39
Original comment by sberlin
on 22 Feb 2011 at 1:40
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.
Original comment by Industri...@gmail.com
on 6 May 2011 at 3:51
[deleted comment]
My solution is to use expose in the configure method of the PrivateModule with
the help of TypeLiteral and Types:
expose((TypeLiteral<Map<String, MessageHandler>>) TypeLiteral.get(
Types.mapOf(String.class, MessageHandler.class)));
I even have crazier stuff like:
expose((TypeLiteral<Set<Entry<String, Provider<MessageHandler>>>>) TypeLiteral.get(
Types.setOf(Types.newParameterizedTypeWithOwner(
Map.class, Entry.class, String.class,
Types.providerOf(MessageHandler.class)))));
Original comment by justindh...@gmail.com
on 17 Sep 2013 at 6:12
I need this too. I'm using workaround with unique annotation for private
multibinder now.
Original comment by Ash2kk@gmail.com
on 1 Oct 2013 at 9:58
Original issue reported on code.google.com by
net...@gmail.com
on 7 May 2009 at 6:46