How to use GWT's Editor Framework with gwt-platform? - gwt

I'm using gwt-platform and tried to implement GWT's editor framework. But I don't get it working from within the presenter. There are some answers around the web, that say I have to inject the EditorDriver somehow into the Presenter, but I don't know how to do this...
At the moment I tried this without success:
public class MyPresenter extends Presenter<MyPresenter.MyView, MyPresenter.MyProxy> implements MyUiHandlers {
public interface MyView extends View, HasUiHandlers<MyUiHandlers>, Editor<MyModel> {}
#ProxyStandard
#NameToken(NameTokens.myPage)
#NoGatekeeper
public interface MyProxy extends ProxyPlace<MyPresenter> {}
interface Driver extends SimpleBeanEditorDriver<MyModel, MyView> {}
private Driver editorDriver;
DispatchAsync dispatcher;
#Inject
public MyPresenter(EventBus eventBus, MyView view, MyProxy proxy, DispatchAsync dispatcher) {
super(eventBus, view, proxy);
getView().setUiHandlers(this);
this.dispatcher = dispatcher;
MyModel m = new MyModel();
m.setId(1L);
m.setUsername("username");
m.setPassword("password");
editorDriver = GWT.create(Driver.class);
editorDriver.initialize(this.getView());
editorDriver.edit(m);
}
...
}
It works if I explicitly specify the ViewImplementation, but that's not the way MVP should work:
interface Driver extends SimpleBeanEditorDriver<MyModel, MyViewImpl> {}
...
editorDriver.initialize((MyViewImpl) this.getView());
I would be nice if someone could give me an example how to do it right.
Thanks

An approach similar to what was used in an earlier version of the Expenses sample worked for me:
An interface that the view should implement. The wildcard is used so that the presenter does not need to know the concrete view implementation:
import com.google.gwt.editor.client.Editor;
import com.gwtplatform.mvp.client.View;
/**
* Implemented by views that edit beans.
*
* #param <B> the type of the bean
*/
public interface BeanEditView<B> extends View, Editor<B> {
/**
* #return a new {#link SimpleBeanEditorDriver} initialized to run
* this editor
*/
SimpleBeanEditorDriver<B, ?> createEditorDriver();
}
Your presenter should look something like this now:
public class MyPresenter extends Presenter<MyPresenter.MyView, MyPresenter.MyProxy> implements MyUiHandlers {
public interface MyView extends BeanEditView<MyModel>, HasUiHandlers<MyUiHandlers> {}
#ProxyStandard
#NameToken(NameTokens.myPage)
#NoGatekeeper
public interface MyProxy extends ProxyPlace<MyPresenter> {}
private SimpleBeanEditorDriver<MyModel, ?> editorDriver;
DispatchAsync dispatcher;
#Inject
public MyPresenter(EventBus eventBus, MyView view, MyProxy proxy, DispatchAsync dispatcher) {
super(eventBus, view, proxy);
getView().setUiHandlers(this);
this.dispatcher = dispatcher;
MyModel m = new MyModel();
m.setId(1L);
m.setUsername("username");
m.setPassword("password");
editorDriver = getView().createEditorDriver();
}
...
}
And the view implmementation:
public class MyViewImpl extends ViewWithUiHandlers<MyUiHandlers> implements
MyPresenter.MyView {
public interface Binder extends UiBinder<Widget, MyViewImpl> { }
private static Binder uiBinder = GWT.create(Binder.class);
/**
* The driver to link the proxy bean with the view.
*/
public interface EditorDriver extends SimpleBeanEditorDriver<MyModel, MyViewImpl> { }
private final Widget widget;
public MyViewImpl() {
widget = uiBinder.createAndBindUi(this);
}
#Override
public SimpleBeanEditorDriver<MyModel, ?> createEditorDriver() {
EditorDriver driver = GWT.create(EditorDriver.class);
driver.initialize(this);
return driver;
}
#Override
public Widget asWidget() {
return widget;
}
...
}
That's as close as I could get to MVP with GWT's Editor Framework. I couldn't find a way for the view implementation to NOT know the model but I don't think it's really necessary.
If anyone has any improvements on this, I'm glad to hear.
Found some additional comments on GWT Editors. It seems that it might just not be possible to completely separate the model. As Thomas Broyer puts it in his answer to another Editor question:
"MVP is not set in stone (it's not even defined; it was coined by Martin Fowler but he retired the term in favor of two more specific patterns), so you're only violating the rules you gave to yourself. Put differently, the Editor framework as a whole can be seen as violating MVP: each editor know the model, not necessarily the exact instance it's editing (as with ValueAwareEditor or LeafValue), but at least the kind of objects it's an editor of."

