Author: oheger
Date: Sat Aug 10 16:51:12 2013
New Revision: 1512798

URL: http://svn.apache.org/r1512798
Log:
Added a flatten() method which allows limiting the number of results.

This method is needed for the conversion of collections or arrays to single
values. Here only the first element needs to be extracted. It is more
efficient to abort the extraction process early instead of producing the full
result collection.

Modified:
    
commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/convert/AbstractListDelimiterHandler.java
    
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/convert/TestDisabledListDelimiterHandler.java

Modified: 
commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/convert/AbstractListDelimiterHandler.java
URL: 
http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/convert/AbstractListDelimiterHandler.java?rev=1512798&r1=1512797&r2=1512798&view=diff
==============================================================================
--- 
commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/convert/AbstractListDelimiterHandler.java
 (original)
+++ 
commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/convert/AbstractListDelimiterHandler.java
 Sat Aug 10 16:51:12 2013
@@ -119,16 +119,21 @@ public abstract class AbstractListDelimi
     protected abstract String escapeString(String s);
 
     /**
-     * Performs the actual work as advertised by the {@code parse()} method. 
The
-     * passed in object is evaluated (if necessary, in a recursive way), and 
all
-     * simple value objects it contains are extracted. They are returned as a
-     * collection.
+     * Extracts all values contained in the specified object up to the given
+     * limit. The passed in object is evaluated (if necessary in a recursive
+     * way). If it is a complex object (e.g. a collection or an array), all its
+     * elements are processed recursively and added to a target collection. The
+     * process stops if the limit is reached, but depending on the input 
object,
+     * it might be exceeded. (The limit is just an indicator to stop the 
process
+     * to avoid unnecessary work if the caller is only interested in a few
+     * values.)
      *
      * @param value the value to be processed
+     * @param limit the limit for aborting the processing
      * @return a "flat" collection containing all primitive values of
      *         the passed in object
      */
-    private Collection<?> flatten(Object value)
+    Collection<?> flatten(Object value, int limit)
     {
         if (value instanceof String)
         {
@@ -138,19 +143,20 @@ public abstract class AbstractListDelimi
         Collection<Object> result = new LinkedList<Object>();
         if (value instanceof Iterable)
         {
-            flattenIterator(result, ((Iterable<?>) value).iterator());
+            flattenIterator(result, ((Iterable<?>) value).iterator(), limit);
         }
         else if (value instanceof Iterator)
         {
-            flattenIterator(result, (Iterator<?>) value);
+            flattenIterator(result, (Iterator<?>) value, limit);
         }
         else if (value != null)
         {
             if (value.getClass().isArray())
             {
-                for (int len = Array.getLength(value), idx = 0; idx < len; 
idx++)
+                for (int len = Array.getLength(value), idx = 0, size = 0; idx 
< len
+                        && size < limit; idx++, size = result.size())
                 {
-                    result.addAll(flatten(Array.get(value, idx)));
+                    result.addAll(flatten(Array.get(value, idx), limit - 
size));
                 }
             }
             else
@@ -163,17 +169,34 @@ public abstract class AbstractListDelimi
     }
 
     /**
+     * Performs the actual work as advertised by the {@code parse()} method.
+     * This method delegates to {@link #flatten(Object, int)} without 
specifying
+     * a limit.
+     *
+     * @param value the value to be processed
+     * @return a &quot;flat&quot; collection containing all primitive values of
+     *         the passed in object
+     */
+    private Collection<?> flatten(Object value)
+    {
+        return flatten(value, Integer.MAX_VALUE);
+    }
+
+    /**
      * Flattens the given iterator. For each element in the iteration
      * {@code flatten()} is called recursively.
      *
      * @param target the target collection
      * @param it the iterator to process
+     * @param limit a limit for the number of elements to extract
      */
-    private void flattenIterator(Collection<Object> target, Iterator<?> it)
+    private void flattenIterator(Collection<Object> target, Iterator<?> it, 
int limit)
     {
-        while (it.hasNext())
+        int size = target.size();
+        while (size < limit && it.hasNext())
         {
-            target.addAll(flatten(it.next()));
+            target.addAll(flatten(it.next(), limit - size));
+            size = target.size();
         }
     }
 }

Modified: 
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/convert/TestDisabledListDelimiterHandler.java
URL: 
http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/convert/TestDisabledListDelimiterHandler.java?rev=1512798&r1=1512797&r2=1512798&view=diff
==============================================================================
--- 
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/convert/TestDisabledListDelimiterHandler.java
 (original)
+++ 
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/convert/TestDisabledListDelimiterHandler.java
 Sat Aug 10 16:51:12 2013
@@ -19,12 +19,13 @@ package org.apache.commons.configuration
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Iterator;
 
 import org.apache.commons.configuration.ListDelimiterHandler;
 import org.apache.commons.configuration.ValueTransformer;
-import org.apache.commons.configuration.convert.DisabledListDelimiterHandler;
 import org.easymock.EasyMock;
 import org.junit.Before;
 import org.junit.Test;
@@ -179,4 +180,45 @@ public class TestDisabledListDelimiterHa
         handler.escapeList(Arrays.asList(VALUES),
                 ListDelimiterHandler.NOOP_TRANSFORMER);
     }
+
+    /**
+     * Tests whether a limit is applied when extracting values from an array.
+     */
+    @Test
+    public void testFlattenArrayWithLimit()
+    {
+        Collection<?> res = handler.flatten(VALUES, 1);
+        assertEquals("Wrong collection size", 1, res.size());
+        assertEquals("Wrong element", VALUES[0], res.iterator().next());
+    }
+
+    /**
+     * Tests whether a limit is applied when extracting elements from a
+     * collection.
+     */
+    @Test
+    public void testFlattenCollectionWithLimit()
+    {
+        Collection<Object> src = Arrays.asList(VALUES);
+        Collection<?> res = handler.flatten(src, 1);
+        assertEquals("Wrong collection size", 1, res.size());
+        assertEquals("Wrong element", VALUES[0], res.iterator().next());
+    }
+
+    /**
+     * Tests whether elements can be extracted from a collection that contains
+     * an array if a limit is specified.
+     */
+    @Test
+    public void testFlattenCollectionWithArrayWithLimit()
+    {
+        Collection<Object> src = new ArrayList<Object>(2);
+        src.add(STR_VALUE);
+        src.add(VALUES);
+        Collection<?> res = handler.flatten(src, 2);
+        assertEquals("Wrong collection size", 2, res.size());
+        Iterator<?> it = res.iterator();
+        assertEquals("Wrong element (1)", STR_VALUE, it.next());
+        assertEquals("Wrong element (2)", VALUES[0], it.next());
+    }
 }


Reply via email to