我正在使用GWT 2.5.0
我的目的是创建一个绑定到ParentBean
对象的编辑器层次结构。 ParentBean
包含List<Group>
,Group
bean包含List<ChildBean>
和List<Group>
。从我发现的编辑器教程中,创建一个包含ListEditor作为其子编辑器的编辑器似乎很简单。但父编辑似乎从未正确初始化子ListEditor。
以下解释了我是如何尝试这样做的。
从下面的代码中,我创建了一个ParentBeanEditor
,它由另一个编辑器GroupListEditor
组成。
GroupListEditor
实施IsEditor<ListEditor<Group, GroupEditor>>
然后,GroupEditor
包含GroupListEditor
子编辑者和ChildBeanEditor
。
我使用ParentBeanEditor
初始化了ParentBean
,其中包含Group
个对象的列表,但是没有为任何GroupEditor
个对象构建Group
。
我在EditorSource<GroupEditor>.create(int)
方法中设置了断点,以验证GroupEditor
中每个Group
是否正在创建ParentBean
,但断点从未被点击过(ListEditor没有构建编辑器。)
我预计GroupListEditor
会被初始化,因为它是ParentBeanEditor
的副编辑。列表和编辑器链都没有在GroupListEditor
中设置。我尝试通过扩展GroupListEditor
直接在ParentBeanEditor
中设置ValueAwareEditor<ParentBean>
子编辑器的列表。这样做,上面提到的断点被击中,GroupListEditor
试图将GroupEditor
附加到编辑器链。但编辑链从未设置过,NPE被引入ListEditorWrapper
第95行。
以下是GroupListEditor
未按预期初始化的示例。永远不会设置EditorChain
,这会导致NPE被ListEditorWrapper
第95行抛出。
public interface ParentBean {
...
List<Group> getGroups();
}
public interface Group {
...
List<ChildBean> getChildBeans();
List<Group> getGroups();
}
public interface ChildBean {
// ChildType is an enum
ChildType getChildType();
}
ParentBean编辑器
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());
}
}
ChildBeanListEditor
将使用提及here的多态编辑器方法。这意味着特定的leafeditor基于ChildBean.getType()
枚举的值附加到编辑器链。但是,我没有显示该代码,因为我无法正确初始化GroupListEditor
。
答案 0 :(得分:0)
关于您的代码的两个问题:
为什么ParentBeanEditor.setValue
向其孩子提供数据?从中可以看出,这是一种解决GroupListEditor
无法获取数据这一事实的方法。这不应该是必要的,并且可能在时间之前通过连接子编辑器来引起NPE。
然后,假设这一点,似乎遵循GroupListEditor
没有获取数据或链。缺乏这些表明编辑框架没有意识到这一点。所有基本布线看起来都是正确的,除了一件事:您的EditorDriver在哪里?
如果您只是通过调用parentBeanEditor.setValue
并且没有驱动程序来尝试使用编辑器框架,那么您将缺少此工具的大多数关键功能。您应该能够让驱动程序为您完成这项工作,而不是在整个树中调用您自己的setValue方法。
快速测试 - 尝试以不应编译的方式破坏某些东西。这包括将@Path
注释更改为@Path("doesnt.exist")
,并尝试运行该应用。你应该得到一个重新绑定错误,因为没有这样的路径。如果你没有得到这个,你肯定需要创建和使用驱动程序。
首先,尝试驱动程序:
从你的代码中不太清楚你正在使用什么样的模型,所以我假设SimpleBeanEditorDriver
对你来说就足够了 - 另一个主要选项是RequestFactoryEditorDriver
,但是即使您使用RequestFactory,也不一定需要使用RequestFactoryEditorDriver
。
驱动程序在两个方面是通用的:您打算编辑的bean类型以及将负责它的编辑器类型。它使用这些通用参数遍历两个对象并生成绑定数据所需的代码。你的可能会是这样的:
public interface Driver extends
SimpleBeanEditorDriver<ParentBean, ParentBeanEditor> { }
我们声明这些就像UiBinder
接口一样 - 只需要足够的细节让代码生成器环顾四周并连接必需品。现在我们有了类型,我们创建了一个实例。这可能会在您的视图中创建,但仍可能由某些演示者逻辑拥有和控制。请注意,这是 not ,就像uibinder一样 - 我们无法保留静态实例,因为每个实例都直接连接到特定的编辑器实例。
这里有两个步骤 - 创建驱动程序,并将其初始化为给定的编辑器实例(以及所有子编辑器,这将是自动的):
ParentBeanEditor editor = ...;
Driver driver = GWT.create(Driver.class);
driver.initialize(editor);
接下来,我们通过将数据传递给驱动程序来绑定数据 - 它有责任将子对象传递给每个子编辑器的setValue方法,以及连接ListEditor所需的编辑器链。
driver.edit(parentInstance);
现在,用户可以查看或编辑对象,因为您的应用程序需求正常。编辑完成后(比如他们单击“保存”按钮),我们可以将编辑器中的所有更改刷新回实例(并注意我们仍在使用相同的驱动程序实例,仍然保留该特定编辑器实例):
ParentBean instance = driver.flush();
请注意,我们也可以刚刚调用driver.flush()
并重复使用之前对parentInstance
的引用 - 这是同样的事情。
假设到目前为止这一切都有意义,可以做一些清理 - ParentBeanEditor并没有真正使用ValueAwareEditor方法,所以可以删除它们:
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));
}
}
观察我们仍然实现Editor<ParentBean>
- 这允许驱动程序泛型有意义,并声明我们有可能本身是子编辑器的字段被连接起来。另外:事实证明此处的@Path
注释是不必要的 - 任何与属性同名的字段/方法(getGroups()
/ setGroups()
==&gt; groups
)或者属性的名称加上'编辑'(groupsEditor
)。如果编辑器包含一个编辑器但不映射到bean中的属性的字段,则会出现错误。如果您实际上是故意这样做的(例如,用于搜索的文本框,而不是用于数据输入),则可以使用@Ignore
对其进行标记。