简体   繁体   中英

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!

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> 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM