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 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); } }