Guice辅助注入工厂中通用返回类型的问题

13

到目前为止,我成功地使用了 Google Guice 2。在迁移到 Guice 3.0 时,我遇到了关于 assisted inject factories 的问题。假设有以下代码:

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));
    }
}

创建注入器时,我遇到以下异常:
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)

使用Guice 2的辅助注入创建器,我的配置可以正常工作:
bind(PaymentFactory.class).toProvider(
FactoryProvider.newFactory(PaymentFactory.class, RealPayment.class));

到目前为止,我找到的唯一解决方法是从工厂方法的返回类型中删除泛型参数。
public interface PaymentFactory {
    Payment create(Date date);
}

有没有人知道为什么Guice 3不喜欢工厂方法中的泛型参数,或者我对辅助注入工厂的理解有什么误解?谢谢!


我在想,你是否应该将 TypeLiteral<Payment<Currency>> 传递给 implement 而不是 Payment.class - Jeremy
@Jeremy Heiler 谢谢,但是你会怎么做呢?TypeLiteral没有公共构造函数,如果你使用TypeLiteral.get(Payment.class),你会得到相同的异常。 - kraftan
也许是这样的?TypeLiteral.get(Types.newParameterizedType(Payment.class, Currency.class)); - Jeremy
应创建一个通用的“TypeLiteral”,如: new TypeLiteral<Payment<Currency>>(){}。 注意{}…必须创建子类以使完整的通用信息可用。 - ColinD
@Jeremy Heiler:不,那样行不通。使用您建议的TypeLiteralimplement方法时存在类型不匹配的问题。 - kraftan
@ColinD 那也不行。还因为 implement 方法的类型不匹配。 - kraftan
1个回答

12

你的代码存在两个问题。

首先,RealPayment 实现了 Payment<SwissFrancs>,但是 PaymentFactory.create 返回的是 Payment<Currency>。一个 Payment<SwissFrancs> 不能从返回 Payment<Currency> 的方法中返回。如果你将 create 的返回类型改为 Payment<? extends Currency>,那么 RealPayment 将可以工作(因为它是一个对某个继承自 Currency 的东西的 Payment)。

其次,你需要使用带有 TypeLiteral 参数的 implement 版本。这可以通过使用一个匿名内部类来实现。要表示“Payment”,你可以使用:

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

查看 TypeLiteral 构造函数的 Javadoc 以获取更多信息。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接