Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Problem with generic return type in guice assisted inject factory

So far, I successfully used google guice 2. While migrating to guice 3.0, I had troubles with assisted inject factories. Assume the following code

public interface Currency {}
public class SwissFrancs implements Currency {}

public interface Payment<T extends Currency> {}
public class RealPayment implements Payment<SwissFrancs> {
    @Inject
    RealPayment(@Assisted Date date) {}
}

public interface PaymentFactory {
    Payment<Currency> create(Date date);
}

public SwissFrancPaymentModule extends AbstractModule {
    protected void configure() {
        install(new FactoryModuleBuilder()
             .implement(Payment.class, RealPayment.class)
             .build(PaymentFactory.class));
    }
}

While creating the injector, I get the following exception:

com.google.inject.CreationException: Guice creation errors:

1) Payment<Currency> is an interface, not a concrete class.
   Unable to create AssistedInject factory. while locating Payment<Currency>
   at PaymentFactory.create(PaymentFactory.java:1)

With the assisted inject creator from guice 2 my configuration works:

bind(PaymentFactory.class).toProvider(
FactoryProvider.newFactory(PaymentFactory.class, RealPayment.class));

The only workaround I found so far is to remove the generic parameter from the return type of the factory method:

public interface PaymentFactory {
    Payment create(Date date);
}

Does anybody know, why guice 3 doesn't like the generic parameter in the factory method or what I generally misunderstood about assisted inject factories? Thanks!

like image 731
kraftan Avatar asked Apr 01 '11 13:04

kraftan


1 Answers

There are two issues with your code above.

First, RealPayment implements Payment<SwissFrancs>, but PaymentFactory.create returns Payment<Currency>. A Payment<SwissFrancs> cannot be returned from a method that returns Payment<Currency>. If you change the return type of create to Payment<? extends Currency>, then RealPayment will work (because it's a Payment for something that extends Currency).

Second, you DO need to use the version of implement that takes a TypeLiteral as its first argument. The way to do that is to use an anonymous inner class. To represent `Payment' you can use

new TypeLiteral<Payment<? extends Currency>>() {}

See the Javadoc for that TypeLiteral constructor for more information.

like image 86
netdpb Avatar answered Sep 17 '22 08:09

netdpb