From 946de09d26c25174768e3b210b5d73722d5f3fcf Mon Sep 17 00:00:00 2001
From: Shawn Heisey
Date: Mon, 20 May 2013 07:39:55 +0000
Subject: [PATCH] SOLR-4048: improve and clean up findRecursive
git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1484386 13f79535-47bb-0310-9956-ffa450edef68
---
.../apache/solr/common/util/NamedList.java | 121 +++++++++++-------
.../solr/common/util/NamedListTest.java | 76 +++++++----
2 files changed, 125 insertions(+), 72 deletions(-)
diff --git a/solr/solrj/src/java/org/apache/solr/common/util/NamedList.java b/solr/solrj/src/java/org/apache/solr/common/util/NamedList.java
index f94c8ef50be..d596afce7f3 100644
--- a/solr/solrj/src/java/org/apache/solr/common/util/NamedList.java
+++ b/solr/solrj/src/java/org/apache/solr/common/util/NamedList.java
@@ -23,8 +23,6 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
-
-
/**
* A simple container class for modeling an ordered list of name/value pairs.
*
@@ -50,9 +48,10 @@ import java.util.Map;
* or simply use a regular {@link Map}
*
*
- *
*/
public class NamedList implements Cloneable, Serializable, Iterable> {
+
+ private static final long serialVersionUID = 1957981902839867821L;
protected final List nvPairs;
/** Creates an empty instance */
@@ -60,7 +59,6 @@ public class NamedList implements Cloneable, Serializable, Iterable();
}
-
/**
* Creates a NamedList instance containing the "name,value" pairs contained in the
* Entry[].
@@ -83,8 +81,8 @@ public class NamedList implements Cloneable, Serializable, Iterable
- * When using this constructor, runtime typesafety is only guaranteed if the all
- * even numbered elements of the input list are of type "T".
+ * When using this constructor, runtime type safety is only guaranteed if
+ * all even numbered elements of the input list are of type "T".
*
*
* @param nameValuePairs underlying List which should be used to implement a NamedList
@@ -156,6 +154,7 @@ public class NamedList implements Cloneable, Serializable, Iterable implements Cloneable, Serializable, Iterable implements Cloneable, Serializable, Iterable implements Cloneable, Serializable, Iterable implements Cloneable, Serializable, Iterable implements Cloneable, Serializable, Iterable list = null;
- T value = null;
- for (String key : args) {
- /* First pass: this list. Later passes: previous value. */
- if (list == null) {
- list = this;
- }
- else
- {
- if (NamedList.class.isInstance(value)) {
- list = (NamedList) value;
+ public Object findRecursive(String... args) {
+ NamedList> currentList = null;
+ Object value = null;
+ for (int i = 0; i < args.length; i++) {
+ String key = args[i];
+ /*
+ * The first time through the loop, the current list is null, so we assign
+ * it to this list. Then we retrieve the first key from this list and
+ * assign it to value.
+ *
+ * On the next loop, we check whether the retrieved value is a NamedList.
+ * If it is, then we drop down to that NamedList, grab the value of the
+ * next key, and start the loop over. If it is not a NamedList, then we
+ * assign the value to null and break out of the loop.
+ *
+ * Assigning the value to null and then breaking out of the loop seems
+ * like the wrong thing to do, but there's a very simple reason that it
+ * works: If we have reached the last key, then the loop ends naturally
+ * after we retrieve the value, and that code is never executed.
+ */
+ if (currentList == null) {
+ currentList = this;
+ } else {
+ if (value instanceof NamedList) {
+ currentList = (NamedList>) value;
} else {
value = null;
break;
}
}
- value = list.get(key);
+ /*
+ * We do not need to do a null check on currentList for the following
+ * assignment. The instanceof check above will fail if the current list is
+ * null, and if that happens, the loop will end before this point.
+ */
+ value = currentList.get(key, 0);
}
return value;
}
@@ -313,12 +340,12 @@ public class NamedList implements Cloneable, Serializable, Iterable implements Map.Entry {
-
+ public static final class NamedListEntry implements Map.Entry {
+
public NamedListEntry() {
}
@@ -335,7 +362,7 @@ public class NamedList implements Cloneable, Serializable, Iterable implements Cloneable, Serializable, Iterable args) {
- for( Map.Entry entry : args.entrySet() ) {
- add( entry.getKey(), entry.getValue() );
+ for (Map.Entry entry : args.entrySet() ) {
+ add(entry.getKey(), entry.getValue());
}
return args.size()>0;
}
@@ -376,7 +403,6 @@ public class NamedList implements Cloneable, Serializable, Iterable(newList);
}
-
//----------------------------------------------------------------------------
// Iterable interface
//----------------------------------------------------------------------------
@@ -408,14 +434,12 @@ public class NamedList implements Cloneable, Serializable, Iterable implements Cloneable, Serializable, Iterable implements Cloneable, Serializable, Iterable implements Cloneable, Serializable, Iterable nl = (NamedList>) obj;
return this.nvPairs.equals(nl.nvPairs);
}
}
diff --git a/solr/solrj/src/test/org/apache/solr/common/util/NamedListTest.java b/solr/solrj/src/test/org/apache/solr/common/util/NamedListTest.java
index 176c2195621..75459c8b4bd 100644
--- a/solr/solrj/src/test/org/apache/solr/common/util/NamedListTest.java
+++ b/solr/solrj/src/test/org/apache/solr/common/util/NamedListTest.java
@@ -29,6 +29,7 @@ public class NamedListTest extends LuceneTestCase {
assertEquals("value1", value);
assertEquals(1, nl.size());
}
+
public void testRecursive() {
// key1
// key2
@@ -37,6 +38,7 @@ public class NamedListTest extends LuceneTestCase {
// --- key2b1
// --- key2b2
// - key2c
+ // - k2int1
// key3
// - key3a
// --- key3a1
@@ -44,50 +46,78 @@ public class NamedListTest extends LuceneTestCase {
// --- key3a3
// - key3b
// - key3c
- NamedList nl2b = new NamedList();
+
+ // this is a varied NL structure.
+ NamedList nl2b = new NamedList();
nl2b.add("key2b1", "value2b1");
nl2b.add("key2b2", "value2b2");
- NamedList nl3a = new NamedList();
+ NamedList nl3a = new NamedList();
nl3a.add("key3a1", "value3a1");
nl3a.add("key3a2", "value3a2");
nl3a.add("key3a3", "value3a3");
NamedList nl2 = new NamedList();
nl2.add("key2a", "value2a");
nl2.add("key2b", nl2b);
- int int1 = 5;
- Integer int2 = 7;
- int int3 = 48;
- nl2.add("k2int1", int1);
- nl2.add("k2int2", int2);
- nl2.add("k2int3", int3);
+ nl2.add("k2int1", (int) 5);
NamedList nl3 = new NamedList();
nl3.add("key3a", nl3a);
nl3.add("key3b", "value3b");
nl3.add("key3c", "value3c");
+ nl3.add("key3c", "value3c2");
NamedList nl = new NamedList();
nl.add("key1", "value1");
nl.add("key2", nl2);
nl.add("key3", nl3);
-
+
+ // Simple three-level checks.
String test1 = (String) nl.findRecursive("key2", "key2b", "key2b2");
- assertEquals(test1, "value2b2");
+ assertEquals("value2b2", test1);
String test2 = (String) nl.findRecursive("key3", "key3a", "key3a3");
- assertEquals(test2, "value3a3");
+ assertEquals("value3a3", test2);
+ // Two-level check.
String test3 = (String) nl.findRecursive("key3", "key3c");
- assertEquals(test3, "value3c");
+ assertEquals("value3c", test3);
+ // Checking that invalid values return null.
String test4 = (String) nl.findRecursive("key3", "key3c", "invalid");
- assertEquals(test4, null);
+ assertEquals(null, test4);
String test5 = (String) nl.findRecursive("key3", "invalid", "invalid");
- assertEquals(test5, null);
+ assertEquals(null, test5);
String test6 = (String) nl.findRecursive("invalid", "key3c");
- assertEquals(test6, null);
- Object nltest = nl.findRecursive("key2", "key2b");
- assertTrue(nltest instanceof NamedList);
- Integer int1test = (Integer) nl.findRecursive("key2", "k2int1");
- assertEquals(int1test, (Integer) 5);
- int int2test = (int) nl.findRecursive("key2", "k2int2");
- assertEquals(int2test, 7);
- int int3test = (int) nl.findRecursive("key2", "k2int3");
- assertEquals(int3test, 48);
+ assertEquals(null, test6);
+ // Verify that retrieved NamedList objects have the right type.
+ Object test7 = nl.findRecursive("key2", "key2b");
+ assertTrue(test7 instanceof NamedList);
+ // Integer check.
+ int test8 = (Integer) nl.findRecursive("key2", "k2int1");
+ assertEquals(5, test8);
+ // Check that a single argument works the same as get(String).
+ String test9 = (String) nl.findRecursive("key1");
+ assertEquals("value1", test9);
+ // enl == explicit nested list
+ //
+ // key1
+ // - key1a
+ // - key1b
+ // key2 (null list)
+ NamedList> enl = new NamedList>();
+ NamedList enlkey1 = new NamedList();
+ NamedList enlkey2 = null;
+ enlkey1.add("key1a", "value1a");
+ enlkey1.add("key1b", "value1b");
+ enl.add("key1", enlkey1);
+ enl.add("key2", enlkey2);
+
+ // Tests that are very similar to the test above, just repeated
+ // on the explicitly nested object type.
+ String enltest1 = (String) enl.findRecursive("key1", "key1a");
+ assertEquals("value1a", enltest1);
+ String enltest2 = (String) enl.findRecursive("key1", "key1b");
+ assertEquals("value1b", enltest2);
+ // Verify that when a null value is stored, the standard get method
+ // says it is null, then check the recursive method.
+ Object enltest3 = enl.get("key2");
+ assertNull(enltest3);
+ Object enltest4 = enl.findRecursive("key2");
+ assertNull(enltest4);
}
}