The issue is that the Driver.class passed to GWT.create
editorDriver = GWT.create(Driver.class);
must the concrete class that holds all sub-editors, i.e. all the uibinded widgets.
One solution is the following:
The view interface extends the editor interface for the Model object
public interface MyView extends View, ..., Editor<MyModel>
The view implementation MyViewImpl defines a driver type
interface MyDriverImpl extends SimpleBeanEditorDriver<MyModel,MyViewImpl>
The driver is instantiated in MyViewImpl by
SimpleBeanEditorDriver<MyModel,MyView> driver = GWT.create(MyDriverImpl.class);
The parent type
SimpleBeanEditorDriver<MyModel,MyView>
can be used to pass references of the driver to the presenter

MVP says that you use the presenter to completely seperate the model from the view. In addition I'd say that your approach puts logic inside the view...
I hope that there's another solution ;)

Related

Dagger2 Android subcomponent injection in nonAndroid classes

Learning Dagger2 and maybe going off the rails here. I have a class - MapRoute that may or may not be needed in a Fragment. If MapRoute is needed, I want to create it and when the MapRoute is instantiated I want to inject it with dependencies created at the application level. I am also using Builder pattern to populate MapRouter.
Perhaps the generic question is when you are in nonAndroid classes (not Activity/Fragment/...) how can you inject dependencies from above? How to you construct the nonAndroid injector in place of AndroidInjection.inject(this)?
So my fragment is:
public class ActivityMapFragment extends DaggerFragment ... {
#Inject
MapRoute.Builder mapRouteBuilder;
private void plotRouteForMap(Cursor csr){
MapRoute.Builder builder = new MapRoute.Builder();
builder.setSupportMapFragment(supportMapFragment)
.setLocationExerciseRecord(ler)
.setMapType(mapType)
.setUseCurrentLocationLabel(useCurrentLocationLabel)
.setCursor(csr)
.setTitle(activityTitle)
.setActivityPhotosCallback(this);
mapRoute = builder.build();
mapRoute.plotGpsRoute();
}
...
MapRoute is: (Edit) added Builder code snippet
public class MapRoute ... {
#Inject
public DisplayUnits displayUnits; <<< Created at app level
#Inject
public PhotoUtils photoUtils; <<<< Create at app level
public MapRoute() {
// Use subcomponent builder
MapRouteSubcomponent component =
DaggerMapRouteSubComponent.builder().build(); <<< Want to do this
component.inject(this);
}
public static class Builder {
SupportMapFragment supportMapFragment;
LocationExerciseRecord ler;
boolean useCurrentLocationLabel;
int mapType;
Cursor cursor;
ActivityPhotosCallback activityPhotosCallback;
String title;
#Inject
public Builder() {
}
public Builder setSupportMapFragment(SupportMapFragment supportMapFragment){
this.supportMapFragment = supportMapFragment;
return this;
}
....
MapRouteSubcomponent best guess:
#Subcomponent(modules = {MapRouteModule.class, ApplicationModule.class})
public interface MapRouteSubcomponent {
// allow to inject into our MapRoute class
void inject(MapRoute mapRoute);
#Subcomponent.Builder
interface Builder extends SubComponentBuilder<MapRouteSubcomponent> {
Builder mapRouteModule(MapRouteModule mapRouteModule);
}
#Module
public class MapRouteModule {
// What to put here?
}
And finally a subcomponent builder:
// from https://github.com/Zorail/SubComponent/blob/master/app/src/main/java/zorail/rohan/com/subcomponent/SubComponentBuilder.java
public interface SubComponentBuilder<V> {
V build();
}
At this point I am at a stand on where to go from here.

how to inject a uiBinder with #Inject (instead of GWT.create())?

Firstly, is doing such thing a good practice ?
I tried what seems to be the right way for me but wasn't successful :
public class FormViewImpl extends CompositeView implements HasUiHandlers<C>, FormView {
public interface SettlementInstructionsSearchFormViewUiBinder extends UiBinder<Widget, SettlementInstructionsSearchFormViewImpl> {}
#Inject
static FormViewImpl uiBinder;
#Inject
static Provider<DateEditorWidget> dateEditorProvider;
#UiField(provided = true)
MyComponent<String> myComp;
#UiField
DateEditorWidget effectiveDateFrom;
// .. other fields
#Inject
public FormViewImpl () {
myComp = new MyComponent<String>("lol");
if (uiBinder == null)
uiBinder = GWT.create(SettlementInstructionsSearchFormViewUiBinder.class);
initWidget(uiBinder.createAndBindUi(this));
}
#UiFactory
DateEditorWidget createDateEditor() {
return dateEditorProvider.get();
}
}
What other things than a class with no arguments is required ? In my company's project the same kind of code works at some other place. Sorry from the high level of noob here...
If you guys had any pointers it would be nice.
Thanks
Two issues:
First, two of your #Inject fields are static - have you done anything to make static fields be injected? Static fields don't get set when Gin (or Guice) creates new instances, those have to be set once and done. As they are static, they will never be garbage collected - this may be okay with you, or it might be a problem, and you should change them to instance fields. If you want to keep them static, then you must invoke requestStaticInjection in your module to ask Gin to initialize them when the ginjector is created.
Next, if you do choose to remove static, the uiBinder field must still be null in that constructor, because the fields can't have been injected yet! How do you set a field on an object that you haven't yet created? That's what you are expecting Gin to be able to do. Instead, consider passing that as an argument into the #Inject decorated constructor. You don't even need to save it as a field, since the widget will only use it the one time.
To have a class generated by GIN (doesn't matter if it is a uiBinder or not) it is not necessary for it to have a default constructor (i.e. the one without parameters). The class you want to inject must have the constructor annotated with #Inject:
#Inject
public InjectMeClass(Object a, Object b)
The other class which is injected, suppose it is a UiBinder, must have the injected fields annotated with #UiField(provided=true):
public class Injected extends Composite {
private static InjectedUiBinder uiBinder = GWT
.create(InjectedUiBinder.class);
interface InjectedUiBinder extends UiBinder<Widget, Injected> {
}
#UiField(provided=true)
InjectMeClass imc;
public Injected(final InjectMeClass imc) {
this.imc=imc;
initWidget(uiBinder.createAndBindUi(this));
}
So, back to your case:
#UiField(provided = true)
MyComponent<String> myComp;
#Inject
public FormViewImpl (MyComponent<String> myComp) {
this.myComp = myComp;
and for example:
public class MyComponent<T> extends Composite {
private T value;
#Inject
public MyComponent(T t) {
this.value = t;
...
}
...
}
In the GIN module you can have a provider:
#Provides
#Singleton
public MyComponent<String> createMyComponent() {
return new MyComponent<String>("lol");
}

How must one use a ListEditor as a child of another Editor?

I am using GWT 2.5.0
My intent was to create an editor hierarchy which binds to a ParentBean object. The ParentBean contains a List<Group>, and the Group bean has a List<ChildBean> and List<Group>. From the Editor tutorials I have found, it seemed simple enough to create an editor which contains a ListEditor as one of its sub-editors. But the parent editor never seems to properly initialize the sub ListEditor.
Here is an explanation of how I attempted to do this.
From the code below, I created a ParentBeanEditor which is composed of one other editor, GroupListEditor.
The GroupListEditor implements IsEditor<ListEditor<Group, GroupEditor>>.
Then, the GroupEditor contains a GroupListEditor subeditor and a ChildBeanEditor.
I initialized the ParentBeanEditor with a ParentBean which contained a list of Group objects, but no GroupEditor was ever constructed for any of the Group objects. I put break points in the EditorSource<GroupEditor>.create(int) method to verify that GroupEditors were being created for each Group in the ParentBean, but the break point was never hit (the ListEditor was not constructing editors).
I expected that the GroupListEditor would be initialized since it was a subeditor of ParentBeanEditor. Neither the list nor the editor chain was set in the GroupListEditor. I tried to set the list of the GroupListEditor subeditor directly in ParentBeanEditor by having it extend ValueAwareEditor<ParentBean>. Doing this, the break point I mentioned above was hit, and the GroupListEditor tried to attach a GroupEditor to the editor chain. But the editor chain was never set, and a NPE is thrown in ListEditorWrapper line 95.
Example
Here is the example where the GroupListEditor is not initializing as expected. The EditorChain is never set, and this results in a NPE being thrown in ListEditorWrapper line 95.
Data Model
public interface ParentBean {
...
List<Group> getGroups();
}
public interface Group {
...
List<ChildBean> getChildBeans();
List<Group> getGroups();
}
public interface ChildBean {
// ChildType is an enum
ChildType getChildType();
}
Editors
The ParentBean Editor
public class ParentBeanEditor extends Composite implements ValueAwareEditor<ParentBean> {
interface ParentBeanEditorUiBinder extends UiBinder<Widget, ParentBeanEditor> {
}
private static ParentBeanEditorUiBinder BINDER = GWT.create(ParentBeanEditorUiBinder.class);
#Path("groups")
#UiField
GroupListEditor groupsEditor;
public ParentBeanEditor() {
initWidget(BINDER.createAndBindUi(this));
}
#Override
public void setDelegate(EditorDelegate<ParentBean> delegate) {}
#Override
public void flush() {}
#Override
public void onPropertyChange(String... paths) {}
#Override
public void setValue(ParentBean value) {
groupsEditor.asEditor().setValue(value.getGroups());
}
}
GroupListEditor
public class GroupListEditor extends Composite implements IsEditor<ListEditor<Group, GroupEditor>>{
interface GroupListEditorUiBinder extends UiBinder<VerticalLayoutContainer, TemplateGroupListEditor> {
}
private static GroupListEditorUiBinder BINDER = GWT.create(GroupListEditorUiBinder.class);
private class GroupEditorSource extends EditorSource<GroupEditor> {
private final GroupListEditor GroupListEditor;
public GroupEditorSource(GroupListEditor GroupListEditor) {
this.GroupListEditor = GroupListEditor;
}
#Override
public GroupEditor create(int index) {
GroupEditor subEditor = new GroupEditor();
GroupListEditor.getGroupsContainer().insert(subEditor, index);
return subEditor;
}
#Override
public void dispose(GroupEditor subEditor){
subEditor.removeFromParent();
}
#Override
public void setIndex(GroupEditor editor, int index){
GroupListEditor.getGroupsContainer().insert(editor, index);
}
}
private final ListEditor<Group, GroupEditor> editor = ListEditor.of(new GroupEditorSource(this));
#UiField
VerticalLayoutContainer groupsContainer;
public GroupListEditor() {
initWidget(BINDER.createAndBindUi(this));
}
public InsertResizeContainer getGroupsContainer() {
return groupsContainer;
}
#Override
public ListEditor<Group, GroupEditor> asEditor() {
return editor;
}
}
GroupEditor
public class GroupEditor extends Composite implements ValueAwareEditor<Group> {
interface GroupEditorUiBinder extends UiBinder<Widget, GroupEditor> {}
private static GroupEditorUiBinder BINDER = GWT.create(GroupEditorUiBinder.class);
#Ignore
#UiField
FieldSet groupField;
#UiField
#Path("childBeans")
ChildBeanListEditor childBeansEditor;
#UiField
#Path("groups")
GroupListEditor groupsEditor;
public GroupEditor() {
initWidget(BINDER.createAndBindUi(this));
}
#Override
public void setDelegate(EditorDelegate<Group> delegate) {}
#Override
public void flush() { }
#Override
public void onPropertyChange(String... paths) {}
#Override
public void setValue(Group value) {
// When the value is set, update the FieldSet header text
groupField.setHeadingText(value.getLabel());
groupsEditor.asEditor().setValue(value.getGroups());
childBeansEditor.asEditor().setValue(value.getChildBeans());
}
}
The ChildBeanListEditor will be using the polymorphic editor methodology mention here. Meaning that a specific leafeditor is attached to the editor chain based off the value of the ChildBean.getType() enum. However, I am not showing that code since I am unable to get the GroupListEditor to properly initialize.
Two concerns about your code:
Why is ParentBeanEditor.setValue feeding data to its child? It appears from this that this was a way to work around the fact that the GroupListEditor was not getting data. This should not be necessary, and may be causing your NPE by wiring up a subeditor before it is time.
Then, assuming this, it seems to follow that the GroupListEditor isn't getting data or a chain. The lack of these suggests that the Editor Framework isn't aware of it. All the basic wiring looks correct, except for one thing: Where is your EditorDriver?
If you are trying to use the editor framework by just invoking parentBeanEditor.setValue and do not have a driver, you are missing most of the key features of this tool. You should be able to ask the driver to do this work for you, and not not to call your own setValue methods throughout the tree.
A quick test - try breaking something in such a way that shouldn't compile. This would include changing the #Path annotation to something like #Path("doesnt.exist"), and trying to run the app. You should get a rebind error, as there is no such path. If you do not get this, you definitely need to be creating and user a driver.
First, try driver itself:
It isn't quite clear from your code what kind of models you are using, so I'll assume that the SimpleBeanEditorDriver will suffice for you - the other main option is the RequestFactoryEditorDriver, but it isn't actually necessary to use the RequestFactoryEditorDriver even if you use RequestFactory.
The Driver is generic on two things: The bean type you intend to edit, and the editor type that will be responsible for it. It uses these generic arguments to traverse both objects and generate code required to bind the data. Yours will likely look like this:
public interface Driver extends
SimpleBeanEditorDriver<ParentBean, ParentBeanEditor> { }
We declare these just like UiBinder interfaces - just enough details to let the code generator look around and wire up essentials. Now that we have the type, we create an instance. This might be created in your view, but may still be owned and controlled by some presenter logic. Note that this is not like uibinder - we cannot keep a static instance, since each one is wired directly to a specific editor instance.
Two steps here - create the driver, and initialize it to a given editor instance (and all sub-editors, which will be automatic):
ParentBeanEditor editor = ...;
Driver driver = GWT.create(Driver.class);
driver.initialize(editor);
Next we bind data by passing it to the driver - it is its responsibility to pass sub-objects to each sub-editor's setValue method, as well as wiring up the editor chain required by the ListEditor.
driver.edit(parentInstance);
Now the user can view or edit the object, as your application requirement works. When editing is complete (say they click the Save button), we can flush all changes from the editors back into the instance (and note that we are still using the same driver instance, still holding that specific editor instance):
ParentBean instance = driver.flush();
Note that we also could have just invoked driver.flush() and reused the earlier reference to parentInstance - its the same thing.
Assuming this has all made sense so far, there is some cleanup that can be done - ParentBeanEditor isn't really using the ValueAwareEditor methods, so they can be removed:
public class ParentBeanEditor extends Composite implements Editor<ParentBean> {
interface ParentBeanEditorUiBinder extends UiBinder<Widget, ParentBeanEditor> {
}
private static ParentBeanEditorUiBinder BINDER = GWT.create(ParentBeanEditorUiBinder.class);
#Path("groups")
#UiField
GroupListEditor groupsEditor;
public ParentBeanEditor() {
initWidget(BINDER.createAndBindUi(this));
}
}
Observe that we still implement Editor<ParentBean> - this allows the driver generics to make sense, and declares that we have fields that might themselves be sub-editors to be wired up. Also: it turns out that the #Path annotation here is unnecessary - any field/method with the same name as the property (getGroups()/setGroups() ==> groups) or the name of the property plus 'Editor' (groupsEditor). If the editor contains a field that is an editor but doesn't map to a property in the bean, you'll get an error. If you actually did this on purpose (say, a text box for searching, not for data entry), you can tag it with #Ignore.

GWT Null objects in #UiHandler methods

I am using GWT 2.4 with MVP.
Here is my view object:
public class LoginWidget extends Composite implements LoginWidgetView {
interface Binder extends UiBinder<Widget, LoginWidget> {
}
private static final Binder BINDER = GWT.create(Binder.class);
#UiField Anchor settings;
public LoginWidget() {
initWidget(BINDER.createAndBindUi(this));
}
#UiHandler("settings")
void handleSettingsClick(ClickEvent e) {
presenter.showSettings();
}
private Presenter presenter;
#Override
public void setPresenter(Presenter presenter) {
this.presenter = presenter;
}
}
I am setting the view´s presenter by
...
getLoginWidget().setPresenter(new LoginWidgetPresenter(placeController));
LoginWidgetPresenter of course implements the view´s Presenter interface. But when I click on the settings anchor, the presenter reference is still null, so presenter.showSettings() throws a NullPointerException.
I suppose that after calling the LoginWidget´s constructor and initializing the widget by
initWidget(BINDER.createAndBindUi(this));
the click handling code in my #UiHandler("settings") method ignores changes to the used objects like my presenter object??
Is there a way to set the presenter object after calling the initWidget() method?
Or is it possible to customize the #UiHandler/initWidget()-behaviour that I can set my presenter afterwards?
Thanks, Manuel
I implement MVP in another way and UIBinder work for my. Maybe if you pass the LoginWidgetPresenter in LoginWidget constructor it works.
public LoginWidget(Presenter presenter) {
this.presenter = presenter;
initWidget(BINDER.createAndBindUi(this));
}
...
getLoginWidget(new LoginWidgetPresenter(placeController));
There are lot of things, which could have gone wrong. The easiest thing is to try to debug your code, by putting breakpoints handleSettings and 'setPresenter' methods.
My guess is that one of following is happening:
setPresenter is never actually called
or
getLoginWidget() always returns a new instance of the widget, and it is quite possible that you are setting presenter on one instance of login widget, but displaying totally different instance of the widget
or
You have getLoginWidget().setPresenter(null) somewhere in your code
or any other guess. It is much more easier to debug, and see for yourself, where and how presenter instance is passed. Anyway, UiBinder will not erase your field values (unless it is modified by someone else to make fun of you)

gwt uibinder in an abstract parent class

i'm wondering if there's a way to build the gwt uibinder logic into an abstract parent class so that i don't have to repeat the code in every class i want to bind.
for example, i'd like to be able to do something like this:
public abstract class BasePanel<Panel extends BasePanel> extends Composite {
interface Binder<BinderPanel extends BasePanel> extends UiBinder<Widget, BinderPanel> { }
private static final Binder binder = GWT.create(Binder<Panel>.class);
public BasePanel() {
initWidget(binder.createAndBindUi(this));
init();
}
}
basically this would allow any child classes to do something like this:
public MyPanel extends BasePanel<MyPanel> {
//my code here
}
the default constructor would take care of all the code to bind MyPanel to MyPanel.ui.xml.
basically i want to be lazy and only have to build the interface and the binder once so that it's done in a common way. thoughts?
thanks in advance.
Proper way to do abstract UI binder classes is to define a super class that will contain logic that is common to all subclass widgets. This class can have fields marked as #UiField, event handlers and anything else that goes into the UI binder class. And child classes actually have UI binder instantiation logic. So something like this:
public abstract BaseWidget extends Composite {
#UiField TextBox textBoxCommon1;
#UiField TextBox textBoxCommon2;
#UiHandler("textBoxCommon1")
void onTextBoxCommon1Changed( ValueChangeEvent<String> event ) {
//...
}
#UiHandler("textBoxCommon2")
void onTextBoxCommon2Changed( ValueChangeEvent<String> event ) {
//...
}
}
public class SomeWidget extends BaseWidget {
interface SomeWidgetUiBinder extends UiBinder<Widget,SomeWidget> {}
private static SomeWidgetUiBinder uiBinder = GWT.create(SomeWidgetUiBinder.class);
#UiField Button someWidgetButton;
public SomeWidget() {
initWidget(uiBinder.createAndBindUi(this));
}
#UiHandler("someWidgetButton")
void onButtonClicked(ClickEvent e) {
Window.alert(textBoxCommon1.getValue());
}
}