Guice Assisted инъекция для типизированных классов - PullRequest
0 голосов
/ 10 февраля 2019

Я пытаюсь сделать вспомогательную инъекцию в Guice.

Вот мои реализации.

public interface Dao<T> {
    T get(String id);
}

public class DaoImpl<T> implements Dao<T> {
    private final Class<T> clazz;
    DaoImpl(@Assisted final Class<T> clazz) {
        this.clazz = clazz;
    }

    @Override 
    public T get() {
      //Some impl code
      return T;
    }
}

Заводской интерфейс.

public interface DaoFactory {
    <T> Dao<T> getDao(Class<T> clazz);
}

Модуль Guice:

public class DaoModule extends AbstractModule {

    @Override
    protected void configure() {
        install(new FactoryModuleBuilder()
                .implement(new TypeLiteral<Dao<? extends Entity>>() {},
                        new TypeLiteral<DaoImpl<? extends Entity>>() {})
                .build(DaoFactory.class));
    }
}

Я получаю сообщение об ошибке: «DaoFactory не может быть использован в качестве ключа; он не указан полностью».

Как мне настроить FactoryModuleBuilder?

Моя цельполучить типизированный экземпляр Dao во время выполнения, используя DaoFactory

1 Ответ

0 голосов
/ 10 февраля 2019

Assisted Inject предполагает наличие привязки для выбора того, что вы хотите получить, возвращаемые вам - параметры вашего интерфейса Factory должны быть просто @Assisted -аннотированными параметрами в конструкторе желаемой реализации.

В этом случае это означает, что для DaoFactory.getDao, чтобы взять T, конструктор DaoImpl<T> должен будет взять этот экземпляр T (аннотированный @Assisted), а затемЭтого достаточно для того, чтобы этот экземпляр DaoImpl мог правильно создавать экземпляры.Примерно так, возможно:

public class DaoImpl<T> implements Dao<T> {

    public DaoImpl(@Assisted T instance) {
        // Do something with the instance so this Dao is wired up right.
        // perhaps with instanceof or instance.getClass()?
    }

    @Override 
    public T get() {
      //Some impl code
      return T;
    }
}

Это все, что помогает инжектор, знает, как это сделать - это не магия, которая может каким-то образом создавать поиск во время выполнения, но этого может быть достаточно для вас, в зависимости от вашего варианта использования.Я не уверен, почему DaoFactory.getDao взял бы экземпляр T, а затем Dao.get() вернул бы также T, но так как это является частью примера кода в вопросе, я предполагаюу вас это уже запланировано.


Обновление после редактирования:

DaoFactory.getDao принимает T экземпляр, но конструктор для DaoImpl - DaoImpl(@Assisted final Class<T> clazz) - с помощьюФабрики инъекций должны принимать тот же параметр, который предполагается передать конструктору.Это хорошая новость для вашего вопроса - вы можете просто слегка изменить объявление фабрики:

public interface DaoFactory {
    <T> Dao<T> getDao(Class<T> obj);
}

Теперь вы вызываете getDao с чем-то вроде MyEntity.class в качестве параметра, и вам будет дан Dao<MyEntity>Экземпляр, который был создан внутренним вызовом guice, вызывая new DaoImpl(MyEntity.class).

Если вы хотите, чтобы он был специфичен для некоторого объекта, вызывая instance.getClass() и передавая его, вы получите некоторые общие эффекты, которые вы должны понимать, так как getClass()фактически возвращает Class<?> или, в лучшем случае, Class<? extends WhateverMyDeclaredTypeIs>.Учтите следующее:

class MyClass {}
class MySubclass extends MyClass{}

MyClass foo = new MySubclass();

factory.getDao(foo.getClass());// the generics will be a Dao<? extends MyClass>, 
// not a Dao<MySubclass>, even though the DaoImpl.clazz holds an instance
// of MySubclass
...