1. package org.apache.solr.common.util;
  2.  
  3. import java.io.Serializable;
  4. import java.util.ArrayList;
  5. import java.util.Arrays;
  6. import java.util.Collection;
  7. import java.util.Iterator;
  8. import java.util.List;
  9. import java.util.Map;
  10.  
  11. import org.apache.solr.common.SolrException;
  12.  
  13. /**
  14. * 一个简单的容器类 用来模拟一个有序的 name/value 键值对列表
  15. * <p>
  16. * 不同于 Maps:
  17. * </p>
  18. * <ul>
  19. * <li>Names可以重复</li>
  20. * <li>元素具有顺序性</li>
  21. * <li>元素可以通过数值索引来访问</li>
  22. * <li>Names和 Values可以都为 null</li>
  23. * </ul>
  24. *
  25. * <p>
  26. * A NamedList provides fast access by element number, but not by name.
  27. * </p>
  28. * <p>
  29. * NamedList被序列化后,元素的顺序就比较重要了.所以ResponseWriters输出格式如JSON通常会选择一个容易在不同客户端保存并持有顺序的数据结构.
  30. *
  31. * 如果通过key访问比序列化更重要是,参考{@link SimpleOrderedMap},或者简单使用常规的{@link Map}
  32. * </p>
  33. *
  34. */
  35. public class NamedList<T> implements Cloneable, Serializable, Iterable<Map.Entry<String,T>> {
  36.  
  37. private static final long serialVersionUID = 1957981902839867821L;
  38. protected final List<Object> nvPairs;
  39.  
  40. /** Creates an empty instance */
  41. public NamedList() {
  42. nvPairs = new ArrayList<Object>();
  43. }
  44.  
  45. /**
  46. *创建一个实例,支持Map.Entry<String, ? extends T>[]类型
  47. *
  48. * <p>
  49. * Modifying the contents of the Entry[] after calling this constructor may change
  50. * the NamedList (in future versions of Solr), but this is not guaranteed and should
  51. * not be relied upon. To modify the NamedList, refer to {@link #add(String, Object)}
  52. * or {@link #remove(String)}.
  53. * </p>
  54. *
  55. * @param nameValuePairs the name value pairs
  56. */
  57. public NamedList(Map.Entry<String, ? extends T>[] nameValuePairs) {
  58. nvPairs = nameValueMapToList(nameValuePairs);
  59. }
  60.  
  61. /**
  62. *创建一个实例,支持明确的name/value配对键值.
  63. * <p>
  64. * When using this constructor, runtime type safety is only guaranteed if
  65. * all even numbered elements of the input list are of type "T".
  66. * </p>
  67. *
  68. * @param nameValuePairs underlying List which should be used to implement a NamedList
  69. * @deprecated Use {@link #NamedList(java.util.Map.Entry[])} for the NamedList instantiation
  70. */
  71. @Deprecated
  72. public NamedList(List<Object> nameValuePairs) {
  73. nvPairs=nameValuePairs;
  74. }
  75.  
  76. /**
  77. *
  78. * 序列化Map.Entry&lt;String,?&gt; 为一个List.这个List中索引为(0,2,4. ..etc)的是String,奇数元素(1,3,5...etc)为"T"类型.
  79. *
  80. * @return Modified List as per the above description
  81. * @deprecated This a temporary placeholder method until the guts of the class
  82. * are actually replaced by List&lt;String, ?&gt;.
  83. * @see <a href="https://issues.apache.org/jira/browse/SOLR-912">SOLR-912</a>
  84. */
  85. @Deprecated
  86. private List<Object> nameValueMapToList(Map.Entry<String, ? extends T>[] nameValuePairs) {
  87. List<Object> result = new ArrayList<Object>();
  88. for (Map.Entry<String, ?> ent : nameValuePairs) {
  89. result.add(ent.getKey());
  90. result.add(ent.getValue());
  91. }
  92. return result;
  93. }
  94.  
  95. /** The total number of name/value pairs */
  96. public int size() {
  97. return nvPairs.size() >> 1;
  98. }
  99.  
  100. /**
  101. * The name of the pair at the specified List index
  102. *
  103. * @return null if no name exists
  104. */
  105. public String getName(int idx) {
  106. return (String)nvPairs.get(idx << 1);
  107. }
  108.  
  109. /**
  110. * The value of the pair at the specified List index
  111. *
  112. * @return may be null
  113. */
  114. @SuppressWarnings("unchecked")
  115. public T getVal(int idx) {
  116. return (T)nvPairs.get((idx << 1) + 1);
  117. }
  118.  
  119. /**
  120. * 在list的末端添加 name/value键值对.
  121. */
  122. public void add(String name, T val) {
  123. nvPairs.add(name);
  124. nvPairs.add(val);
  125. }
  126.  
  127. /**
  128. * 修改指定索引处的键值对的name值.
  129. */
  130. public void setName(int idx, String name) {
  131. nvPairs.set(idx<<1, name);
  132. }
  133.  
  134. /**
  135. *修改指定索引处的键值对的value值.
  136. *
  137. * @return 老的对于索引的value值
  138. */
  139. public T setVal(int idx, T val) {
  140. int index = (idx<<1)+1;
  141. @SuppressWarnings("unchecked")
  142. T old = (T)nvPairs.get( index );
  143. nvPairs.set(index, val);
  144. return old;
  145. }
  146.  
  147. /**
  148. *删除指定索引处的键值对的name/value值.
  149. *
  150. * @return 删除的键值对的value值
  151. */
  152. public T remove(int idx) {
  153. int index = (idx<<1);
  154. nvPairs.remove(index);
  155. @SuppressWarnings("unchecked")
  156. T result = (T)nvPairs.remove(index); // same index, as things shifted in previous remove
  157. return result;
  158. }
  159.  
  160. /**
  161. * 扫描指定索引处开始的List列表,并返回第一处name为指定名字的键值对的索引
  162. *
  163. * @param name 查询的name,可能为null
  164. * @param start 搜索查询起始索引
  165. * @return 第一处匹配键值的索引,如果不匹配,返回-1
  166. */
  167. public int indexOf(String name, int start) {
  168. int sz = size();
  169. for (int i=start; i<sz; i++) {
  170. String n = getName(i);
  171. if (name==null) {
  172. if (n==null) return i; // matched null
  173. } else if (name.equals(n)) {
  174. return i;
  175. }
  176. }
  177. return -1;
  178. }
  179.  
  180. /**
  181. * 返回第一个name为指定值的实例的value值.
  182. *
  183. * <p>
  184. * NOTE: this runs in linear time (it scans starting at the
  185. * beginning of the list until it finds the first pair with
  186. * the specified name).
  187. *
  188. * @return null if not found or if the value stored was null.
  189. * @see #indexOf
  190. * @see #get(String,int)
  191. *
  192. */
  193. public T get(String name) {
  194. return get(name,0);
  195. }
  196.  
  197. /**
  198. * Gets the value for the first instance of the specified name
  199. * found starting at the specified index.
  200. * <p>
  201. * NOTE: this runs in linear time (it scans starting at the
  202. * specified position until it finds the first pair with
  203. * the specified name).
  204. *
  205. * @return null if not found or if the value stored was null.
  206. * @see #indexOf
  207. */
  208. public T get(String name, int start) {
  209. int sz = size();
  210. for (int i=start; i<sz; i++) {
  211. String n = getName(i);
  212. if (name==null) {
  213. if (n==null) return getVal(i);
  214. } else if (name.equals(n)) {
  215. return getVal(i);
  216. }
  217. }
  218. return null;
  219. }
  220.  
  221. /**
  222. * Gets the values for the the specified name
  223. *
  224. * @param name Name
  225. * @return List of values
  226. */
  227. public List<T> getAll(String name) {
  228. List<T> result = new ArrayList<T>();
  229. int sz = size();
  230. for (int i = 0; i < sz; i++) {
  231. String n = getName(i);
  232. if (name==n || (name!=null && name.equals(n))) {
  233. result.add(getVal(i));
  234. }
  235. }
  236. return result;
  237. }
  238.  
  239. /**
  240. * Removes all values matching the specified name
  241. *
  242. * @param name Name
  243. */
  244. private void killAll(String name) {
  245. int sz = size();
  246. // Go through the list backwards, removing matches as found.
  247. for (int i = sz - 1; i >= 0; i--) {
  248. String n = getName(i);
  249. if (name==n || (name!=null && name.equals(n))) {
  250. remove(i);
  251. }
  252. }
  253. }
  254.  
  255. /**
  256. * 递归解析NameList结构到一个指定的元素中.随着NameList树的解析,最后一个元素可以是任何类型,包括NameList,
  257. * 但前面所有元素必须NamedList对象本身.如果指定的层次结构不存在,那么返回为null.NameList是允许null值的,
  258. * 所以最后返回的值也可以是null;
  259. *
  260. * 这个方法对解析solr响应的/admin/mbeans 句柄特别有用,当然也同样用于其他复杂结构的工作处理.
  261. *
  262. * 推荐明确抛出返回值,一个比较安全的选择及时接受Object对象的返回值,然后去确认它的类型.
  263. *
  264. * 使用示例:
  265. *
  266. * String coreName = (String) response.findRecursive
  267. * ("solr-mbeans", "CORE", "core", "stats", "coreName");
  268. * long numDoc = (long) response.findRecursive
  269. * ("solr-mbeans", "CORE", "searcher", "stats", "numDocs");
  270. *
  271. * @param args
  272. * One or more strings specifying the tree to navigate.
  273. * @return the last entry in the given path hierarchy, null if not found.
  274. */
  275. public Object findRecursive(String... args) {
  276. NamedList<?> currentList = null;
  277. Object value = null;
  278. for (int i = 0; i < args.length; i++) {
  279. String key = args[i];
  280. /*
  281. * 第一次循环,currentList为null,所以我们把 NameList这个对象分配给currentList.
  282. * 然后我们检索这个列表的第一个key,然后把key对应的对象值 赋值给value 变量.
  283. *
  284. * 第二次循环遍历时,首先确认上一次我们获得的value是否是一个NameList.
  285. * 如果是NameList对象,那么将该对象赋值给currentList,抓取下一个key对应的value值,并开始遍历.
  286. * 如果不是一个NameList对象,重置value值为null,中断遍历.
  287. *
  288. * 赋值value为null,然后结束循环遍历,看起来做的不正确,但是有一个非常简单的原因,
  289. * 它的工作原理:如果循环到最后一个key,在检索到对应的value值时会自然结束循环遍历,并且这段代码永远不会执行的.
  290. *
  291. */
  292. if (currentList == null) {
  293. currentList = this;
  294. } else {
  295. if (value instanceof NamedList) {
  296. currentList = (NamedList<?>) value;
  297. } else {
  298. value = null;
  299. break;
  300. }
  301. }
  302. /*
  303. * 这里不再需要验证currentList是否为null.如果当前list为null的话,上面代码value instanceof NamedList
  304. * 的检查会失败的.如果这种情况发生的话,循环就会在这之前结束.
  305. *
  306. */
  307. value = currentList.get(key, 0);
  308. }
  309. return value;
  310. }
  311.  
  312. @Override
  313. public String toString() {
  314. StringBuilder sb = new StringBuilder();
  315. sb.append('{');
  316. int sz = size();
  317. for (int i=0; i<sz; i++) {
  318. if (i != 0) sb.append(',');
  319. sb.append(getName(i));
  320. sb.append('=');
  321. sb.append(getVal(i));
  322. }
  323. sb.append('}');
  324.  
  325. return sb.toString();
  326. }
  327.  
  328. /**
  329. *
  330. * 帮助类实现 Map.Entry&lt;String, T&gt;用来存储 NamedList中的key-value关系.
  331. */
  332. public static final class NamedListEntry<T> implements Map.Entry<String,T> {
  333.  
  334. public NamedListEntry() {
  335.  
  336. }
  337.  
  338. public NamedListEntry(String _key, T _value) {
  339. key = _key;
  340. value = _value;
  341. }
  342.  
  343. @Override
  344. public String getKey() {
  345. return key;
  346. }
  347.  
  348. @Override
  349. public T getValue() {
  350. return value;
  351. }
  352.  
  353. @Override
  354. public T setValue(T _value) {
  355. T oldValue = value;
  356. value = _value;
  357. return oldValue;
  358. }
  359.  
  360. private String key;
  361.  
  362. private T value;
  363. }
  364.  
  365. /**
  366. * 遍历Map,依次增加了它的键/值对
  367. *
  368. */
  369. public boolean addAll(Map<String,T> args) {
  370. for (Map.Entry<String, T> entry : args.entrySet() ) {
  371. add(entry.getKey(), entry.getValue());
  372. }
  373. return args.size()>0;
  374. }
  375.  
  376. /**将给定的NameList的元素添加到当前NameList对象中 */
  377. public boolean addAll(NamedList<T> nl) {
  378. nvPairs.addAll(nl.nvPairs);
  379. return nl.size()>0;
  380. }
  381.  
  382. /**
  383. * 生成一个<i>浅拷贝</i>的NameList.
  384. */
  385. @Override
  386. public NamedList<T> clone() {
  387. ArrayList<Object> newList = new ArrayList<Object>(nvPairs.size());
  388. newList.addAll(nvPairs);
  389. return new NamedList<T>(newList);
  390. }
  391.  
  392. //----------------------------------------------------------------------------
  393. // Iterable 接口
  394. //----------------------------------------------------------------------------
  395.  
  396. /**
  397. * 支持Iterable接口
  398. */
  399. @Override
  400. public Iterator<Map.Entry<String,T>> iterator() {
  401.  
  402. final NamedList<T> list = this;
  403.  
  404. Iterator<Map.Entry<String,T>> iter = new Iterator<Map.Entry<String,T>>() {
  405.  
  406. int idx = 0;
  407.  
  408. @Override
  409. public boolean hasNext() {
  410. return idx < list.size();
  411. }
  412.  
  413. @Override
  414. public Map.Entry<String,T> next() {
  415. final int index = idx++;
  416. Map.Entry<String,T> nv = new Map.Entry<String,T>() {
  417. @Override
  418. public String getKey() {
  419. return list.getName( index );
  420. }
  421.  
  422. @Override
  423. public T getValue() {
  424. return list.getVal( index );
  425. }
  426.  
  427. @Override
  428. public String toString() {
  429. return getKey()+"="+getValue();
  430. }
  431.  
  432. @Override
  433. public T setValue(T value) {
  434. return list.setVal(index, value);
  435. }
  436. };
  437. return nv;
  438. }
  439.  
  440. @Override
  441. public void remove() {
  442. throw new UnsupportedOperationException();
  443. }
  444. };
  445. return iter;
  446. }
  447.  
  448. /**
  449. * NOTE: 线性时间执行 (it scans starting at the
  450. * beginning of the list until it finds the first pair with
  451. * the specified name).
  452. */
  453. public T remove(String name) {
  454. int idx = indexOf(name, 0);
  455. if(idx != -1) return remove(idx);
  456. return null;
  457. }
  458.  
  459. /**
  460. * 删除并返回指定name的所有values.如果没有匹配,返回null.这个方法返回所有匹配对象,不考虑数据类型.
  461. * 如果解析solr配置选项,{@link #removeConfigArgs(String)} 或者 {@link #removeBooleanArg(String)}
  462. * 方法是一个更好的选择.
  463. *
  464. * @param name Name
  465. * @return List of values
  466. */
  467. public List<T> removeAll(String name) {
  468. List<T> result = new ArrayList<T>();
  469. result = getAll(name);
  470. if (result.size() > 0 ) {
  471. killAll(name);
  472. return result;
  473. }
  474. return null;
  475. }
  476.  
  477. /**
  478. * 用来从NameList对象中获取一个boolean参数.如果name不存在,返回null.如果对应name有多个value,
  479. * 或者这个值不是Boolean或者String类型,会抛出一个异常.如果只有一个值存在,并且是 一个Boolean或者String类型
  480. * 这个value值就会删除并返回一个Boolean值.如果抛出异常,NamedList将不会改变.
  481. * 参考 {@link #removeAll(String)}和 {@link #removeConfigArgs(String)}的更多方式:从NamedList收集的配置信息
  482. *
  483. * @param name NameList中要查询的key值.
  484. *
  485. * @return The boolean value found.
  486. * @throws SolrException
  487. * If multiple values are found for the name or the value found is
  488. * not a Boolean or a String.
  489. */
  490. public Boolean removeBooleanArg(final String name) {
  491. Boolean bool;
  492. List<T> values = getAll(name);
  493. if (0 == values.size()) {
  494. return null;
  495. }
  496. if (values.size() > 1) {
  497. throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
  498. "Only one '" + name + "' is allowed");
  499. }
  500. Object o = get(name);
  501. if (o instanceof Boolean) {
  502. bool = (Boolean)o;
  503. } else if (o instanceof CharSequence) {
  504. bool = Boolean.parseBoolean(o.toString());
  505. } else {
  506. throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
  507. "'" + name + "' must have type 'bool' or 'str'; found " + o.getClass());
  508. }
  509. remove(name);
  510. return bool;
  511. }
  512.  
  513. /**
  514. * 从NamedList对象中获取一个或者多个参数用来保存配置参数.找到所有匹配给定name的entries.
  515. * 如果都是字符串或者字符串数组,从NameList中删除它们,并返回{@link Collection}.
  516. *
  517. * 如果返回的集合是一个{@link ArrayList},那么参数顺序将被保存.如果关联name的value值不是字符串或者是字符串数组,
  518. * 那么抛出一个SolrException异常.异常抛出,NameList不会更改.如果没有匹配的值,返回一个空的集合.如果需要删除,
  519. * 并在检索到所有匹配的条目时不考虑数据类型,那么使用 {@link #removeAll(String)} 替代.
  520. * {@link #removeBooleanArg(String)} 方法用来检索一个boolean参数.
  521. *
  522. * @param name NameList中要查询的key值
  523. * @return A collection of the values found.
  524. * @throws SolrException
  525. * If values are found for the input key that are not strings or
  526. * arrays of strings.
  527. */
  528. @SuppressWarnings("rawtypes")
  529. public Collection<String> removeConfigArgs(final String name)
  530. throws SolrException {
  531. List<T> objects = getAll(name);
  532. List<String> collection = new ArrayList<String>(size() / 2);
  533. final String err = "init arg '" + name + "' must be a string "
  534. + "(ie: 'str'), or an array (ie: 'arr') containing strings; found: ";
  535.  
  536. for (Object o : objects) {
  537. if (o instanceof String) {
  538. collection.add((String) o);
  539. continue;
  540. }
  541.  
  542. // If it's an array, convert to List (which is a Collection).
  543. if (o instanceof Object[]) {
  544. o = Arrays.asList((Object[]) o);
  545. }
  546.  
  547. // If it's a Collection, collect each value.
  548. if (o instanceof Collection) {
  549. for (Object item : (Collection) o) {
  550. if (!(item instanceof String)) {
  551. throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, err + item.getClass());
  552. }
  553. collection.add((String) item);
  554. }
  555. continue;
  556. }
  557. throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, err + o.getClass());
  558. }
  559.  
  560. if (collection.size() > 0) {
  561. killAll(name);
  562. }
  563.  
  564. return collection;
  565. }
  566.  
  567. public void clear() {
  568. nvPairs.clear();
  569. }
  570.  
  571. @Override
  572. public int hashCode() {
  573. return nvPairs.hashCode();
  574. }
  575.  
  576. @Override
  577. public boolean equals(Object obj) {
  578. if (!(obj instanceof NamedList)) return false;
  579. NamedList<?> nl = (NamedList<?>) obj;
  580. return this.nvPairs.equals(nl.nvPairs);
  581. }
  582. }

