ListDelimiterHandler.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *     http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.apache.commons.configuration2.convert;

  18. import java.util.Collection;
  19. import java.util.Collections;
  20. import java.util.IdentityHashMap;
  21. import java.util.List;

  22. /**
  23.  * <p>
  24.  * Definition of an interface that controls the handling of list delimiters in configuration properties.
  25.  * </p>
  26.  * <p>
  27.  * {@link org.apache.commons.configuration2.AbstractConfiguration AbstractConfiguration} supports list delimiters in
  28.  * property values. If such a delimiter is found, the value actually contains multiple values and has to be split. This
  29.  * is useful for instance for {@link org.apache.commons.configuration2.PropertiesConfiguration PropertiesConfiguration}:
  30.  * properties files that have to be compatible with the {@link java.util.Properties} class cannot have multiple
  31.  * occurrences of a single property key, therefore a different storage scheme for multi-valued properties is needed. A
  32.  * possible storage scheme could look as follows:
  33.  * </p>
  34.  *
  35.  * <pre>
  36.  * myProperty=value1,value2,value3
  37.  * </pre>
  38.  *
  39.  * <p>
  40.  * Here a comma is used as list delimiter. When parsing this property (and using a corresponding
  41.  * {@code ListDelimiterHandler} implementation) the string value is split, and three values are added for the property
  42.  * key.
  43.  * </p>
  44.  * <p>
  45.  * A {@code ListDelimiterHandler} knows how to parse and to escape property values. It is called by concrete
  46.  * {@code Configuration} implementations when they have to deal with properties with multiple values.
  47.  * </p>
  48.  *
  49.  * @since 2.0
  50.  */
  51. public interface ListDelimiterHandler {
  52.     /**
  53.      * A specialized {@code ValueTransformer} implementation which does no transformation. The {@code transformValue()}
  54.      * method just returns the passed in object without changes. This instance can be used by configurations which do not
  55.      * require additional encoding.
  56.      */
  57.     ValueTransformer NOOP_TRANSFORMER = value -> value;

  58.     /**
  59.      * Escapes the specified single value object. This method is called for properties containing only a single value. So
  60.      * this method can rely on the fact that the passed in object is not a list. An implementation has to check whether the
  61.      * value contains list delimiter characters and - if so - escape them accordingly.
  62.      *
  63.      * @param value the value to be escaped
  64.      * @param transformer a {@code ValueTransformer} for an additional encoding (must not be <strong>null</strong>)
  65.      * @return the escaped value
  66.      */
  67.     Object escape(Object value, ValueTransformer transformer);

  68.     /**
  69.      * Escapes all values in the given list and concatenates them to a single string. This operation is required by
  70.      * configurations that have to represent properties with multiple values in a single line in their external
  71.      * configuration representation. This may require an advanced escaping in some cases.
  72.      *
  73.      * @param values the list with all the values to be converted to a single value
  74.      * @param transformer a {@code ValueTransformer} for an additional encoding (must not be <strong>null</strong>)
  75.      * @return the resulting escaped value
  76.      */
  77.     Object escapeList(List<?> values, ValueTransformer transformer);

  78.     /**
  79.      * Extracts all values contained in the specified object up to the given limit. The passed in object is evaluated (if
  80.      * necessary in a recursive way). If it is a complex object (for example a collection or an array), all its elements are
  81.      * processed recursively and added to a target collection. The process stops if the limit is reached, but depending on
  82.      * the input object, it might be exceeded. (The limit is just an indicator to stop the process to avoid unnecessary work
  83.      * if the caller is only interested in a few values.)
  84.      *
  85.      * @param value the value to be processed
  86.      * @param limit the limit for aborting the processing
  87.      * @return a &quot;flat&quot; collection containing all primitive values of the passed in object
  88.      * @since 2.9.0
  89.      */
  90.     default Collection<?> flatten(final Object value, final int limit) {
  91.         return AbstractListDelimiterHandler.flatten(this, value, limit, Collections.newSetFromMap(new IdentityHashMap<>()));
  92.     }

  93.     /**
  94.      * Parses the specified value for list delimiters and splits it if necessary. The passed in object can be either a
  95.      * single value or a complex one, for example a collection, an array, or an {@code Iterable}. It is the responsibility of this
  96.      * method to return an {@code Iterable} which contains all extracted values.
  97.      *
  98.      * @param value the value to be parsed
  99.      * @return an {@code Iterable} allowing access to all extracted values
  100.      */
  101.     Iterable<?> parse(Object value);

  102.     /**
  103.      * Splits the specified string at the list delimiter and returns a collection with all extracted components. A concrete
  104.      * implementation also has to deal with escape characters which might mask a list delimiter character at certain
  105.      * positions. The boolean {@code trim} flag determines whether each extracted component should be trimmed. This
  106.      * typically makes sense as the list delimiter may be surrounded by whitespace. However, there may be specific use cases
  107.      * in which automatic trimming is not desired.
  108.      *
  109.      * @param s the string to be split
  110.      * @param trim a flag whether each component of the string is to be trimmed
  111.      * @return a collection with all components extracted from the string
  112.      */
  113.     Collection<String> split(String s, boolean trim);

  114. }