You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2022/07/14 14:34:33 UTC

[commons-configuration] branch master updated (15f1ee11 -> 5de7c48e)

This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/commons-configuration.git


    from 15f1ee11 Format tweaks
     new 86d695f7 Sort members.
     new f289d6e7 Sort members.
     new c034d659 Add org.apache.commons.configuration2.convert.ListDelimiterHandler.flatten(Object, int)
     new 5de7c48e Add DefaultConversionHandler#setListDelimiterHandler(ListDelimiterHandler).

The 4 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 src/changes/changes.xml                            |   3 +
 .../convert/AbstractListDelimiterHandler.java      | 122 ++++-----
 .../convert/DefaultConversionHandler.java          | 281 +++++++++++----------
 .../convert/ListDelimiterHandler.java              |  71 ++++--
 .../convert/TestDefaultConversionHandler.java      |  14 +-
 5 files changed, 268 insertions(+), 223 deletions(-)


[commons-configuration] 04/04: Add DefaultConversionHandler#setListDelimiterHandler(ListDelimiterHandler).

Posted by gg...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-configuration.git

commit 5de7c48e4d591e638562672fbbe38db5d14e89b3
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Thu Jul 14 10:34:26 2022 -0400

    Add DefaultConversionHandler#setListDelimiterHandler(ListDelimiterHandler).
---
 src/changes/changes.xml                            |   3 +
 .../convert/DefaultConversionHandler.java          | 281 +++++++++++----------
 .../convert/TestDefaultConversionHandler.java      |  14 +-
 3 files changed, 169 insertions(+), 129 deletions(-)

diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 3e0a1fe8..b53a320a 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -30,6 +30,9 @@
         CombinedConfiguration#getKeys() can throw NoSuchElementException.
       </action>
       <!-- ADD -->
+      <action issue="CONFIGURATION-799" type="fix" dev="ggregory" due-to="Xinshiyou, Gary Gregory">
+        Add DefaultConversionHandler#setListDelimiterHandler(ListDelimiterHandler).
+      </action>
       <!-- UPDATE -->
       <action type="update" dev="ggregory" due-to="Dependabot">
         Bump spotbugs-maven-plugin from 4.7.0.0 to 4.7.1.0 #193.
diff --git a/src/main/java/org/apache/commons/configuration2/convert/DefaultConversionHandler.java b/src/main/java/org/apache/commons/configuration2/convert/DefaultConversionHandler.java
index acd3d1ba..4cfb856f 100644
--- a/src/main/java/org/apache/commons/configuration2/convert/DefaultConversionHandler.java
+++ b/src/main/java/org/apache/commons/configuration2/convert/DefaultConversionHandler.java
@@ -45,6 +45,7 @@ import org.apache.commons.lang3.ClassUtils;
  * @since 2.0
  */
 public class DefaultConversionHandler implements ConversionHandler {
+
     /**
      * A default instance of this class. Because an instance of this class can be shared between arbitrary objects it is
      * possible to make use of this default instance anywhere.
@@ -54,9 +55,6 @@ public class DefaultConversionHandler implements ConversionHandler {
     /** The default format for dates. */
     public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
 
-    /** A helper object used for extracting values from complex objects. */
-    private static final ListDelimiterHandler EXTRACTOR = DisabledListDelimiterHandler.INSTANCE;
-
     /**
      * Constant for a default {@code ConfigurationInterpolator} to be used if none is provided by the caller.
      */
@@ -67,72 +65,142 @@ public class DefaultConversionHandler implements ConversionHandler {
         }
     };
 
+    /** The default {@link ListDelimiterHandler} used for extracting values from complex objects. */
+    static final ListDelimiterHandler LIST_DELIMITER_HANDLER = DisabledListDelimiterHandler.INSTANCE;
+
     /** The current date format. */
     private volatile String dateFormat;
 
+    /** The default {@link ListDelimiterHandler} used for extracting values from complex objects. */
+    private volatile ListDelimiterHandler listDelimiterHandler = DisabledListDelimiterHandler.INSTANCE;
+
     /**
-     * Returns the date format used by this conversion handler.
+     * Obtains a {@code ConfigurationInterpolator}. If the passed in one is not <b>null</b>, it is used. Otherwise, a
+     * default one is returned.
      *
-     * @return the date format
+     * @param ci the {@code ConfigurationInterpolator} provided by the caller
+     * @return the {@code ConfigurationInterpolator} to be used
      */
