GWT GIN Инъекция на уровне поля - PullRequest
2 голосов
/ 27 февраля 2012

Мы оцениваем использование GIN в нашем проекте GWT и добились хороших результатов с типичным внедрением через аргументы конструктора. У нас были трудности с инжекцией на уровне поля. Поля всегда заканчиваются нулем. У кого-нибудь есть хороший пример того, как правильно достичь уровня инъекции с помощью GIN?

Обновление:

Вот пример кода, похожего на наш:

public class MVP implements EntryPoint {

  public static final HandlerManager EVENT_BUS = new HandlerManager(null);
  private final MVPInjector _injector = GWT.create(MVPInjector.class);

  public void onModuleLoad() {
    // set up layout for module
    RootLayoutPanel.get().add(mainPanel);

    // initialize presenters
    ListPresenter listPresenter = _injector.listPresenter();
    DetailPresenter detailPresenter = _injector.detailPresenter();

    listPresenter.go(listContainer);
    detailPresenter.go(detailContainer);

    // simulate data coming in from RPC call
    EVENT_BUS.fireEvent(new DataReadyEvent(getData()));
  }
}

public class ListPresenter {

  private final HandlerManager _eventBus;
  private final Map<String, Fruit> _myRecords = new HashMap<String, Fruit>();
  private final Display _view;

  @Inject
  public ListPresenter(Display argView, HandlerManager argEventBus) {
    _eventBus = argEventBus;
    _view = argView;
  }

  public void go(HasWidgets argContainer) {
    argContainer.clear();
    argContainer.add(_view.asWidget());
  }

  public interface Display {
    public Widget asWidget();

    public void clear();

    public SingleSelectionModel<ViewProxy> getSelectionModel();

    public void setData(List<ViewProxy> argData);
  }
}

public class DetailPresenter {

  private final HandlerManager _eventBus;
  private final Display _view;
  private Fruit _myRecord;

  @Inject
  private ImagePresenterFactory _imagePresenterFactory;

  @Inject
  private TestPresenter _testPresenter;

  @Inject
  public DetailPresenter(Display argView, HandlerManager argEventBus) {
    _view = argView;
    _eventBus = argEventBus;
  }

  public void go(HasWidgets argContainer) {
    argContainer.clear();
    argContainer.add(_view.asWidget());

    if (_testPresenter != null) {
      _testPresenter.go();
    }
  }

  public interface Display {
    public Widget asWidget();

    public HasText getDescriptionControl();

    public HasClickHandlers getImageControl();

    public HasText getNameControl();

    public HasClickHandlers getSaveControl();

    public void setEnabledControls(boolean argEnabled);
  }
}

public class TestPresenter {

  @Inject
  HandlerManager _eventBus;

  public TestPresenter() {}

  public void go() {
    if (_eventBus != null) {
      _eventBus.toString();
    }
    else {
      // event bus was not injected
    }
  }
}

@GinModules(MVPModule.class)
public interface MVPInjector extends Ginjector {

  DetailPresenter detailPresenter();

  ListPresenter listPresenter();

}

public class MVPModule extends AbstractGinModule {

  @Provides
  @Singleton
  public HandlerManager getEventBus() {
    return MVP.EVENT_BUS;
  }

  @Provides
  public TestPresenter getTestPresenter() {
    return new TestPresenter();
  }

  @Override
  protected void configure() {
    bind(ListPresenter.Display.class).to(ListView.class);
    bind(DetailPresenter.Display.class).to(DetailView.class);
    bind(ImagePresenter.Display.class).to(ImagePopup.class);
    install(new GinFactoryModuleBuilder().build(ImagePresenterFactory.class));
  }

  public interface ImagePresenterFactory {
    public ImagePresenter createImagePresenter(ImageResource argImage);
  }

}

В приведенном выше коде я удалил большую часть кода, в котором нет GIN. TestPresenter, который требуется для DetailPresenter, вводится успешно, но HandlerManager, который требуется для TestPresenter, всегда равен нулю. Как видите, введенный HandlerManager не используется в конструкторе.

1 Ответ

1 голос
/ 27 февраля 2012

Обновление, глядя на пример кода:

@Provides
public TestPresenter getTestPresenter() {
  return new TestPresenter();
}

Поскольку вы создаете его самостоятельно, предполагается, что вы имели дело с любыми уколами. Удалите этот метод, и он вызовет конструктор по умолчанию (впрыскивание туда, если необходимо), а затем посетит любой другой сайт внедрения.

Еще одна проблема, с которой вы можете столкнуться: существует несколько ссылок HandlerManager, убедитесь, что все ваши ссылки на HandlerManager используют один и тот же пакет.


Оригинальный ответ:

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

InstanceToInject instance = new InstanceToInject(...);
instance.field = provideFieldValue();

К тому времени, когда поле даже может быть назначено, ваш конструктор уже запущен.

Если поле имеет значение NULL при запуске другого метода, убедитесь, что метод не запускается конструктором , а после того, как внедрение завершило свою работу. Другие случаи, когда он еще может быть нулевым, будут @Inject аннотируемыми сеттерами.

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

...