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 19 import java.util.Collection; 20 import java.util.Collections; 21 import java.util.IdentityHashMap; 22 import java.util.List; 23 24 /** 25 * <p> 26 * Definition of an interface that controls the handling of list delimiters in configuration properties. 27 * </p> 28 * <p> 29 * {@link org.apache.commons.configuration2.AbstractConfiguration AbstractConfiguration} supports list delimiters in 30 * property values. If such a delimiter is found, the value actually contains multiple values and has to be split. This 31 * is useful for instance for {@link org.apache.commons.configuration2.PropertiesConfiguration PropertiesConfiguration}: 32 * properties files that have to be compatible with the {@link java.util.Properties} class cannot have multiple 33 * occurrences of a single property key, therefore a different storage scheme for multi-valued properties is needed. A 34 * possible storage scheme could look as follows: 35 * </p> 36 * 37 * <pre> 38 * myProperty=value1,value2,value3 39 * </pre> 40 * 41 * <p> 42 * Here a comma is used as list delimiter. When parsing this property (and using a corresponding 43 * {@code ListDelimiterHandler} implementation) the string value is split, and three values are added for the property 44 * key. 45 * </p> 46 * <p> 47 * A {@code ListDelimiterHandler} knows how to parse and to escape property values. It is called by concrete 48 * {@code Configuration} implementations when they have to deal with properties with multiple values. 49 * </p> 50 * 51 * @since 2.0 52 */ 53 public interface ListDelimiterHandler { 54 /** 55 * A specialized {@code ValueTransformer} implementation which does no transformation. The {@code transformValue()} 56 * method just returns the passed in object without changes. This instance can be used by configurations which do not 57 * require additional encoding. 58 */ 59 ValueTransformer NOOP_TRANSFORMER = value -> value; 60 61 /** 62 * Escapes the specified single value object. This method is called for properties containing only a single value. So 63 * this method can rely on the fact that the passed in object is not a list. An implementation has to check whether the 64 * value contains list delimiter characters and - if so - escape them accordingly. 65 * 66 * @param value the value to be escaped 67 * @param transformer a {@code ValueTransformer} for an additional encoding (must not be <b>null</b>) 68 * @return the escaped value 69 */ 70 Object escape(Object value, ValueTransformer transformer); 71 72 /** 73 * Escapes all values in the given list and concatenates them to a single string. This operation is required by 74 * configurations that have to represent properties with multiple values in a single line in their external 75 * configuration representation. This may require an advanced escaping in some cases. 76 * 77 * @param values the list with all the values to be converted to a single value 78 * @param transformer a {@code ValueTransformer} for an additional encoding (must not be <b>null</b>) 79 * @return the resulting escaped value 80 */ 81 Object escapeList(List<?> values, ValueTransformer transformer); 82 83 /** 84 * Extracts all values contained in the specified object up to the given limit. The passed in object is evaluated (if 85 * necessary in a recursive way). If it is a complex object (e.g. a collection or an array), all its elements are 86 * processed recursively and added to a target collection. The process stops if the limit is reached, but depending on 87 * the input object, it might be exceeded. (The limit is just an indicator to stop the process to avoid unnecessary work 88 * if the caller is only interested in a few values.) 89 * 90 * @param value the value to be processed 91 * @param limit the limit for aborting the processing 92 * @return a "flat" collection containing all primitive values of the passed in object 93 * @since 2.9.0 94 */ 95 default Collection<?> flatten(final Object value, final int limit) { 96 return AbstractListDelimiterHandler.flatten(this, value, limit, Collections.newSetFromMap(new IdentityHashMap<>())); 97 } 98 99 /** 100 * Parses the specified value for list delimiters and splits it if necessary. The passed in object can be either a 101 * single value or a complex one, e.g. a collection, an array, or an {@code Iterable}. It is the responsibility of this 102 * method to return an {@code Iterable} which contains all extracted values. 103 * 104 * @param value the value to be parsed 105 * @return an {@code Iterable} allowing access to all extracted values 106 */ 107 Iterable<?> parse(Object value); 108 109 /** 110 * Splits the specified string at the list delimiter and returns a collection with all extracted components. A concrete 111 * implementation also has to deal with escape characters which might mask a list delimiter character at certain 112 * positions. The boolean {@code trim} flag determines whether each extracted component should be trimmed. This 113 * typically makes sense as the list delimiter may be surrounded by whitespace. However, there may be specific use cases 114 * in which automatic trimming is not desired. 115 * 116 * @param s the string to be split 117 * @param trim a flag whether each component of the string is to be trimmed 118 * @return a collection with all components extracted from the string 119 */ 120 Collection<String> split(String s, boolean trim); 121 122 }