Fix a NullPointerException in Editor framework when a null sub-Editor is encountered during traversal.
Patch by: bobv
Review by: rjrjr
Review at http://gwt-code-reviews.appspot.com/1354802
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@9705 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/editor/client/impl/AbstractEditorContext.java b/user/src/com/google/gwt/editor/client/impl/AbstractEditorContext.java
index 64b04e4..8f33519 100644
--- a/user/src/com/google/gwt/editor/client/impl/AbstractEditorContext.java
+++ b/user/src/com/google/gwt/editor/client/impl/AbstractEditorContext.java
@@ -41,11 +41,6 @@
private final LeafValueEditor<T> leafValueEditor;
private final ValueAwareEditor<T> valueAwareEditor;
- public AbstractEditorContext(AbstractEditorDelegate<T, ?> delegate) {
- this(delegate.getEditor(), delegate.getPath());
- this.delegate = delegate;
- }
-
public AbstractEditorContext(Editor<T> editor, String path) {
this.editor = editor;
this.path = path;
@@ -123,6 +118,10 @@
return isHalted;
}
+ public void setEditorDelegate(AbstractEditorDelegate<T, ?> delegate) {
+ this.delegate = delegate;
+ }
+
public abstract void setInModel(T data);
public void traverse(EditorVisitor visitor, AbstractEditorDelegate<?, ?> next) {
diff --git a/user/src/com/google/gwt/editor/client/impl/RootEditorContext.java b/user/src/com/google/gwt/editor/client/impl/RootEditorContext.java
index 5f82cda..3723c13 100644
--- a/user/src/com/google/gwt/editor/client/impl/RootEditorContext.java
+++ b/user/src/com/google/gwt/editor/client/impl/RootEditorContext.java
@@ -28,7 +28,8 @@
public RootEditorContext(AbstractEditorDelegate<T, ?> editorDelegate,
Class<T> editedType, T value) {
- super(editorDelegate);
+ super(editorDelegate.getEditor(), editorDelegate.getPath());
+ setEditorDelegate(editorDelegate);
this.editedType = editedType;
this.value = value;
}
diff --git a/user/src/com/google/gwt/editor/rebind/AbstractEditorDriverGenerator.java b/user/src/com/google/gwt/editor/rebind/AbstractEditorDriverGenerator.java
index a080e37..fdb0427 100644
--- a/user/src/com/google/gwt/editor/rebind/AbstractEditorDriverGenerator.java
+++ b/user/src/com/google/gwt/editor/rebind/AbstractEditorDriverGenerator.java
@@ -27,7 +27,6 @@
import com.google.gwt.editor.client.Editor;
import com.google.gwt.editor.client.EditorVisitor;
import com.google.gwt.editor.client.impl.AbstractEditorContext;
-import com.google.gwt.editor.client.impl.AbstractEditorDelegate;
import com.google.gwt.editor.client.impl.RootEditorContext;
import com.google.gwt.editor.rebind.model.EditorData;
import com.google.gwt.editor.rebind.model.EditorModel;
@@ -192,17 +191,18 @@
sw.println("getEditorChain().accept(visitor);");
}
for (EditorData d : data) {
+ if (d.isDelegateRequired()) {
+ sw.println("if (%s != null) ", delegateFields.get(d));
+ }
sw.println("{");
sw.indent();
String editorContextName = getEditorContext(delegateData, d);
+ sw.println(
+ "%s ctx = new %s(getObject(), editor.%s, appendPath(\"%s\"));",
+ editorContextName, editorContextName, d.getSimpleExpression(),
+ d.getDeclaredPath());
if (d.isDelegateRequired()) {
- sw.println("%s ctx = new %s(getObject(), %s);", editorContextName,
- editorContextName, delegateFields.get(d));
- } else {
- sw.println(
- "%s ctx = new %s(getObject(), editor.%s, appendPath(\"%s\"));",
- editorContextName, editorContextName, d.getSimpleExpression(),
- d.getDeclaredPath());
+ sw.println("ctx.setEditorDelegate(%s);", delegateFields.get(d));
}
sw.println("ctx.traverse(visitor, %s);", d.isDelegateRequired()
? delegateFields.get(d) : "null");
@@ -250,19 +250,13 @@
if (pw != null) {
ClassSourceFileComposerFactory f = new ClassSourceFileComposerFactory(
pkg, simpleName);
- String editedSourceName = data.getEditedType().getQualifiedSourceName();
+ String editedSourceName = data.getEditedType().getParameterizedQualifiedSourceName();
f.setSuperclass(AbstractEditorContext.class.getCanonicalName() + "<"
+ editedSourceName + ">");
SourceWriter sw = f.createSourceWriter(context, pw);
String parentSourceName = parent.getEditedType().getQualifiedSourceName();
sw.println("private final %s parent;", parentSourceName);
- sw.println("public %s(%s parent, %s<%s, ?> delegate) {", simpleName,
- parentSourceName, AbstractEditorDelegate.class.getCanonicalName(),
- editedSourceName);
- sw.indentln("super(delegate);");
- sw.indentln("this.parent = parent;");
- sw.println("}");
sw.println("public %s(%s parent, %s<%s> editor, String path) {",
simpleName, parentSourceName, Editor.class.getCanonicalName(),
@@ -283,8 +277,8 @@
sw.println("}");
sw.println(
- "@Override public Class<%1$s> getEditedType() { return %1$s.class; }",
- editedSourceName);
+ "@Override public Class getEditedType() { return %s.class; }",
+ data.getEditedType().getQualifiedSourceName());
sw.println("@Override public %s getFromModel() {", editedSourceName);
sw.indentln("return (parent != null && %s) ? parent%s%s : null;",
diff --git a/user/test/com/google/gwt/editor/client/SimpleBeanEditorTest.java b/user/test/com/google/gwt/editor/client/SimpleBeanEditorTest.java
index 2f5b990..66d7c9f 100644
--- a/user/test/com/google/gwt/editor/client/SimpleBeanEditorTest.java
+++ b/user/test/com/google/gwt/editor/client/SimpleBeanEditorTest.java
@@ -321,6 +321,37 @@
assertEquals("Should see this", person.getName());
}
+ public void testEditorWithNullSubEditor() {
+ PersonEditor editor = new PersonEditor();
+ editor.addressEditor = null;
+ PersonEditorDriver driver = GWT.create(PersonEditorDriver.class);
+ driver.initialize(editor);
+ driver.edit(person);
+
+ assertEquals("Alice", editor.name.getValue());
+ editor.name.setValue("New name");
+ driver.flush();
+ assertEquals("New name", person.getName());
+
+ /*
+ * Verify that changing the editor structure without re-initializing is a
+ * no-op.
+ */
+ editor.name.setValue("Should see this");
+ editor.addressEditor = new AddressEditor();
+ editor.addressEditor.city.setValue("Should not see this");
+ driver.flush();
+ assertEquals("Should see this", person.getName());
+ assertEquals("City", person.getAddress().getCity());
+
+ // Re-initialize and check that flushing works again
+ driver.initialize(editor);
+ driver.edit(person);
+ editor.addressEditor.city.setValue("Should see this");
+ driver.flush();
+ assertEquals("Should see this", person.getAddress().getCity());
+ }
+
/**
* Test the use of the IsEditor interface that allows a view object to
* encapsulate its Editor.