Reputation: 155
Using GWT 2.4.0 I'm attempting to use deferred binding rules to substitute a uibinder template for another.
The way that I have come up with to do this is by creating a concrete class for each uibinder template that returns the instance of the uibinder. Here is an example.
public class ThemeOneUiBinderImpl {
@UiTemplate("ThemeOne.ui.xml")
interface ThemeOneUiBinder extends UiBinder<Widget, PageToTheme> {
}
private static ThemeOneUiBinder uiBinder = GWT.create(ThemeOneUiBinder.class);
public static UiBinder<Widget, PageToTheme> getImpl() {
return uiBinder;
}
}
Then I have a second class that is basically the same called ThemeTwoUiBinderImpl. My class references ThemeOneUiBinderImpl and calls getImpl().createAndBindUi(this)
And the following deferred binding rules
<replace-with class="package.ThemeTwoUiBinderImpl">
<when-type-is class="package.ThemeOneUiBinderImpl"/>
<when-property-is name="theme" value="theme2"/>
</replace-with>
With these rules in place, when I compile I see that the number of permutations doubles so it is doing something... But when I load the page, the theme1 uibinder is still loading. I have two issues:
Thoughts? Solutions? Thanks!
Upvotes: 1
Views: 2380
Reputation: 203
If you want the View to bind to Viewimpl based on useragent property then
I want to share one the method that I tried, First of all instead of mapping view to viewimpl you can bind it to viewprovider, and then based on user-agent values you can return the appropriate instance to bind to.I implemented this in sample application and its working fine as of now.
Upvotes: 0
Reputation: 155
I reviewed the GWT appearance design pattern again and realized that I didn't really understand how the replace-with was working. I thought that it was replacing one concrete implementation of a class with another. But looking closer I saw that there needs to be an abstract class or interface that is created using GWT.create. Understanding and thinking of the appearances as I would doing the same thing with reflection really helped me to figure it out.
Also... As Blessed Geek pointed out, if you have an abstract base then GWT.create would fail which is what you want if your classes aren't properly being replaced.
I now have the following in my view
public interface MyHeaderAppearance {
UiBinder<Widget, MyHeaderView> getUiBinder();
public int getHeight();
}
private final LoginPageAppearance appearance;
public MyHeaderView() {
appearance = GWT.<MyHeaderAppearance> create(MyHeaderAppearance.class);
}
public void render() {
panel.add(appearance.getUiBinder().createAndBindUi(this))
}
my theme implementation just implements the MyHeaderAppearance interface in a class called MyHeaderAppearanceImpl. To support multiple themes there I have packages for each theme and an instance of MyHeaderAppearanceImpl in each theme package.
then I am replacing my theme implementation code like this
ThemeOne.gwt.xml
<module>
<replace-with class="theme1.MyHeaderAppearanceImpl">
<when-type-is class="MyHeaderAppearance"/>
</replace-with>
</module>
and including the theme like this in my main module
<inherits name="theme.ThemeOne" />
It's working and I am happy but are there any improvement ideas?
Upvotes: 0
Reputation: 21634
Let me tell you Google's intended way of letting you replace template of a class.
To replace the ui template of a uibinded java class, just extend the class. This is somewhat borne of an MVP attitude towards the template as a view and code as model. Somewhat. The idea is you can replace the view anytime on the model without having to change the model, but also not forbidding you to add to the model.
What I do is create a base class with a default/dummy template.
If the extension classes are not in the same package as the base class, the uibinded fields/resources/methods of the base class must be public.
In fact, what I normally do is not have any GWT.create in the base class but in the extension class - so that
Then I extend the base class, to create a uibinder class with a ui template, where the fields/resources in the ui template matches exactly the uifield/resources in the base class plus any fields/resources I added into the extended class.
The principle behind this is that:
any consummated extension of a base uibinded class must have a reciprocal ui template where the template must re-implement the ui fields/resources of the base class completely, regardless if the base class already has its own ui template.
When I say "consummated", it means that GWT.create method is invoked on the template in that extension class.
The consequence to this rule is that you cannot extend a uibinded class without having to reimplement the template.
Say you have a nicely laid out Dialog box with uibinder. And you wish to avail it to be extended for minor tweaks without change in appearance. Unfortunately the extended Dialog box would have to make a copy of the template file of the base class, even if you do not intend to make any ui/layout changes.
I don't think you should perform template replacement thro replace-with in gwt.xml, when there is already an avenue to do it conveniently.
What you are doing is obfuscating and I don't think I would spend time analysing it.
Upvotes: 3