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

a 夏天 提交于 2019-12-06 14:23:51

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!