Проблема с универсальным типом возврата в фабрике по внедрению - PullRequest
13 голосов
/ 01 апреля 2011

До сих пор я успешно использовал Google Guice 2. При переходе на Guice 3.0 у меня были проблемы с фабриками вспомогательных инъекций. Предположим, следующий код

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 не нравится универсальный параметр в фабричном методе или что я обычно неправильно понимаю на фабриках вспомогательных инъекций? Спасибо!

1 Ответ

12 голосов
/ 21 апреля 2011

С вашим кодом есть две проблемы.

Сначала RealPayment реализует Payment<SwissFrancs>, но PaymentFactory.create возвращает Payment<Currency>. Payment<SwissFrancs> нельзя вернуть из метода, который возвращает Payment<Currency>. Если вы измените тип возвращаемого значения create на Payment<? extends Currency>, то RealPayment будет работать (поскольку это Payment для чего-то, что расширяет Currency).

Во-вторых, вам НЕОБХОДИМО использовать версию implement, которая принимает TypeLiteral в качестве первого аргумента. Способ сделать это - использовать анонимный внутренний класс. Для представления «Оплаты» вы можете использовать

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

См. Javadoc для этого TypeLiteral конструктора для получения дополнительной информации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...