如何通过GIN与UiBinder和Widgets一起使用注入?

Ben*_*n M 8 gwt gwt-gin dependency-injection uibinder

我正在使用GWT 2.4与gwt-platform 0.7和gin 1.5.0.

我已经为我的GWT应用程序的动态(实时)翻译构建了一个库.因此,每个小部件都会在LocaleChangeEvent被触发时得到通知,然后让我TranslationDictionary获取要显示的新String.

小部件实际上看起来像这样:

public class LocaleAwareLabel extends Label implements LocaleChangeEventHandler {
    TranslationDictionary dictionary;
    String translationToken;

    public LocaleAwareLabel(TranslationDictionary dictionary, EventBus eventBus, String translationToken) {
        this.dictionary = dictionary;
        this.translationToken = translationToken;
        eventBus.addHandler(LocaleChangeEvent.TYPE, this);
        getCurrentTranslationFromDictionary();
    }

    public void getCurrentTranslationFromDictionary() {
        this.setText(dictionary.getTranslation(translationToken));
    }

    @Override
    public void onLocaleChange(LocaleChangeEvent event) {
        getCurrentTranslationFromDictionary();
    }
}
Run Code Online (Sandbox Code Playgroud)

正如你所看到的:我不能轻易地将这个小部件与UiBinder一起使用,在我注入的时刻EventBusTranslationDictionary我的View使用方式@UiField(provided=true)如下:

@UiField(provided=true)
LocaleAwareLabel myLabel;

@Inject
public MyView(TranslationDictionary dictionary, EventBus eventBus) {
    widget = uiBinder.createAndBindUi(this);

    myLabel = new LocaleAwareLabel(dictionary, eventBus, "someTranslationToken");
}
Run Code Online (Sandbox Code Playgroud)

我想要的是:没有使用我的小部件@UiField(provided=true),所以我可以简单地将它们放在ui.xml这样的内容中:

<custom:LocaleAwareLabel ui:field="myLabel" translationToken="someTranslationToken" />
Run Code Online (Sandbox Code Playgroud)

我知道我可以translationToken使用以下命令设置via UiBinder:

public void setTranslationToken(String translationToken) {
    this.translationToken = translationToken;
}
Run Code Online (Sandbox Code Playgroud)

但是我仍然有一个问题,我不能使用零参数构造函数,因为EventBusTranslationDictionary.另外我不能getCurrentTranslationFromDictionary()在构造函数内部调用,因为translationToken当然在构造函数之后设置了值.

如果有人可以提供解决方案,可能会有代码示例,这将是很好的.

和PS我是一个完全注射 - 菜鸟,但从我的理解杜松子酒可能以某种方式解决我的问题.但我不知道怎么做.

谢谢!

Chr*_*her 6

目前在Dependency Injection和UiBinder之间存在一点概念不匹配,但我目前使用它的方式是:

private final Provider<LocaleAwareLabel> labelProvider;

@Inject
public MyView(TranslationDictionary dictionary, 
              EventBus eventBus, 
              Provider<LocaleAwareLabel> labelProvider) {

  this.dictionary = dictionary;
  this.labelProvider = labelProvider;
  initWidget(uiBinder.createAndBindUi(this));
}

@UiFactory
public LocaleAwareLabel buildLocaleAwareLabel() {
  return labelProvider.get();
}
Run Code Online (Sandbox Code Playgroud)

然后我可以在我的ui.xml中创建任意数量的标签:

<g:HTMLPanel>
  <custom:LocaleAwareLabel translationToken="abc"/>
  <custom:LocaleAwareLabel translationToken="xyz"/>
</g:HTMLPanel>
Run Code Online (Sandbox Code Playgroud)

在LocaleAwareLabel中,我使用setter方法作为转换令牌,并覆盖onLoad():

private String translationToken;

@Inject
public LocaleAwareLabel(TranslationDictionary dictionary, EventBus eventBus) {
  this.dictionary = dictionary;
  initWidget(uiBinder.createAndBindUi(this));
}

@Override
protected void onLoad() {
  super.onLoad();
  doSomethingWithTheTranslationToken(); // do this here, not in the constructor!
}

public void setTranslationToken(final String translationToken) {
  this.translationToken = translationToken;
}
Run Code Online (Sandbox Code Playgroud)

AssistedInject的示例

MyView更改为:

private final LocaleAwareLabelFactory labelFactory;

@Inject
public MyView(TranslationDictionary dictionary, 
              EventBus eventBus, 
              LocaleAwareLabelFactory labelFactory) {

  this.dictionary = dictionary;
  this.labelFactory = labelFactory;

  initWidget(uiBinder.createAndBindUi(this));
}

@UiFactory
public LocaleAwareLabel buildLocaleAwareLabel(final String translationToken) {
  return labelFactory.create(translationToken);
}
Run Code Online (Sandbox Code Playgroud)

LocaleAwareLabel:

public interface LocaleAwareLabelFactory {
  LocaleAwareLabel create(final String translationToken);
}

@Inject
public LocaleAwareLabel(TranslationDictionary dictionary, 
                        EventBus eventBus, 
                        @Assisted String translationToken) {

  this.dictionary = dictionary;
  initWidget(uiBinder.createAndBindUi(this));
  doSomethingWithTheTranslationToken(); // now you can do it in the constructor!
}
Run Code Online (Sandbox Code Playgroud)

在您的Gin模块中,添加:

install(new GinFactoryModuleBuilder().build(LocaleAwareLabelFactory.class));
Run Code Online (Sandbox Code Playgroud)

确保将guice的assistedinject jar(例如guice-assistedinject-snapshot.jar)添加到类路径中.


Tho*_*yer 5

目前这是不可能的,因为UiBinder不会调用GIN来实例化小部件.为此,您必须使用@UiFactory方法,或提供已构建的实例@Uifield(provided=true).

已经要求增强以更好地整合两者.您可以在此处跟踪:http://code.google.com/p/google-web-toolkit/issues/detail?id = 6151

作为替代方案,您可以requestStaticInjection将a Provider注入static字段,并get()从构造函数中调用提供程序:

public class LocaleAwareLabel extends Label {
   @Inject Provider<EventBus> eventBusProvider;
   @Inject Provider<TranslationDictionary> dictionaryProvider;

   private final TranslationDictionary dictionary;
   private final EventBus eventBus;
   private final string translationToken;

   @UiConstructor
   public LocaleAwareLabel(String translationToken) {
       this(dictionaryProvider.get(), eventBusProvider.get(), translationToken);
   }

   // For cases where you can use injection, or inject params yourself
   @Inject
   public LocaleAwarelabel(TranslationDictionary dictionary, EventBus eventBus,
           String translationToken) {
       this.dictionary = dictionary;
       this.eventBus = eventBus;
       this.translationToken = translationToken;
   }
Run Code Online (Sandbox Code Playgroud)

您可能也对GIN对Assisted-Inject的支持感兴趣,以便更容易编写@UiFactory方法或初始化@UiField(provided=true)字段.