assistedinject, mapbinder, and superinterfaces

60 views
Skip to first unread message

Leigh Klotz

unread,
Nov 13, 2008, 6:51:58 PM11/13/08
to google-guice
As part of a meta-class system, I would like to use assistedinject to
create a number of FactoryProviders for different interfaces, and use
mapbinder to hold the factories.

It appears that assistedinject doesn't work well with factory
interfaces that extend other interfaces, and without a parent
interface, it's difficult to put all the factories into a mapbinder.

Is there a simple way out of this conundrum that I'm just
overlooking? Is there another way to accomplish my task?

The detalis are below:

I would like to declare assistedinject factories which extend a
superinterface:

public interface MotorcycleFactory { Motorcycle create(String vin); }
public interface YamahaFactory extends MotorcycleFactory { Yamaha
create(String vin); }
public interface HarleyFactory extends MotorcycleFactory { Harley
create(String vin); }

Then put the resulting factories into a mapbinder:
public void configure() {
MapBunder<String, MotorcycleFactory> f = MapBinder.newMapBinder(binder
(), String.class, MotorcycleFactory.class);
f.addBinding("Harley", HarleyFactory.class);
f.addBinding("Yamaha", YamahaFactory.class);
}

Then I should be able to retrieve the factories from the mapbinder and
operate on them:

class Main {
@Inject MapBinder<String, MotorcycleFactory> factories;
Motorcycle create(String brand, String vin) {
return create(factories.get(brand), vin);
}
Motorcycle create(MotorcycleFactory f, String vin) {
return f.create("abc123");
}
}

Unfortunately, this doesn't work because of an issue with
assistedinject.

In snapshot-20081016, assistedinject appears to require that all
methods of the interface directly match the @AssistedInject
constructor signature of the concrete class. (I would have thought it
would require only the declared methods to match, and then do type
matching on the inherited methods.)

So, with this constructor
@AssistedInject public HarleyImpl(GasTank gasTank, @Assisted String
vin) {..}

this line
bind(HarleyFactory.class).toProvider FactoryProvider.newFactory
(HarleyFactory.class, Harley.class));

yields this error
An exception was caught and reported. Message: Constructor mismatch:
Harley has 1 @AssistedInject constructors, factory HarleyFactory has 2
creation methods

So, I cannot bind the HarleyFactory and YamahaFactory because of the
contradictory requirements of (1) super interface returning
MotorcycleFactory and (2) FactoryProvider requiring matching
constructors. It's odd, because the superinterface for HarleyFactory
(MotorcycleFactory) doesn't even declare itself to return a Harley, so
there's no way I can see for FactoryProvider to find a constructor on
HarleyFactory that creates exactly a MotorcycleFactory.

Is there a way around this issue with assistedinject and super
interfaces so that I can have a common class to use in mapbinder? Is
there a solution by using f.addBinding("Harley").toProvider and adding
another level of indirection? Then I still have the @AssistedInject
issue with inherited super-interfaces.

Is there a better way for me to implement the dispatch logic I need
for the meta-class hierarchies?

I have a worked-up sample case for all of this posted at
http://graflex.org/klotz/2008/11/aimb/aimb.zip

Thank you,
Leigh.

limpb...@gmail.com

unread,
Nov 13, 2008, 7:37:20 PM11/13/08
to google-guice
On Nov 13, 3:51 pm, Leigh Klotz <Leigh.Kl...@gmail.com> wrote:
> In snapshot-20081016, assistedinject appears to require that all
> methods of the interface directly match the @AssistedInject
> constructor signature of the concrete class. (I would have thought it
> would require only the declared methods to match, and then do type
> matching on the inherited methods.)

Dan Martin has written 'assistedinject deluxe' that makes this easy.
I'll try to get it checked into SVN shortly...
http://code.google.com/p/google-guice/issues/detail?id=131

For anyone curious, here's the improvements:
- factory-built objects use a regular @Inject constructor
- parameters are 'matched up' using binding annotations rather than
parameter order.
- parameters can be injected anywhere – not just constructors. You
can inject even parameters into your dependencies, or as providers
- factory-built objects can use method interceptors



Reply all
Reply to author
Forward
0 new messages