2017-02-03 8 views
3
пример

игрушки:Как переместить анонимного провайдера, который ссылается на поля в модуле в отдельный класс?

public class MyModule extends AbstractModule { 
    private static final Foo foo; 

    public MyModule(Foo foo) { 
    this.foo = foo; 
    } 

    @Override 
    public void configure() { 
    bind(Bar.class).toProvider(new Provider<Bar>() { 
     @Override public Bar get() { 
     return foo.getBar(); 
     } 
    }); 
    } 
} 

Это позволяет мне лениво вызвать .getBar() метод предоставленного пользователем Foo экземпляра, хранящегося в области MyModule. Однако теперь provider has its own dependencies - следовательно, мне нужно определить не-анонимный класс. Я указываю конструктор @Inject. Что-то вроде:

public class MyModule extends AbstractModule { 
    private static final Foo foo; 

    public MyModule(Foo foo) { 
    this.foo = foo; 
    } 

    @Override 
    public void configure() { 
    bind(Bar.class).toProvider(BarProvider.class); 
    } 

    BarProvider implements Provider<Bar> { 
    private Baz baz; 

    @Inject BarProvider(Baz baz) { 
     this.baz = baz; 
    } 

    @Override public Bar get() { 
     return foo.getBar(baz); 
    } 
    } 
} 

Отлично! Кроме Guice doesn't like this ...

Исключение в потоке «основного» com.google.inject.CreationException: Невозможно создать инжектор, см следующие ошибки:

1) Впрыскивание во внутренние классы не поддерживается. Используйте вместо класса com.example класс 'static' (верхний уровень или вложенный) .MyModule $ BarProvider.

Итак, я на связи. Мне нужно одновременно получить как поле на модуле, так и введенный тип из класса Provider. Есть какой-либо способ сделать это?


Примечание: эта игрушка пример исключает некоторые из реальной сложности - в частности, bind() утверждение более активное участие, поэтому я не могу просто определить @Provides метод.

ответ

0

Я понимаю, что я получал зацикливаться на том, Guice построить мой Provider для меня, что я на самом деле не нужно делать. Несмотря на то, что в документации Guice, переданной в DatabaseTransactionLogProvider.class, лучшая параллель с первым фрагментом будет заключаться в том, чтобы вручную создать экземпляр моего Provider и передать как экземпляр Foo, так и экземпляр Provider<Baz> (provided by the module).

public class MyModule extends AbstractModule { 
    private static final Foo foo; 

    public MyModule(Foo foo) { 
    this.foo = foo; 
    } 

    @Override 
    public void configure() { 
    bind(Bar.class).toProvider(new BarProvider(foo, getProvider(Baz.class)); 
    } 

    static BarProvider implements Provider<Bar> { 
    private final Foo foo; 
    private final Provider<Baz> bazProvider; 

    BarProvider(Foo foo, Provider<Baz> bazProvider) { 
     this.foo = foo; 
     this.bazProvider = bazProvider; 
    } 

    @Override public Bar get() { 
     return foo.getBar(bazProvider.get()); 
    } 
    } 
} 
2

Частично, инъекция во внутренний класс невозможна, потому что Guice не может отразить внутренний экземпляр без внешнего родительского экземпляра (эквивалент синтаксиса arcane outerInstance.new InnerInstance()).

Некоторых опции:

  • Сделать Foo инъекционного через граф, возможно, скрытый в PrivateModule поэтому он не подвергается воздействию всей графе (если это важно для вас).
  • Используйте анонимный внутренний провайдер (или извлеченный эквивалент) и получите Provider<Baz> из метода AbstractModule getProvider(Class<T>). Вы получите исключение, если попытаетесь вызвать это до создания Инъектора, но для создания Провайдера, как вы это делаете, это, вероятно, не проблема.
  • Отправьте bind за пределы проблемы с игрушкой, чтобы узнать, возможно ли с помощью ловкости @Provides.

Похожие: Accessing Guice injector in its Module?

+0

Thanks Jeff! После публикации я понял, что мне нужен был 'getProvider()'.Он смотрел мне прямо в лицо, но почему-то он не нажал :) – dimo414

 Смежные вопросы

  • Нет связанных вопросов^_^