Author: hlship
Date: Mon Oct 17 19:12:44 2011
New Revision: 1185333
URL: http://svn.apache.org/viewvc?rev=1185333&view=rev
Log:
TAP5-1630: A TreeModelAdapter that returns null from getChildren() causes an NPE
Modified:
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/tree/DefaultTreeModel.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/tree/TreeModelAdapter.java
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/Stuff.java
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/StuffTreeModelAdapter.java
Modified:
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/tree/DefaultTreeModel.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/tree/DefaultTreeModel.java?rev=1185333&r1=1185332&r2=1185333&view=diff
==============================================================================
---
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/tree/DefaultTreeModel.java
(original)
+++
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/tree/DefaultTreeModel.java
Mon Oct 17 19:12:44 2011
@@ -27,9 +27,9 @@ import java.util.Map;
/**
* A default implementation of TreeModel that starts with a {@link
ValueEncoder} (for the element to string conversion),
* a {@link TreeModelAdapter}, and a list of root nodes.
- * <p>
+ * <p/>
* This implementation is <em>not</em> thread safe.
- *
+ *
* @param <T>
* @since 5.3
*/
@@ -86,7 +86,15 @@ public class DefaultTreeModel<T> impleme
public List<TreeNode<T>> getChildren()
{
if (children == null)
- children =
F.flow(adapter.getChildren(value)).map(toTreeNode).toList();
+ {
+ List<T> childValues = adapter.getChildren(value);
+
+ boolean empty = childValues == null || childValues.isEmpty();
+
+ children = empty
+ ? emptyTreeNodeList()
+ : F.flow(childValues).map(toTreeNode).toList();
+ }
return children;
}
@@ -96,17 +104,19 @@ public class DefaultTreeModel<T> impleme
return adapter.getLabel(value);
}
+ private List<TreeNode<T>> emptyTreeNodeList()
+ {
+ return Collections.emptyList();
+ }
+
}
/**
* Creates a new model starting from a single root element.
- *
- * @param encoder
- * used to convert values to strings and vice-versa
- * @param adapter
- * adapts elements to the tree
- * @param root
- * defines the root node of the model
+ *
+ * @param encoder used to convert values to strings and vice-versa
+ * @param adapter adapts elements to the tree
+ * @param root defines the root node of the model
*/
public DefaultTreeModel(ValueEncoder<T> encoder, TreeModelAdapter<T>
adapter, T root)
{
@@ -115,13 +125,10 @@ public class DefaultTreeModel<T> impleme
/**
* Standard constructor.
- *
- * @param encoder
- * used to convert values to strings and vice-versa
- * @param adapter
- * adapts elements to the tree
- * @param roots
- * defines the root nodes of the model
+ *
+ * @param encoder used to convert values to strings and vice-versa
+ * @param adapter adapts elements to the tree
+ * @param roots defines the root nodes of the model
*/
public DefaultTreeModel(ValueEncoder<T> encoder, TreeModelAdapter<T>
adapter, List<T> roots)
{
Modified:
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/tree/TreeModelAdapter.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/tree/TreeModelAdapter.java?rev=1185333&r1=1185332&r2=1185333&view=diff
==============================================================================
---
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/tree/TreeModelAdapter.java
(original)
+++
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/tree/TreeModelAdapter.java
Mon Oct 17 19:12:44 2011
@@ -18,35 +18,36 @@ import java.util.List;
/**
* Used with {@link DefaultTreeModel} to define how to extract labels and
child nodes from a value.
- *
+ *
* @since 5.3
*/
public interface TreeModelAdapter<T>
{
/**
* Determines if the value is a leaf or a (potential) container of
children.
- *
+ *
* @see TreeNode#isLeaf()
*/
boolean isLeaf(T value);
/**
* Returns true if the value has children (only invoked for non-leaf
values).
- *
+ *
* @see TreeNode#getHasChildren()
*/
boolean hasChildren(T value);
/**
* Returns the children, in the order they should be presented to the
client.
- *
+ * This should return the childen in the correct presentation or, or
return null or an empty list.
+ *
* @see TreeNode#getChildren()
*/
List<T> getChildren(T value);
/**
* Returns a text label for the value, which may be presented to the
client.
- *
+ *
* @see TreeNode#getLabel()
*/
String getLabel(T value);
Modified:
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/Stuff.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/Stuff.java?rev=1185333&r1=1185332&r2=1185333&view=diff
==============================================================================
---
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/Stuff.java
(original)
+++
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/Stuff.java
Mon Oct 17 19:12:44 2011
@@ -28,7 +28,7 @@ public class Stuff
public final String name;
- public final List<Stuff> children = CollectionFactory.newList();
+ public List<Stuff> children;
public Stuff(String name)
{
@@ -39,7 +39,7 @@ public class Stuff
{
for (String name : names)
{
- children.add(new Stuff(name));
+ addChild(new Stuff(name));
}
return this;
@@ -47,6 +47,11 @@ public class Stuff
public Stuff addChild(Stuff child)
{
+ if (children == null)
+ {
+ children = CollectionFactory.newList();
+ }
+
children.add(child);
return this;
@@ -87,7 +92,8 @@ public class Stuff
ROOT.addChild(numbers);
}
- public static TreeModel<Stuff> createTreeModel() {
+ public static TreeModel<Stuff> createTreeModel()
+ {
ValueEncoder<Stuff> encoder = new StuffValueEncoder();
return new DefaultTreeModel<Stuff>(encoder, new
StuffTreeModelAdapter(), Stuff.ROOT.children);
Modified:
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/StuffTreeModelAdapter.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/StuffTreeModelAdapter.java?rev=1185333&r1=1185332&r2=1185333&view=diff
==============================================================================
---
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/StuffTreeModelAdapter.java
(original)
+++
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/StuffTreeModelAdapter.java
Mon Oct 17 19:12:44 2011
@@ -14,20 +14,20 @@
package org.apache.tapestry5.integration.app1;
-import java.util.List;
-
import org.apache.tapestry5.tree.TreeModelAdapter;
+import java.util.List;
+
public class StuffTreeModelAdapter implements TreeModelAdapter<Stuff>
{
public boolean isLeaf(Stuff value)
{
- return value.children.isEmpty();
+ return !hasChildren(value);
}
public boolean hasChildren(Stuff value)
{
- return !value.children.isEmpty();
+ return value.children != null && !value.children.isEmpty();
}
public List<Stuff> getChildren(Stuff value)