-    public String getDateFormat() {
-        final String fmt = dateFormat;
-        return fmt != null ? fmt : DEFAULT_DATE_FORMAT;
+    private static ConfigurationInterpolator fetchInterpolator(final ConfigurationInterpolator ci) {
+        return ci != null ? ci : NULL_INTERPOLATOR;
     }
 
     /**
-     * Sets the date format to be used by this conversion handler. This format is applied by conversions to {@code Date} or
-     * {@code Calendar} objects. The string is passed to the {@code java.text.SimpleDateFormat} class, so it must be
-     * compatible with this class. If no date format has been set, a default format is used.
+     * Performs the conversion from the passed in source object to the specified target class. This method is called for
+     * each conversion to be done. The source object has already been passed to the {@link ConfigurationInterpolator}, so
+     * interpolation does not have to be done again. (The passed in {@code ConfigurationInterpolator} may still be necessary
+     * for extracting values from complex objects; it is guaranteed to be non <b>null</b>.) The source object may be a
+     * complex object, e.g. a collection or an array. This base implementation checks whether the source object is complex.
+     * If so, it delegates to {@link #extractConversionValue(Object, Class, ConfigurationInterpolator)} to obtain a single
+     * value. Eventually, {@link #convertValue(Object, Class, ConfigurationInterpolator)} is called with the single value to
+     * be converted.
      *
-     * @param dateFormat the date format string
-     * @see #DEFAULT_DATE_FORMAT
+     * @param <T> the desired target type of the conversion
+     * @param src the source object to be converted
+     * @param targetCls the desired target class
+     * @param ci the {@code ConfigurationInterpolator} (not <b>null</b>)
+     * @return the converted value
+     * @throws ConversionException if conversion is not possible
      */
-    public void setDateFormat(final String dateFormat) {
-        this.dateFormat = dateFormat;
+    protected <T> T convert(final Object src, final Class<T> targetCls, final ConfigurationInterpolator ci) {
+        final Object conversionSrc = isComplexObject(src) ? extractConversionValue(src, targetCls, ci) : src;
+        return convertValue(ci.interpolate(conversionSrc), targetCls, ci);
     }
 
-    @Override
-    public <T> T to(final Object src, final Class<T> targetCls, final ConfigurationInterpolator ci) {
-        final ConfigurationInterpolator interpolator = fetchInterpolator(ci);
-        return convert(interpolator.interpolate(src), targetCls, interpolator);
+    /**
+     * Helper method for converting all values of a source object and storing them in a collection.
+     *
+     * @param <T> the target type of the conversion
+     * @param src the source object
+     * @param elemClass the target class of the conversion
+     * @param ci the {@code ConfigurationInterpolator}
+     * @param dest the collection in which to store the results
+     * @throws ConversionException if a conversion cannot be performed
+     */
+    private <T> void convertToCollection(final Object src, final Class<T> elemClass, final ConfigurationInterpolator ci, final Collection<T> dest) {
+        for (final Object o : extractValues(ci.interpolate(src))) {
+            dest.add(convert(o, elemClass, ci));
+        }
     }
 
     /**
-     * {@inheritDoc} This implementation extracts all values stored in the passed in source object, converts them to the
-     * target type, and adds them to a result array. Arrays of objects and of primitive types are supported. If the source
-     * object is <b>null</b>, result is <b>null</b>, too.
+     * Performs a conversion of a single value to the specified target class. The passed in source object is guaranteed to
+     * be a single value, but it can be <b>null</b>. Derived classes that want to extend the available conversions, but are
+     * happy with the handling of complex objects, just need to override this method.
+     *
+     * @param <T> the desired target type of the conversion
+     * @param src the source object (a single value)
+     * @param targetCls the target class of the conversion
+     * @param ci the {@code ConfigurationInterpolator} (not <b>null</b>)
+     * @return the converted value
+     * @throws ConversionException if conversion is not possible
      */
-    @Override
-    public Object toArray(final Object src, final Class<?> elemClass, final ConfigurationInterpolator ci) {
+    protected <T> T convertValue(final Object src, final Class<T> targetCls, final ConfigurationInterpolator ci) {
         if (src == null) {
             return null;
         }
-        if (isEmptyElement(src)) {
-            return Array.newInstance(elemClass, 0);
-        }
 
-        final ConfigurationInterpolator interpolator = fetchInterpolator(ci);
-        return elemClass.isPrimitive() ? toPrimitiveArray(src, elemClass, interpolator) : toObjectArray(src, elemClass, interpolator);
+        // This is a safe cast because PropertyConverter either returns an
+        // object of the correct class or throws an exception.
+        @SuppressWarnings("unchecked")
+        final T result = (T) PropertyConverter.to(targetCls, src, this);
+        return result;
     }
 
     /**
-     * {@inheritDoc} This implementation extracts all values stored in the passed in source object, converts them to the
-     * target type, and adds them to the target collection. The target collection must not be <b>null</b>. If the source
-     * object is <b>null</b>, nothing is added to the collection.
+     * Extracts a single value from a complex object. This method is called by {@code convert()} if the source object is
+     * complex. This implementation extracts the first value from the complex object and returns it.
      *
-     * @throws IllegalArgumentException if the target collection is <b>null</b>
+     * @param container the complex object
+     * @param targetCls the target class of the conversion
+     * @param ci the {@code ConfigurationInterpolator} (not <b>null</b>)
+     * @return the value to be converted (may be <b>null</b> if no values are found)
      */
-    @Override
-    public <T> void toCollection(final Object src, final Class<T> elemClass, final ConfigurationInterpolator ci, final Collection<T> dest) {
-        if (dest == null) {
-            throw new IllegalArgumentException("Target collection must not be null!");
-        }
+    protected Object extractConversionValue(final Object container, final Class<?> targetCls, final ConfigurationInterpolator ci) {
+        final Collection<?> values = extractValues(container, 1);
+        return values.isEmpty() ? null : ci.interpolate(values.iterator().next());
+    }
 
-        if (src != null && !isEmptyElement(src)) {
-            final ConfigurationInterpolator interpolator = fetchInterpolator(ci);
-            convertToCollection(src, elemClass, interpolator, dest);
-        }
+    /**
+     * Extracts all values contained in the given source object and returns them as a flat collection.
+     *
+     * @param source the source object (may be a single value or a complex object)
+     * @return a collection with all extracted values
+     */
+    protected Collection<?> extractValues(final Object source) {
+        return extractValues(source, Integer.MAX_VALUE);
+    }
+
+    /**
+     * Extracts a maximum number of values contained in the given source object and returns them as flat collection. This
+     * method is useful if the caller only needs a subset of values, e.g. only the first one.
+     *
+     * @param source the source object (may be a single value or a complex object)
+     * @param limit the number of elements to extract
+     * @return a collection with all extracted values
+     */
+    protected Collection<?> extractValues(final Object source, final int limit) {
+        return listDelimiterHandler.flatten(source, limit);
+    }
+
+    /**
+     * Returns the date format used by this conversion handler.
+     *
+     * @return the date format
+     */
+    public String getDateFormat() {
+        final String fmt = dateFormat;
+        return fmt != null ? fmt : DEFAULT_DATE_FORMAT;
+    }
+
+    /**
+     * Gets the {@link ListDelimiterHandler} used for extracting values from complex objects.
+     *
+     * @return the {@link ListDelimiterHandler} used for extracting values from complex objects, never null.
+     * @since 2.9.0
+     */
+    public ListDelimiterHandler getListDelimiterHandler() {
+        return listDelimiterHandler;
     }
 
     /**
@@ -166,85 +234,69 @@ public class DefaultConversionHandler implements ConversionHandler {
     }
 
     /**
-     * Performs the conversion from the passed in source object to the specified target class. This method is called for
-     * each conversion to be done. The source object has already been passed to the {@link ConfigurationInterpolator}, so
-     * interpolation does not have to be done again. (The passed in {@code ConfigurationInterpolator} may still be necessary
-     * for extracting values from complex objects; it is guaranteed to be non <b>null</b>.) The source object may be a
-     * complex object, e.g. a collection or an array. This base implementation checks whether the source object is complex.
-     * If so, it delegates to {@link #extractConversionValue(Object, Class, ConfigurationInterpolator)} to obtain a single
-     * value. Eventually, {@link #convertValue(Object, Class, ConfigurationInterpolator)} is called with the single value to
-     * be converted.
+     * Sets the date format to be used by this conversion handler. This format is applied by conversions to {@code Date} or
+     * {@code Calendar} objects. The string is passed to the {@code java.text.SimpleDateFormat} class, so it must be
+     * compatible with this class. If no date format has been set, a default format is used.
      *
-     * @param <T> the desired target type of the conversion
-     * @param src the source object to be converted
-     * @param targetCls the desired target class
-     * @param ci the {@code ConfigurationInterpolator} (not <b>null</b>)
-     * @return the converted value
-     * @throws ConversionException if conversion is not possible
+     * @param dateFormat the date format string
+     * @see #DEFAULT_DATE_FORMAT
      */
-    protected <T> T convert(final Object src, final Class<T> targetCls, final ConfigurationInterpolator ci) {
-        final Object conversionSrc = isComplexObject(src) ? extractConversionValue(src, targetCls, ci) : src;
-        return convertValue(ci.interpolate(conversionSrc), targetCls, ci);
+    public void setDateFormat(final String dateFormat) {
+        this.dateFormat = dateFormat;
     }
 
     /**
-     * Extracts a maximum number of values contained in the given source object and returns them as flat collection. This
-     * method is useful if the caller only needs a subset of values, e.g. only the first one.
+     * Sets the {@link ListDelimiterHandler} used for extracting values from complex objects.
      *
-     * @param source the source object (may be a single value or a complex object)
-     * @param limit the number of elements to extract
-     * @return a collection with all extracted values
+     * @param listDelimiterHandler the {@link ListDelimiterHandler} used for extracting values from complex objects. Setting
+     *        the value to null resets the value to its default.
+     * @since 2.9.0
      */
-    protected Collection<?> extractValues(final Object source, final int limit) {
-        return EXTRACTOR.flatten(source, limit);
+    public void setListDelimiterHandler(final ListDelimiterHandler listDelimiterHandler) {
+        this.listDelimiterHandler = listDelimiterHandler != null ? listDelimiterHandler : LIST_DELIMITER_HANDLER;
     }
 
-    /**
-     * Extracts all values contained in the given source object and returns them as a flat collection.
-     *
-     * @param source the source object (may be a single value or a complex object)
-     * @return a collection with all extracted values
-     */
-    protected Collection<?> extractValues(final Object source) {
-        return extractValues(source, Integer.MAX_VALUE);
+    @Override
+    public <T> T to(final Object src, final Class<T> targetCls, final ConfigurationInterpolator ci) {
+        final ConfigurationInterpolator interpolator = fetchInterpolator(ci);
+        return convert(interpolator.interpolate(src), targetCls, interpolator);
     }
 
     /**
-     * Extracts a single value from a complex object. This method is called by {@code convert()} if the source object is
-     * complex. This implementation extracts the first value from the complex object and returns it.
-     *
-     * @param container the complex object
-     * @param targetCls the target class of the conversion
-     * @param ci the {@code ConfigurationInterpolator} (not <b>null</b>)
-     * @return the value to be converted (may be <b>null</b> if no values are found)
+     * {@inheritDoc} This implementation extracts all values stored in the passed in source object, converts them to the
+     * target type, and adds them to a result array. Arrays of objects and of primitive types are supported. If the source
+     * object is <b>null</b>, result is <b>null</b>, too.
      */
-    protected Object extractConversionValue(final Object container, final Class<?> targetCls, final ConfigurationInterpolator ci) {
-        final Collection<?> values = extractValues(container, 1);
-        return values.isEmpty() ? null : ci.interpolate(values.iterator().next());
+    @Override
+    public Object toArray(final Object src, final Class<?> elemClass, final ConfigurationInterpolator ci) {
+        if (src == null) {
+            return null;
+        }
+        if (isEmptyElement(src)) {
+            return Array.newInstance(elemClass, 0);
+        }
+
+        final ConfigurationInterpolator interpolator = fetchInterpolator(ci);
+        return elemClass.isPrimitive() ? toPrimitiveArray(src, elemClass, interpolator) : toObjectArray(src, elemClass, interpolator);
     }
 
     /**
-     * Performs a conversion of a single value to the specified target class. The passed in source object is guaranteed to
-     * be a single value, but it can be <b>null</b>. Derived classes that want to extend the available conversions, but are
-     * happy with the handling of complex objects, just need to override this method.
+     * {@inheritDoc} This implementation extracts all values stored in the passed in source object, converts them to the
+     * target type, and adds them to the target collection. The target collection must not be <b>null</b>. If the source
+     * object is <b>null</b>, nothing is added to the collection.
      *
-     * @param <T> the desired target type of the conversion
-     * @param src the source object (a single value)
-     * @param targetCls the target class of the conversion
-     * @param ci the {@code ConfigurationInterpolator} (not <b>null</b>)
-     * @return the converted value
-     * @throws ConversionException if conversion is not possible
+     * @throws IllegalArgumentException if the target collection is <b>null</b>
      */
-    protected <T> T convertValue(final Object src, final Class<T> targetCls, final ConfigurationInterpolator ci) {
-        if (src == null) {
-            return null;
+    @Override
+    public <T> void toCollection(final Object src, final Class<T> elemClass, final ConfigurationInterpolator ci, final Collection<T> dest) {
+        if (dest == null) {
+            throw new IllegalArgumentException("Target collection must not be null!");
         }
 
-        // This is a safe cast because PropertyConverter either returns an
-        // object of the correct class or throws an exception.
-        @SuppressWarnings("unchecked")
-        final T result = (T) PropertyConverter.to(targetCls, src, this);
-        return result;
+        if (src != null && !isEmptyElement(src)) {
+            final ConfigurationInterpolator interpolator = fetchInterpolator(ci);
+            convertToCollection(src, elemClass, interpolator, dest);
+        }
     }
 
     /**
@@ -304,31 +356,4 @@ public class DefaultConversionHandler implements ConversionHandler {
         }
         return array;
     }
-
-    /**
-     * Helper method for converting all values of a source object and storing them in a collection.
-     *
-     * @param <T> the target type of the conversion
-     * @param src the source object
-     * @param elemClass the target class of the conversion
-     * @param ci the {@code ConfigurationInterpolator}
-     * @param dest the collection in which to store the results
-     * @throws ConversionException if a conversion cannot be performed
-     */
-    private <T> void convertToCollection(final Object src, final Class<T> elemClass, final ConfigurationInterpolator ci, final Collection<T> dest) {
-        for (final Object o : extractValues(ci.interpolate(src))) {
-            dest.add(convert(o, elemClass, ci));
-        }
-    }
-
-    /**
-     * Obtains a {@code ConfigurationInterpolator}. If the passed in one is not <b>null</b>, it is used. Otherwise, a
-     * default one is returned.
-     *
-     * @param ci the {@code ConfigurationInterpolator} provided by the caller
-     * @return the {@code ConfigurationInterpolator} to be used
-     */
-    private static ConfigurationInterpolator fetchInterpolator(final ConfigurationInterpolator ci) {
-        return ci != null ? ci : NULL_INTERPOLATOR;
-    }
 }
diff --git a/src/test/java/org/apache/commons/configuration2/convert/TestDefaultConversionHandler.java b/src/test/java/org/apache/commons/configuration2/convert/TestDefaultConversionHandler.java
index 05d79161..ce751c83 100644
--- a/src/test/java/org/apache/commons/configuration2/convert/TestDefaultConversionHandler.java
+++ b/src/test/java/org/apache/commons/configuration2/convert/TestDefaultConversionHandler.java
@@ -76,7 +76,7 @@ public class TestDefaultConversionHandler {
     }
 
     @Before
-    public void setUp() throws Exception {
+    public void setUp() {
         handler = new DefaultConversionHandler();
     }
 
@@ -88,6 +88,18 @@ public class TestDefaultConversionHandler {
         assertEquals("Wrong date format", DefaultConversionHandler.DEFAULT_DATE_FORMAT, handler.getDateFormat());
     }
 
+    @Test
+    public synchronized void testListDelimiterHandler() {
+        assertEquals(DefaultConversionHandler.LIST_DELIMITER_HANDLER, handler.getListDelimiterHandler());
+        handler.setListDelimiterHandler(null);
+        assertEquals(DefaultConversionHandler.LIST_DELIMITER_HANDLER, handler.getListDelimiterHandler());
+        final LegacyListDelimiterHandler legacyListDelimiterHandler = new LegacyListDelimiterHandler(',');
+        handler.setListDelimiterHandler(legacyListDelimiterHandler);
+        assertEquals(legacyListDelimiterHandler, handler.getListDelimiterHandler());
+        handler.setListDelimiterHandler(null);
+        assertEquals(DefaultConversionHandler.LIST_DELIMITER_HANDLER, handler.getListDelimiterHandler());
+    }
+
     /**
      * Tests whether the date format can be changed.
      */


[commons-configuration] 01/04: Sort members.

Posted by gg...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-configuration.git

commit 86d695f7fe59504ba64398b6de3faf10786076f3
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Thu Jul 14 09:47:37 2022 -0400

    Sort members.
---
 .../convert/AbstractListDelimiterHandler.java      | 96 +++++++++++-----------
 1 file changed, 48 insertions(+), 48 deletions(-)

diff --git a/src/main/java/org/apache/commons/configuration2/convert/AbstractListDelimiterHandler.java b/src/main/java/org/apache/commons/configuration2/convert/AbstractListDelimiterHandler.java
index 85d5db65..a7eb3ddc 100644
--- a/src/main/java/org/apache/commons/configuration2/convert/AbstractListDelimiterHandler.java
+++ b/src/main/java/org/apache/commons/configuration2/convert/AbstractListDelimiterHandler.java
@@ -36,33 +36,6 @@ import java.util.LinkedList;
  * @since 2.0
  */
 public abstract class AbstractListDelimiterHandler implements ListDelimiterHandler {
-    /**
-     * {@inheritDoc} Depending on the type of the passed in object the following things happen:
-     * <ul>
-     * <li>Strings are checked for delimiter characters and split if necessary. This is done by calling the {@code split()}
-     * method.</li>
-     * <li>For objects implementing the {@code Iterable} interface, the corresponding {@code Iterator} is obtained, and
-     * contained elements are added to the resulting iteration.</li>
-     * <li>Arrays are treated as {@code Iterable} objects.</li>
-     * <li>All other types are directly inserted.</li>
-     * <li>Recursive combinations are supported, e.g. a collection containing an array that contains strings: The resulting
-     * collection will only contain primitive objects.</li>
-     * </ul>
-     */
-    @Override
-    public Iterable<?> parse(final Object value) {
-        return flatten(value);
-    }
-
-    /**
-     * {@inheritDoc} This implementation handles the case that the passed in string is <b>null</b>. In this case, an empty
-     * collection is returned. Otherwise, this method delegates to {@link #splitString(String, boolean)}.
-     */
-    @Override
-    public Collection<String> split(final String s, final boolean trim) {
-        return s == null ? new ArrayList<>(0) : splitString(s, trim);
-    }
-
     /**
      * {@inheritDoc} This implementation checks whether the object to be escaped is a string. If yes, it delegates to
      * {@link #escapeString(String)}, otherwise no escaping is performed. Eventually, the passed in transformer is invoked
@@ -73,16 +46,6 @@ public abstract class AbstractListDelimiterHandler implements ListDelimiterHandl
         return transformer.transformValue(value instanceof String ? escapeString((String) value) : value);
     }
 
-    /**
-     * Actually splits the passed in string which is guaranteed to be not <b>null</b>. This method is called by the base
-     * implementation of the {@code split()} method. Here the actual splitting logic has to be implemented.
-     *
-     * @param s the string to be split (not <b>null</b>)
-     * @param trim a flag whether the single components have to be trimmed
-     * @return a collection with the extracted components of the passed in string
-     */
-    protected abstract Collection<String> splitString(String s, boolean trim);
-
     /**
      * Escapes the specified string. This method is called by {@code escape()} if the passed in object is a string. Concrete
      * subclasses have to implement their specific escaping logic here, so that the list delimiters they support are
@@ -93,6 +56,17 @@ public abstract class AbstractListDelimiterHandler implements ListDelimiterHandl
      */
     protected abstract String escapeString(String s);
 
+    /**
+     * 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(final Object value) {
+        return flatten(value, Integer.MAX_VALUE);
+    }
+
     /**
      * 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
@@ -125,17 +99,6 @@ public abstract class AbstractListDelimiterHandler implements ListDelimiterHandl
         return result;
     }
 
-    /**
-     * 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(final Object value) {
-        return flatten(value, Integer.MAX_VALUE);
-    }
-
     /**
      * Flattens the given iterator. For each element in the iteration {@code flatten()} is called recursively.
      *
@@ -150,4 +113,41 @@ public abstract class AbstractListDelimiterHandler implements ListDelimiterHandl
             size = target.size();
         }
     }
+
+    /**
+     * {@inheritDoc} Depending on the type of the passed in object the following things happen:
+     * <ul>
+     * <li>Strings are checked for delimiter characters and split if necessary. This is done by calling the {@code split()}
+     * method.</li>
+     * <li>For objects implementing the {@code Iterable} interface, the corresponding {@code Iterator} is obtained, and
+     * contained elements are added to the resulting iteration.</li>
+     * <li>Arrays are treated as {@code Iterable} objects.</li>
+     * <li>All other types are directly inserted.</li>
+     * <li>Recursive combinations are supported, e.g. a collection containing an array that contains strings: The resulting
+     * collection will only contain primitive objects.</li>
+     * </ul>
+     */
+    @Override
+    public Iterable<?> parse(final Object value) {
+        return flatten(value);
+    }
+
+    /**
+     * {@inheritDoc} This implementation handles the case that the passed in string is <b>null</b>. In this case, an empty
+     * collection is returned. Otherwise, this method delegates to {@link #splitString(String, boolean)}.
+     */
+    @Override
+    public Collection<String> split(final String s, final boolean trim) {
+        return s == null ? new ArrayList<>(0) : splitString(s, trim);
+    }
+
+    /**
+     * Actually splits the passed in string which is guaranteed to be not <b>null</b>. This method is called by the base
+     * implementation of the {@code split()} method. Here the actual splitting logic has to be implemented.
+     *
+     * @param s the string to be split (not <b>null</b>)
+     * @param trim a flag whether the single components have to be trimmed
+     * @return a collection with the extracted components of the passed in string
+     */
+    protected abstract Collection<String> splitString(String s, boolean trim);
 }


[commons-configuration] 03/04: Add org.apache.commons.configuration2.convert.ListDelimiterHandler.flatten(Object, int)

Posted by gg...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-configuration.git

commit c034d659aab642fcf0b29e501c39808149368212
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Thu Jul 14 10:00:58 2022 -0400

    Add org.apache.commons.configuration2.convert.ListDelimiterHandler.flatten(Object,
    int)
---
 .../convert/AbstractListDelimiterHandler.java      | 66 ++++++----------------
 .../convert/DefaultConversionHandler.java          |  2 +-
 .../convert/ListDelimiterHandler.java              | 37 ++++++++++++
 3 files changed, 55 insertions(+), 50 deletions(-)

diff --git a/src/main/java/org/apache/commons/configuration2/convert/AbstractListDelimiterHandler.java b/src/main/java/org/apache/commons/configuration2/convert/AbstractListDelimiterHandler.java
index a7eb3ddc..5fbcd7f9 100644
--- a/src/main/java/org/apache/commons/configuration2/convert/AbstractListDelimiterHandler.java
+++ b/src/main/java/org/apache/commons/configuration2/convert/AbstractListDelimiterHandler.java
@@ -16,11 +16,9 @@
  */
 package org.apache.commons.configuration2.convert;
 
-import java.lang.reflect.Array;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Iterator;
-import java.util.LinkedList;
 
 /**
  * <p>
@@ -36,6 +34,23 @@ import java.util.LinkedList;
  * @since 2.0
  */
 public abstract class AbstractListDelimiterHandler implements ListDelimiterHandler {
+
+    /**
+     * Flattens the given iterator. For each element in the iteration {@code flatten()} is called recursively.
+     *
+     * @param handler the working handler
+     * @param target the target collection
+     * @param iterator the iterator to process
+     * @param limit a limit for the number of elements to extract
+     */
+    static void flattenIterator(final ListDelimiterHandler handler, final Collection<Object> target, final Iterator<?> iterator, final int limit) {
+        int size = target.size();
+        while (size < limit && iterator.hasNext()) {
+            target.addAll(handler.flatten(iterator.next(), limit - size));
+            size = target.size();
+        }
+    }
+
     /**
      * {@inheritDoc} This implementation checks whether the object to be escaped is a string. If yes, it delegates to
      * {@link #escapeString(String)}, otherwise no escaping is performed. Eventually, the passed in transformer is invoked
@@ -67,53 +82,6 @@ public abstract class AbstractListDelimiterHandler implements ListDelimiterHandl
         return flatten(value, Integer.MAX_VALUE);
     }
 
-    /**
-     * 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 &quot;flat&quot; collection containing all primitive values of the passed in object
-     */
-    Collection<?> flatten(final Object value, final int limit) {
-        if (value instanceof String) {
-            return split((String) value, true);
-        }
-        final Collection<Object> result = new LinkedList<>();
-        if (value instanceof Iterable) {
-            flattenIterator(result, ((Iterable<?>) value).iterator(), limit);
-        } else if (value instanceof Iterator) {
-            flattenIterator(result, (Iterator<?>) value, limit);
-        } else if (value != null) {
-            if (value.getClass().isArray()) {
-                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), limit - size));
-                }
-            } else {
-                result.add(value);
-            }
-        }
-        return result;
-    }
-
-    /**
-     * Flattens the given iterator. For each element in the iteration {@code flatten()} is called recursively.
-     *
-     * @param target the target collection
-     * @param iterator the iterator to process
-     * @param limit a limit for the number of elements to extract
-     */
-    private void flattenIterator(final Collection<Object> target, final Iterator<?> iterator, final int limit) {
-        int size = target.size();
-        while (size < limit && iterator.hasNext()) {
-            target.addAll(flatten(iterator.next(), limit - size));
-            size = target.size();
-        }
-    }
-
     /**
      * {@inheritDoc} Depending on the type of the passed in object the following things happen:
      * <ul>
diff --git a/src/main/java/org/apache/commons/configuration2/convert/DefaultConversionHandler.java b/src/main/java/org/apache/commons/configuration2/convert/DefaultConversionHandler.java
index 2f326014..acd3d1ba 100644
--- a/src/main/java/org/apache/commons/configuration2/convert/DefaultConversionHandler.java
+++ b/src/main/java/org/apache/commons/configuration2/convert/DefaultConversionHandler.java
@@ -55,7 +55,7 @@ public class DefaultConversionHandler implements ConversionHandler {
     public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
 
     /** A helper object used for extracting values from complex objects. */
-    private static final AbstractListDelimiterHandler EXTRACTOR = (AbstractListDelimiterHandler) DisabledListDelimiterHandler.INSTANCE;
+    private static final ListDelimiterHandler EXTRACTOR = DisabledListDelimiterHandler.INSTANCE;
 
     /**
      * Constant for a default {@code ConfigurationInterpolator} to be used if none is provided by the caller.
diff --git a/src/main/java/org/apache/commons/configuration2/convert/ListDelimiterHandler.java b/src/main/java/org/apache/commons/configuration2/convert/ListDelimiterHandler.java
index 7b48dacf..090587cb 100644
--- a/src/main/java/org/apache/commons/configuration2/convert/ListDelimiterHandler.java
+++ b/src/main/java/org/apache/commons/configuration2/convert/ListDelimiterHandler.java
@@ -16,7 +16,10 @@
  */
 package org.apache.commons.configuration2.convert;
 
+import java.lang.reflect.Array;
 import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedList;
 import java.util.List;
 
 /**
@@ -100,4 +103,38 @@ public interface ListDelimiterHandler {
      * @return a collection with all components extracted from the string
      */
     Collection<String> split(String s, boolean trim);
+
+    /**
+     * 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 &quot;flat&quot; collection containing all primitive values of the passed in object
+     * @since 2.9.0
+     */
+    default Collection<?> flatten(final Object value, final int limit) {
+        if (value instanceof String) {
+            return split((String) value, true);
+        }
+        final Collection<Object> result = new LinkedList<>();
+        if (value instanceof Iterable) {
+            AbstractListDelimiterHandler.flattenIterator(this, result, ((Iterable<?>) value).iterator(), limit);
+        } else if (value instanceof Iterator) {
+            AbstractListDelimiterHandler.flattenIterator(this, result, (Iterator<?>) value, limit);
+        } else if (value != null) {
+            if (value.getClass().isArray()) {
+                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), limit - size));
+                }
+            } else {
+                result.add(value);
+            }
+        }
+        return result;
+    }
+
 }


[commons-configuration] 02/04: Sort members.

Posted by gg...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-configuration.git

commit f289d6e7905ba84b4967d98ebc94e2390000ed67
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Thu Jul 14 09:48:50 2022 -0400

    Sort members.
---
 .../convert/ListDelimiterHandler.java              | 44 +++++++++++-----------
 1 file changed, 22 insertions(+), 22 deletions(-)

diff --git a/src/main/java/org/apache/commons/configuration2/convert/ListDelimiterHandler.java b/src/main/java/org/apache/commons/configuration2/convert/ListDelimiterHandler.java
index ca4a7cd2..7b48dacf 100644
--- a/src/main/java/org/apache/commons/configuration2/convert/ListDelimiterHandler.java
+++ b/src/main/java/org/apache/commons/configuration2/convert/ListDelimiterHandler.java
@@ -56,6 +56,28 @@ public interface ListDelimiterHandler {
      */
     ValueTransformer NOOP_TRANSFORMER = value -> value;
 
+    /**
+     * Escapes the specified single value object. This method is called for properties containing only a single value. So
+     * this method can rely on the fact that the passed in object is not a list. An implementation has to check whether the
+     * value contains list delimiter characters and - if so - escape them accordingly.
+     *
+     * @param value the value to be escaped
+     * @param transformer a {@code ValueTransformer} for an additional encoding (must not be <b>null</b>)
+     * @return the escaped value
+     */
+    Object escape(Object value, ValueTransformer transformer);
+
+    /**
+     * Escapes all values in the given list and concatenates them to a single string. This operation is required by
+     * configurations that have to represent properties with multiple values in a single line in their external
+     * configuration representation. This may require an advanced escaping in some cases.
+     *
+     * @param values the list with all the values to be converted to a single value
+     * @param transformer a {@code ValueTransformer} for an additional encoding (must not be <b>null</b>)
+     * @return the resulting escaped value
+     */
+    Object escapeList(List<?> values, ValueTransformer transformer);
+
     /**
      * Parses the specified value for list delimiters and splits it if necessary. The passed in object can be either a
      * single value or a complex one, e.g. a collection, an array, or an {@code Iterable}. It is the responsibility of this
@@ -78,26 +100,4 @@ public interface ListDelimiterHandler {
      * @return a collection with all components extracted from the string
      */
     Collection<String> split(String s, boolean trim);
-
-    /**
-     * Escapes the specified single value object. This method is called for properties containing only a single value. So
-     * this method can rely on the fact that the passed in object is not a list. An implementation has to check whether the
-     * value contains list delimiter characters and - if so - escape them accordingly.
-     *
-     * @param value the value to be escaped
-     * @param transformer a {@code ValueTransformer} for an additional encoding (must not be <b>null</b>)
-     * @return the escaped value
-     */
-    Object escape(Object value, ValueTransformer transformer);
-
-    /**
-     * Escapes all values in the given list and concatenates them to a single string. This operation is required by
-     * configurations that have to represent properties with multiple values in a single line in their external
-     * configuration representation. This may require an advanced escaping in some cases.
-     *
-     * @param values the list with all the values to be converted to a single value
-     * @param transformer a {@code ValueTransformer} for an additional encoding (must not be <b>null</b>)
-     * @return the resulting escaped value
-     */
-    Object escapeList(List<?> values, ValueTransformer transformer);
 }