Skip to content
Christopher Viel edited this page Jan 5, 2015 · 1 revision

If you're like me:

  • You like Google Gin
  • You like injecting dependencies into your custom composites
  • You love declaring your widgets in UiBinder

then GWTP has something for you! GinUiBinder allows you to instatiate your custom, Gin-powered widgets into UiBinder easily.

Important note

GinUiBinder is a feature that has been around for ages in GWTP but that has never been documented. This feature let you use widgets inside your UiBinder without using @UiField(provided = true). This only works on widgets that use @Inject.

This feature is highly unstable as we hack our way through UiBinder. With each new release of GWT, there's a high possibility that the tool will be broken. There's no backward compatibility as well, you will have to both update GWT and GWTP to the most recent version to be able to use this feature continuously. Ack.

Why it's cool

Let's define our own Gin-powered composite, for example:

import com.myproject.client.SharingService;
import com.myproject.client.TwitterUrlBuilder;
import com.myproject.client.UrlBuilderFactory;

public class TwitterShareButton extends Composite {
    interface Binder extends UiBinder<InlineHyperlink, TwitterShareButton> {
    }

    @UiField
    InlineHyperlink shareLink;

    private final SharingService sharingService;
    private TwitterUrlBuilder twitterUrlBuilder;

    @Inject
    public TwitterShareButton(Binder binder,
                              UrlBuilderFactory urlBuilderFactory,
                              SharingService sharingService) {
        this.sharingService = sharingService;

        initWidget(binder.createAndBindUi(this));

        twitterUrlBuilder = urlBuilderFactory.createTwitterUrlBuilder();
    }

    public void setTweet(String tweet) {
        twitterUrlBuilder.setTweet(tweet);
    }

    @UiHandler("shareLink")
    public void handleClick(ClickEvent event) {
        sharingService.share(twitterUrlBuilder);
    }
}

Notice how TwitterShareButton makes extensive use of Gin-managed dependency injection? Of course, Binder, UrlBuilderFactory and SharingService must be resolved by Gin in order to instantiate TwitterShareButton properly.

Without GinUiBinder, we'll have to declare our instance of TwitterShareButton in ParentWidget like this:

<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
             xmlns:g='urn:import:com.google.gwt.user.client.ui'
             xmlns:share='urn:import:com.myproject.client.api.share.button'>
    <g:HTMLPanel>
        <share:TwitterShareButton tweet="@ArcBees GinUiBinder is #awesome!" ui:field="twitterShareBtn"/>
    </g:HTMLPanel>
</ui:UiBinder>

And here's ParentWidget's code:

public class ParentWidget extends ViewImpl implements HeaderPresenter.MyView {
    interface Binder extends UiBinder<Widget, ParentWidget> {
    }

    @UiField(provided = true) // this ...
    TwitterShareButton twitterShareButton;

    @Inject
    ParentWidget(Binder uiBinder, 
                 TwitterShareButton twitterShareButton) {
        this.twitterShareButton = twitterShareButton; // and this is required!

        initWidget(uiBinder.createAndBindUi(this));
    }
}

With GinUiBinder, we'll get rid of the reference to TwitterShareButton that is shared between the UiBinder and the view. This will allow us to remove the ui:field tag in the UiBinder:

<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
             xmlns:g='urn:import:com.google.gwt.user.client.ui'
             xmlns:share='urn:import:com.myproject.client.api.share.button'>
    <g:HTMLPanel>
        <share:TwitterShareButton tweet="@ArcBees GinUiBinder is #awesome!"/> <!-- No more ui:field, yay! -->
    </g:HTMLPanel>
</ui:UiBinder>

and to remove the (provided = true) parameter in the @UiField annotation and the TwitterShareButton field initialization before binding the ui:

public class ParentWidget extends ViewImpl implements HeaderPresenter.MyView {
    interface Binder extends UiBinder<Widget, ParentWidget> {
    }

    @UiField // ah, this is better!
    TwitterShareButton twitterShareButton;

    @Inject
    ParentWidget(Binder uiBinder) {
        initWidget(uiBinder.createAndBindUi(this)); // phew, no more pesky initializations!
    }
}

How to use it

  1. Make sure GWTP is in your classpath before GWT. If you use Maven, make sure the GWTP dependencies are declare before GWT dependencies in your pom.xml
  2. Inherit the GinUiBinder GWT module. Add this to your GWT module:
<inherits name="com.google.gwt.uibinder.GinUiBinder"/>
  1. Create a custom Ginjector that defines one interface method for each of your custom composites:
public interface MyGinjector extends Ginjector {
    TwitterShareButton getTwitterShareButton();
}
  1. Extend property gin.ginjector.extensions with your custom Ginjector. In your GWT module file, add:
<extend-configuration-property name="gin.ginjector.extensions"
                               value="com.myproject.client.gin.MyGinjector"/>
Clone this wiki locally