测试类:

  1. package org.apache.solr.common.util;
  2.  
  3. import java.util.ArrayList;
  4. import java.util.List;
  5.  
  6. import org.apache.lucene.util.LuceneTestCase;
  7. import org.apache.solr.common.SolrException;
  8.  
  9. public class NamedListTest extends LuceneTestCase {
  10. public void testRemove() {
  11. NamedList<String> nl = new NamedList<String>();
  12. nl.add("key1", "value1");
  13. nl.add("key2", "value2");
  14. assertEquals(2, nl.size());
  15. String value = null;
  16. value = nl.remove(0);
  17. assertEquals("value1", value);
  18. assertEquals(1, nl.size());
  19. value = nl.remove("key2");
  20. assertEquals("value2", value);
  21. assertEquals(0, nl.size());
  22. }
  23.  
  24. public void testRemoveAll() {
  25. NamedList<String> nl = new NamedList<String>();
  26. nl.add("key1", "value1-1");
  27. nl.add("key2", "value2-1");
  28. nl.add("key1", "value1-2");
  29. nl.add("key2", "value2-2");
  30. nl.add("key1", "value1-3");
  31. nl.add("key2", "value2-3");
  32. nl.add("key1", "value1-4");
  33. nl.add("key2", "value2-4");
  34. nl.add("key1", "value1-5");
  35. nl.add("key2", "value2-5");
  36. nl.add("key1", "value1-6");
  37. assertEquals(11, nl.size());
  38. List<String> values = null;
  39. values = nl.removeAll("key1");
  40. assertEquals("value1-1", values.get(0));
  41. assertEquals("value1-3", values.get(2));
  42. assertEquals(6, values.size());
  43. assertEquals(5, nl.size());
  44. values = nl.removeAll("key2");
  45. assertEquals(5, values.size());
  46. assertEquals(0, nl.size());
  47. }
  48.  
  49. public void testRemoveArgs() {
  50. NamedList<Object> nl = new NamedList<Object>();
  51. nl.add("key1", "value1-1");
  52. nl.add("key2", "value2-1");
  53. nl.add("key1", "value1-2");
  54. nl.add("key2", "value2-2");
  55. nl.add("key1", "value1-3");
  56. nl.add("key2", "value2-3");
  57. nl.add("key1", "value1-4");
  58. nl.add("key2", "value2-4");
  59. nl.add("key1", "value1-5");
  60. nl.add("key2", "value2-5");
  61. nl.add("key1", "value1-6");
  62. nl.add("key2", 0);
  63. nl.add("key2", "value2-7");
  64. assertEquals(13, nl.size());
  65. List<String> values = (ArrayList<String>) nl.removeConfigArgs("key1");
  66. assertEquals("value1-1", values.get(0));
  67. assertEquals("value1-3", values.get(2));
  68. assertEquals(6, values.size());
  69. assertEquals(7, nl.size());
  70. try {
  71. values = (ArrayList<String>) nl.removeConfigArgs("key2");
  72. fail();
  73. }
  74. catch(SolrException e) {
  75. // Expected exception.
  76. assertTrue(true);
  77. }
  78. // nl should be unmodified when removeArgs throws an exception.
  79. assertEquals(7, nl.size());
  80. }
  81.  
  82. public void testRecursive() {
  83. /**
  84. * NL结构说明
  85. */
  86. // key1
  87. // key2
  88. // - key2a
  89. // - key2b
  90. // --- key2b1
  91. // --- key2b2
  92. // - key2c
  93. // - k2int1
  94. // key3
  95. // - key3a
  96. // --- key3a1
  97. // --- key3a2
  98. // --- key3a3
  99. // - key3b
  100. // - key3c
  101.  
  102. // 实例化一个多样的NL结构.
  103. NamedList<String> nl2b = new NamedList<String>();
  104. nl2b.add("key2b1", "value2b1");
  105. nl2b.add("key2b2", "value2b2");
  106. NamedList<String> nl3a = new NamedList<String>();
  107. nl3a.add("key3a1", "value3a1");
  108. nl3a.add("key3a2", "value3a2");
  109. nl3a.add("key3a3", "value3a3");
  110. NamedList<Object> nl2 = new NamedList<Object>();
  111. nl2.add("key2a", "value2a");
  112. nl2.add("key2b", nl2b);
  113. nl2.add("k2int1", (int) 5);
  114. NamedList<Object> nl3 = new NamedList<Object>();
  115. nl3.add("key3a", nl3a);
  116. nl3.add("key3b", "value3b");
  117. nl3.add("key3c", "value3c");
  118. nl3.add("key3c", "value3c2");
  119. NamedList<Object> nl = new NamedList<Object>();
  120. nl.add("key1", "value1");
  121. nl.add("key2", nl2);
  122. nl.add("key3", nl3);
  123.  
  124. // 简单的三级检查.
  125. String test1 = (String) nl.findRecursive("key2", "key2b", "key2b2");
  126. assertEquals("value2b2", test1);
  127. String test2 = (String) nl.findRecursive("key3", "key3a", "key3a3");
  128. assertEquals("value3a3", test2);
  129. // 二级检查
  130. String test3 = (String) nl.findRecursive("key3", "key3c");
  131. assertEquals("value3c", test3);
  132. // 检查无效值返回null.
  133. String test4 = (String) nl.findRecursive("key3", "key3c", "invalid");
  134. assertEquals(null, test4);
  135. String test5 = (String) nl.findRecursive("key3", "invalid", "invalid");
  136. assertEquals(null, test5);
  137. String test6 = (String) nl.findRecursive("invalid", "key3c");
  138. assertEquals(null, test6);
  139. // 验证检索NamedList对象具有正确的类型.
  140. Object test7 = nl.findRecursive("key2", "key2b");
  141. assertTrue(test7 instanceof NamedList);
  142. // Integer检查.
  143. int test8 = (Integer) nl.findRecursive("key2", "k2int1");
  144. assertEquals(5, test8);
  145. // Check that a single argument works the same as get(String).
  146. String test9 = (String) nl.findRecursive("key1");
  147. assertEquals("value1", test9);
  148. // enl == 明确嵌套列表
  149. //
  150. // key1
  151. // - key1a
  152. // - key1b
  153. // key2 (null list)
  154. NamedList<NamedList<String>> enl = new NamedList<NamedList<String>>();
  155. NamedList<String> enlkey1 = new NamedList<String>();
  156. NamedList<String> enlkey2 = null;
  157. enlkey1.add("key1a", "value1a");
  158. enlkey1.add("key1b", "value1b");
  159. enl.add("key1", enlkey1);
  160. enl.add("key2", enlkey2);
  161.  
  162. // 和上面的测试很类似, 只是重复了明确嵌套的对象类型.
  163. String enltest1 = (String) enl.findRecursive("key1", "key1a");
  164. assertEquals("value1a", enltest1);
  165. String enltest2 = (String) enl.findRecursive("key1", "key1b");
  166. assertEquals("value1b", enltest2);
  167. // 验证:在存储一个null值时,get方法返回的是一个null,那么验证这个递归方法.
  168. Object enltest3 = enl.get("key2");
  169. assertNull(enltest3);
  170. Object enltest4 = enl.findRecursive("key2");
  171. assertNull(enltest4);
  172. }
  173. }

solrj:org.apache.solr.common.util.NamedList.java的更多相关文章

  1. org.apache.solr.common.util.ContentStream.java及其实现类

    org.apache.solr.common.util.ContentStream.java 主要是获取文件,URL,字节数组,字符串等的数据流.主要方法又InputStream getStream( ...

  2. java.lang.NoClassDefFoundError: org/apache/solr/common/params/SolrParams

    启动tomcat服务,报错误java.lang.NoClassDefFoundError: org/apache/solr/common/params/SolrParams [2016-03-10 2 ...

  3. mavne install 报错org.apache.maven.surefire.util.SurefireReflectionException: java.lang.reflect.InvocationTargetException

    maven install 报错 org.apache.maven.surefire.util.SurefireReflectionException: java.lang.reflect.Invoc ...

  4. solr启动时报错org.apache.solr.common.SolrException: undefined field text的解决办法

    solr启动时报错org.apache.solr.common.SolrException: undefined field text的解决办法 原创 2015年08月21日 20:47:40 标签: ...

  5. Solr6.4.2异常:org.apache.solr.common.SolrException: Error opening new searcher

    版权声明:本文为博主原创文章,转载请附上原文出处链接和本声明. 原文链接:https://www.cnblogs.com/chenghu/p/13840021.html Solr版本6.4.2 启动S ...

  6. solr error logs org.apache.solr.common.SolrException: ERROR: [doc=17] unknown field alias

    在solr中 添加新的索引词语时,报如标题所示错误,指定是插入的字段没有在solr索引字段里 可以修改 solr安装目录/solr/conf 目录下的 schema.xml 在此xml文件内加入所需字 ...

  7. Apache Solr采用Java开发、基于Lucene的全文搜索服务器

    http://docs.spring.io/spring-data/solr/ 首先介绍一下solr: Apache Solr (读音: SOLer) 是一个开源.高性能.采用Java开发.基于Luc ...

  8. solr环境搭建及java小demo

    一配置solr环境 1.下载solr 2.配置solr(最好单独分离出一个tomcat,一台机器启动多个tomcat参见:http://www.cnblogs.com/lxlwellaccessful ...

  9. 配置好solr搜索引擎服务器后java后台如何将商品信息导入索引库

    首先,在配置文件目录中添加solr 服务器的bean 配置文件 solr服务器的url可以写在配置文件中: url地址其实就是我们网页可以访问的solr地址: 然后我们写 service packag ...

随机推荐

  1. 前端异步解决方案——mmDeferred

    Deferred是前端解决异步操作的一种编程范式,后来出现的Promise规范更是让其普适性大大提高.不过Promise规范也存在分岐.现在最流行的是Promise/A规范. Promise/A大致是 ...

  2. Java并发编程:Java ConcurrentModificationException异常原因和解决方法

    Java ConcurrentModificationException异常原因和解决方法 在前面一篇文章中提到,对Vector.ArrayList在迭代的时候如果同时对其进行修改就会抛出java.u ...

  3. HDU 5867 Water problem (模拟)

    Water problem 题目链接: http://acm.split.hdu.edu.cn/showproblem.php?pid=5867 Description If the numbers ...

  4. SpriteKit

    [SpriteKit] Sprite Kit provides a graphics rendering and animation infrastructure that you can use t ...

  5. ubuntu官方源列表网址

    http://wiki.ubuntu.org.cn/%E6%BA%90%E5%88%97%E8%A1%A8 (推荐台湾的源)

  6. POJ3280(DP)

    题目大意是说一个字符串,每插入或者删除一个字符都需要一定的代价,问怎样可以使这个字符串变成一个回文串,且花费最小. 首先明确的就是如果已经将区间[i,j]整理成为一个回文串(不管中间有多少个字符或者是 ...

  7. 引用 1.9.1.min.js dom对象 没有live 绑定事件方法, 引用 1.7.js 就有live 绑定事件方法

    问题:相同环境,引用 1.9.1.min.js $('div[data-role="page"]').live('pagehide', function (event, ui) { ...

  8. HDU 1392 Surround the Trees 构造凸包

    又是一道模板题 #include <iostream> #include <cstring> #include <cstdlib> #include <cst ...

  9. CENTOS LINUX查询内存大小、频率

    more /proc/meminfo dmidecode [root@barcode-mcs ~]# dmidecode -t memory linux下查看主板内存槽与内存信息 1.查看内存槽数.那 ...

  10. js 浮点小数计算精度问题 parseFloat 精度问题

    在js中进行以元为单位进行金额计算时 使用parseFloat会产生精度问题 var price = 10.99; var quantity = 7; var needPay = parseFloat ...