- /*
- * Copyright 2001-2004 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package org.apache.commons.collections;
-
- import java.io.PrintStream;
- import java.text.NumberFormat;
- import java.text.ParseException;
- import java.util.Collections;
- import java.util.Enumeration;
- import java.util.HashMap;
- import java.util.Iterator;
- import java.util.Map;
- import java.util.Properties;
- import java.util.ResourceBundle;
- import java.util.SortedMap;
- import java.util.TreeMap;
-
- import org.apache.commons.collections.map.FixedSizeMap;
- import org.apache.commons.collections.map.FixedSizeSortedMap;
- import org.apache.commons.collections.map.LazyMap;
- import org.apache.commons.collections.map.LazySortedMap;
- import org.apache.commons.collections.map.ListOrderedMap;
- import org.apache.commons.collections.map.PredicatedMap;
- import org.apache.commons.collections.map.PredicatedSortedMap;
- import org.apache.commons.collections.map.TransformedMap;
- import org.apache.commons.collections.map.TransformedSortedMap;
- import org.apache.commons.collections.map.TypedMap;
- import org.apache.commons.collections.map.TypedSortedMap;
- import org.apache.commons.collections.map.UnmodifiableMap;
- import org.apache.commons.collections.map.UnmodifiableSortedMap;
-
- /**
- * Provides utility methods and decorators for
- * {@link Map} and {@link SortedMap} instances.
- * <p>
- * It contains various type safe methods
- * as well as other useful features like deep copying.
- * <p>
- * It also provides the following decorators:
- *
- * <ul>
- * <li>{@link #fixedSizeMap(Map)}
- * <li>{@link #fixedSizeSortedMap(SortedMap)}
- * <li>{@link #lazyMap(Map,Factory)}
- * <li>{@link #lazyMap(Map,Transformer)}
- * <li>{@link #lazySortedMap(SortedMap,Factory)}
- * <li>{@link #lazySortedMap(SortedMap,Transformer)}
- * <li>{@link #predicatedMap(Map,Predicate,Predicate)}
- * <li>{@link #predicatedSortedMap(SortedMap,Predicate,Predicate)}
- * <li>{@link #transformedMap(Map, Transformer, Transformer)}
- * <li>{@link #transformedSortedMap(SortedMap, Transformer, Transformer)}
- * <li>{@link #typedMap(Map, Class, Class)}
- * <li>{@link #typedSortedMap(SortedMap, Class, Class)}
- * </ul>
- *
- * @since Commons Collections 1.0
- * @version $Revision: 1.46 $ $Date: 2004/04/21 20:34:11 $
- *
- * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
- * @author <a href="mailto:nissim@nksystems.com">Nissim Karpenstein</a>
- * @author <a href="mailto:knielsen@apache.org">Kasper Nielsen</a>
- * @author Paul Jack
- * @author Stephen Colebourne
- * @author Matthew Hawthorne
- * @author Arun Mammen Thomas
- * @author Janek Bogucki
- * @author Max Rydahl Andersen
- * @author <a href="mailto:equinus100@hotmail.com">Ashwin S</a>
- */
- public class MapUtils {
-
- /**
- * An empty unmodifiable map.
- * This was not provided in JDK1.2.
- */
- public static final Map EMPTY_MAP = UnmodifiableMap.decorate(new HashMap(1));
- /**
- * An empty unmodifiable sorted map.
- * This is not provided in the JDK.
- */
- public static final SortedMap EMPTY_SORTED_MAP = UnmodifiableSortedMap.decorate(new TreeMap());
- /**
- * String used to indent the verbose and debug Map prints.
- */
- private static final String INDENT_STRING = " ";
-
- /**
- * <code>MapUtils</code> should not normally be instantiated.
- */
- public MapUtils() {
- }
-
- // Type safe getters
- //-------------------------------------------------------------------------
- /**
- * Gets from a Map in a null-safe manner.
- *
- * @param map the map to use
- * @param key the key to look up
- * @return the value in the Map, <code>null</code> if null map input
- */
- public static Object getObject(final Map map, final Object key) {
- if (map != null) {
- return map.get(key);
- }
- return null;
- }
-
- /**
- * Gets a String from a Map in a null-safe manner.
- * <p>
- * The String is obtained via <code>toString</code>.
- *
- * @param map the map to use
- * @param key the key to look up
- * @return the value in the Map as a String, <code>null</code> if null map input
- */
- public static String getString(final Map map, final Object key) {
- if (map != null) {
- Object answer = map.get(key);
- if (answer != null) {
- return answer.toString();
- }
- }
- return null;
- }
-
- /**
- * Gets a Boolean from a Map in a null-safe manner.
- * <p>
- * If the value is a <code>Boolean</code> it is returned directly.
- * If the value is a <code>String</code> and it equals 'true' ignoring case
- * then <code>true</code> is returned, otherwise <code>false</code>.
- * If the value is a <code>Number</code> an integer zero value returns
- * <code>false</code> and non-zero returns <code>true</code>.
- * Otherwise, <code>null</code> is returned.
- *
- * @param map the map to use
- * @param key the key to look up
- * @return the value in the Map as a Boolean, <code>null</code> if null map input
- */
- public static Boolean getBoolean(final Map map, final Object key) {
- if (map != null) {
- Object answer = map.get(key);
- if (answer != null) {
- if (answer instanceof Boolean) {
- return (Boolean) answer;
-
- } else if (answer instanceof String) {
- return new Boolean((String) answer);
-
- } else if (answer instanceof Number) {
- Number n = (Number) answer;
- return (n.intValue() != 0) ? Boolean.TRUE : Boolean.FALSE;
- }
- }
- }
- return null;
- }
-
- /**
- * Gets a Number from a Map in a null-safe manner.
- * <p>
- * If the value is a <code>Number</code> it is returned directly.
- * If the value is a <code>String</code> it is converted using
- * {@link NumberFormat#parse(String)} on the system default formatter
- * returning <code>null</code> if the conversion fails.
- * Otherwise, <code>null</code> is returned.
- *
- * @param map the map to use
- * @param key the key to look up
- * @return the value in the Map as a Number, <code>null</code> if null map input
- */
- public static Number getNumber(final Map map, final Object key) {
- if (map != null) {
- Object answer = map.get(key);
- if (answer != null) {
- if (answer instanceof Number) {
- return (Number) answer;
-
- } else if (answer instanceof String) {
- try {
- String text = (String) answer;
- return NumberFormat.getInstance().parse(text);
-
- } catch (ParseException e) {
- logInfo(e);
- }
- }
- }
- }
- return null;
- }
-
- /**
- * Gets a Byte from a Map in a null-safe manner.
- * <p>
- * The Byte is obtained from the results of {@link #getNumber(Map,Object)}.
- *
- * @param map the map to use
- * @param key the key to look up
- * @return the value in the Map as a Byte, <code>null</code> if null map input
- */
- public static Byte getByte(final Map map, final Object key) {
- Number answer = getNumber(map, key);
- if (answer == null) {
- return null;
- } else if (answer instanceof Byte) {
- return (Byte) answer;
- }
- return new Byte(answer.byteValue());
- }
-
- /**
- * Gets a Short from a Map in a null-safe manner.
- * <p>
- * The Short is obtained from the results of {@link #getNumber(Map,Object)}.
- *
- * @param map the map to use
- * @param key the key to look up
- * @return the value in the Map as a Short, <code>null</code> if null map input
- */
- public static Short getShort(final Map map, final Object key) {
- Number answer = getNumber(map, key);
- if (answer == null) {
- return null;
- } else if (answer instanceof Short) {
- return (Short) answer;
- }
- return new Short(answer.shortValue());
- }
-
- /**
- * Gets a Integer from a Map in a null-safe manner.
- * <p>
- * The Integer is obtained from the results of {@link #getNumber(Map,Object)}.
- *
- * @param map the map to use
- * @param key the key to look up
- * @return the value in the Map as a Integer, <code>null</code> if null map input
- */
- public static Integer getInteger(final Map map, final Object key) {
- Number answer = getNumber(map, key);
- if (answer == null) {
- return null;
- } else if (answer instanceof Integer) {
- return (Integer) answer;
- }
- return new Integer(answer.intValue());
- }
-
- /**
- * Gets a Long from a Map in a null-safe manner.
- * <p>
- * The Long is obtained from the results of {@link #getNumber(Map,Object)}.
- *
- * @param map the map to use
- * @param key the key to look up
- * @return the value in the Map as a Long, <code>null</code> if null map input
- */
- public static Long getLong(final Map map, final Object key) {
- Number answer = getNumber(map, key);
- if (answer == null) {
- return null;
- } else if (answer instanceof Long) {
- return (Long) answer;
- }
- return new Long(answer.longValue());
- }
-
- /**
- * Gets a Float from a Map in a null-safe manner.
- * <p>
- * The Float is obtained from the results of {@link #getNumber(Map,Object)}.
- *
- * @param map the map to use
- * @param key the key to look up
- * @return the value in the Map as a Float, <code>null</code> if null map input
- */
- public static Float getFloat(final Map map, final Object key) {
- Number answer = getNumber(map, key);
- if (answer == null) {
- return null;
- } else if (answer instanceof Float) {
- return (Float) answer;
- }
- return new Float(answer.floatValue());
- }
-
- /**
- * Gets a Double from a Map in a null-safe manner.
- * <p>
- * The Double is obtained from the results of {@link #getNumber(Map,Object)}.
- *
- * @param map the map to use
- * @param key the key to look up
- * @return the value in the Map as a Double, <code>null</code> if null map input
- */
- public static Double getDouble(final Map map, final Object key) {
- Number answer = getNumber(map, key);
- if (answer == null) {
- return null;
- } else if (answer instanceof Double) {
- return (Double) answer;
- }
- return new Double(answer.doubleValue());
- }
-
- /**
- * Gets a Map from a Map in a null-safe manner.
- * <p>
- * If the value returned from the specified map is not a Map then
- * <code>null</code> is returned.
- *
- * @param map the map to use
- * @param key the key to look up
- * @return the value in the Map as a Map, <code>null</code> if null map input
- */
- public static Map getMap(final Map map, final Object key) {
- if (map != null) {
- Object answer = map.get(key);
- if (answer != null && answer instanceof Map) {
- return (Map) answer;
- }
- }
- return null;
- }
-
- // Type safe getters with default values
- //-------------------------------------------------------------------------
- /**
- * Looks up the given key in the given map, converting null into the
- * given default value.
- *
- * @param map the map whose value to look up
- * @param key the key of the value to look up in that map
- * @param defaultValue what to return if the value is null
- * @return the value in the map, or defaultValue if the original value
- * is null or the map is null
- */
- public static Object getObject( Map map, Object key, Object defaultValue ) {
- if ( map != null ) {
- Object answer = map.get( key );
- if ( answer != null ) {
- return answer;
- }
- }
- return defaultValue;
- }
-
- /**
- * Looks up the given key in the given map, converting the result into
- * a string, using the default value if the the conversion fails.
- *
- * @param map the map whose value to look up
- * @param key the key of the value to look up in that map
- * @param defaultValue what to return if the value is null or if the
- * conversion fails
- * @return the value in the map as a string, or defaultValue if the
- * original value is null, the map is null or the string conversion
- * fails
- */
- public static String getString( Map map, Object key, String defaultValue ) {
- String answer = getString( map, key );
- if ( answer == null ) {
- answer = defaultValue;
- }
- return answer;
- }
-
- /**
- * Looks up the given key in the given map, converting the result into
- * a boolean, using the default value if the the conversion fails.
- *
- * @param map the map whose value to look up
- * @param key the key of the value to look up in that map
- * @param defaultValue what to return if the value is null or if the
- * conversion fails
- * @return the value in the map as a boolean, or defaultValue if the
- * original value is null, the map is null or the boolean conversion
- * fails
- */
- public static Boolean getBoolean( Map map, Object key, Boolean defaultValue ) {
- Boolean answer = getBoolean( map, key );
- if ( answer == null ) {
- answer = defaultValue;
- }
- return answer;
- }
-
- /**
- * Looks up the given key in the given map, converting the result into
- * a number, using the default value if the the conversion fails.
- *
- * @param map the map whose value to look up
- * @param key the key of the value to look up in that map
- * @param defaultValue what to return if the value is null or if the
- * conversion fails
- * @return the value in the map as a number, or defaultValue if the
- * original value is null, the map is null or the number conversion
- * fails
- */
- public static Number getNumber( Map map, Object key, Number defaultValue ) {
- Number answer = getNumber( map, key );
- if ( answer == null ) {
- answer = defaultValue;
- }
- return answer;
- }
-
- /**
- * Looks up the given key in the given map, converting the result into
- * a byte, using the default value if the the conversion fails.
- *
- * @param map the map whose value to look up
- * @param key the key of the value to look up in that map
- * @param defaultValue what to return if the value is null or if the
- * conversion fails
- * @return the value in the map as a number, or defaultValue if the
- * original value is null, the map is null or the number conversion
- * fails
- */
- public static Byte getByte( Map map, Object key, Byte defaultValue ) {
- Byte answer = getByte( map, key );
- if ( answer == null ) {
- answer = defaultValue;
- }
- return answer;
- }
-
- /**
- * Looks up the given key in the given map, converting the result into
- * a short, using the default value if the the conversion fails.
- *
- * @param map the map whose value to look up
- * @param key the key of the value to look up in that map
- * @param defaultValue what to return if the value is null or if the
- * conversion fails
- * @return the value in the map as a number, or defaultValue if the
- * original value is null, the map is null or the number conversion
- * fails
- */
- public static Short getShort( Map map, Object key, Short defaultValue ) {
- Short answer = getShort( map, key );
- if ( answer == null ) {
- answer = defaultValue;
- }
- return answer;
- }
-
- /**
- * Looks up the given key in the given map, converting the result into
- * an integer, using the default value if the the conversion fails.
- *
- * @param map the map whose value to look up
- * @param key the key of the value to look up in that map
- * @param defaultValue what to return if the value is null or if the
- * conversion fails
- * @return the value in the map as a number, or defaultValue if the
- * original value is null, the map is null or the number conversion
- * fails
- */
- public static Integer getInteger( Map map, Object key, Integer defaultValue ) {
- Integer answer = getInteger( map, key );
- if ( answer == null ) {
- answer = defaultValue;
- }
- return answer;
- }
-
- /**
- * Looks up the given key in the given map, converting the result into
- * a long, using the default value if the the conversion fails.
- *
- * @param map the map whose value to look up
- * @param key the key of the value to look up in that map
- * @param defaultValue what to return if the value is null or if the
- * conversion fails
- * @return the value in the map as a number, or defaultValue if the
- * original value is null, the map is null or the number conversion
- * fails
- */
- public static Long getLong( Map map, Object key, Long defaultValue ) {
- Long answer = getLong( map, key );
- if ( answer == null ) {
- answer = defaultValue;
- }
- return answer;
- }
-
- /**
- * Looks up the given key in the given map, converting the result into
- * a float, using the default value if the the conversion fails.
- *
- * @param map the map whose value to look up
- * @param key the key of the value to look up in that map
- * @param defaultValue what to return if the value is null or if the
- * conversion fails
- * @return the value in the map as a number, or defaultValue if the
- * original value is null, the map is null or the number conversion
- * fails
- */
- public static Float getFloat( Map map, Object key, Float defaultValue ) {
- Float answer = getFloat( map, key );
- if ( answer == null ) {
- answer = defaultValue;
- }
- return answer;
- }
-
- /**
- * Looks up the given key in the given map, converting the result into
- * a double, using the default value if the the conversion fails.
- *
- * @param map the map whose value to look up
- * @param key the key of the value to look up in that map
- * @param defaultValue what to return if the value is null or if the
- * conversion fails
- * @return the value in the map as a number, or defaultValue if the
- * original value is null, the map is null or the number conversion
- * fails
- */
- public static Double getDouble( Map map, Object key, Double defaultValue ) {
- Double answer = getDouble( map, key );
- if ( answer == null ) {
- answer = defaultValue;
- }
- return answer;
- }
-
- /**
- * Looks up the given key in the given map, converting the result into
- * a map, using the default value if the the conversion fails.
- *
- * @param map the map whose value to look up
- * @param key the key of the value to look up in that map
- * @param defaultValue what to return if the value is null or if the
- * conversion fails
- * @return the value in the map as a number, or defaultValue if the
- * original value is null, the map is null or the map conversion
- * fails
- */
- public static Map getMap( Map map, Object key, Map defaultValue ) {
- Map answer = getMap( map, key );
- if ( answer == null ) {
- answer = defaultValue;
- }
- return answer;
- }
-
-
- // Type safe primitive getters
- //-------------------------------------------------------------------------
- /**
- * Gets a boolean from a Map in a null-safe manner.
- * <p>
- * If the value is a <code>Boolean</code> its value is returned.
- * If the value is a <code>String</code> and it equals 'true' ignoring case
- * then <code>true</code> is returned, otherwise <code>false</code>.
- * If the value is a <code>Number</code> an integer zero value returns
- * <code>false</code> and non-zero returns <code>true</code>.
- * Otherwise, <code>false</code> is returned.
- *
- * @param map the map to use
- * @param key the key to look up
- * @return the value in the Map as a Boolean, <code>false</code> if null map input
- */
- public static boolean getBooleanValue(final Map map, final Object key) {
- Boolean booleanObject = getBoolean(map, key);
- if (booleanObject == null) {
- return false;
- }
- return booleanObject.booleanValue();
- }
-
- /**
- * Gets a byte from a Map in a null-safe manner.
- * <p>
- * The byte is obtained from the results of {@link #getNumber(Map,Object)}.
- *
- * @param map the map to use
- * @param key the key to look up
- * @return the value in the Map as a byte, <code>0</code> if null map input
- */
- public static byte getByteValue(final Map map, final Object key) {
- Byte byteObject = getByte(map, key);
- if (byteObject == null) {
- return 0;
- }
- return byteObject.byteValue();
- }
-
- /**
- * Gets a short from a Map in a null-safe manner.
- * <p>
- * The short is obtained from the results of {@link #getNumber(Map,Object)}.
- *
- * @param map the map to use
- * @param key the key to look up
- * @return the value in the Map as a short, <code>0</code> if null map input
- */
- public static short getShortValue(final Map map, final Object key) {
- Short shortObject = getShort(map, key);
- if (shortObject == null) {
- return 0;
- }
- return shortObject.shortValue();
- }
-
- /**
- * Gets an int from a Map in a null-safe manner.
- * <p>
- * The int is obtained from the results of {@link #getNumber(Map,Object)}.
- *
- * @param map the map to use
- * @param key the key to look up
- * @return the value in the Map as an int, <code>0</code> if null map input
- */
- public static int getIntValue(final Map map, final Object key) {
- Integer integerObject = getInteger(map, key);
- if (integerObject == null) {
- return 0;
- }
- return integerObject.intValue();
- }
-
- /**
- * Gets a long from a Map in a null-safe manner.
- * <p>
- * The long is obtained from the results of {@link #getNumber(Map,Object)}.
- *
- * @param map the map to use
- * @param key the key to look up
- * @return the value in the Map as a long, <code>0L</code> if null map input
- */
- public static long getLongValue(final Map map, final Object key) {
- Long longObject = getLong(map, key);
- if (longObject == null) {
- return 0L;
- }
- return longObject.longValue();
- }
-
- /**
- * Gets a float from a Map in a null-safe manner.
- * <p>
- * The float is obtained from the results of {@link #getNumber(Map,Object)}.
- *
- * @param map the map to use
- * @param key the key to look up
- * @return the value in the Map as a float, <code>0.0F</code> if null map input
- */
- public static float getFloatValue(final Map map, final Object key) {
- Float floatObject = getFloat(map, key);
- if (floatObject == null) {
- return 0f;
- }
- return floatObject.floatValue();
- }
-
- /**
- * Gets a double from a Map in a null-safe manner.
- * <p>
- * The double is obtained from the results of {@link #getNumber(Map,Object)}.
- *
- * @param map the map to use
- * @param key the key to look up
- * @return the value in the Map as a double, <code>0.0</code> if null map input
- */
- public static double getDoubleValue(final Map map, final Object key) {
- Double doubleObject = getDouble(map, key);
- if (doubleObject == null) {
- return 0d;
- }
- return doubleObject.doubleValue();
- }
-
- // Type safe primitive getters with default values
- //-------------------------------------------------------------------------
- /**
- * Gets a boolean from a Map in a null-safe manner,
- * using the default value if the the conversion fails.
- * <p>
- * If the value is a <code>Boolean</code> its value is returned.
- * If the value is a <code>String</code> and it equals 'true' ignoring case
- * then <code>true</code> is returned, otherwise <code>false</code>.
- * If the value is a <code>Number</code> an integer zero value returns
- * <code>false</code> and non-zero returns <code>true</code>.
- * Otherwise, <code>defaultValue</code> is returned.
- *
- * @param map the map to use
- * @param key the key to look up
- * @param defaultValue return if the value is null or if the
- * conversion fails
- * @return the value in the Map as a Boolean, <code>defaultValue</code> if null map input
- */
- public static boolean getBooleanValue(final Map map, final Object key, boolean defaultValue) {
- Boolean booleanObject = getBoolean(map, key);
- if (booleanObject == null) {
- return defaultValue;
- }
- return booleanObject.booleanValue();
- }
-
- /**
- * Gets a byte from a Map in a null-safe manner,
- * using the default value if the the conversion fails.
- * <p>
- * The byte is obtained from the results of {@link #getNumber(Map,Object)}.
- *
- * @param map the map to use
- * @param key the key to look up
- * @param defaultValue return if the value is null or if the
- * conversion fails
- * @return the value in the Map as a byte, <code>defaultValue</code> if null map input
- */
- public static byte getByteValue(final Map map, final Object key, byte defaultValue) {
- Byte byteObject = getByte(map, key);
- if (byteObject == null) {
- return defaultValue;
- }
- return byteObject.byteValue();
- }
-
- /**
- * Gets a short from a Map in a null-safe manner,
- * using the default value if the the conversion fails.
- * <p>
- * The short is obtained from the results of {@link #getNumber(Map,Object)}.
- *
- * @param map the map to use
- * @param key the key to look up
- * @param defaultValue return if the value is null or if the
- * conversion fails
- * @return the value in the Map as a short, <code>defaultValue</code> if null map input
- */
- public static short getShortValue(final Map map, final Object key, short defaultValue) {
- Short shortObject = getShort(map, key);
- if (shortObject == null) {
- return defaultValue;
- }
- return shortObject.shortValue();
- }
-
- /**
- * Gets an int from a Map in a null-safe manner,
- * using the default value if the the conversion fails.
- * <p>
- * The int is obtained from the results of {@link #getNumber(Map,Object)}.
- *
- * @param map the map to use
- * @param key the key to look up
- * @param defaultValue return if the value is null or if the
- * conversion fails
- * @return the value in the Map as an int, <code>defaultValue</code> if null map input
- */
- public static int getIntValue(final Map map, final Object key, int defaultValue) {
- Integer integerObject = getInteger(map, key);
- if (integerObject == null) {
- return defaultValue;
- }
- return integerObject.intValue();
- }
-
- /**
- * Gets a long from a Map in a null-safe manner,
- * using the default value if the the conversion fails.
- * <p>
- * The long is obtained from the results of {@link #getNumber(Map,Object)}.
- *
- * @param map the map to use
- * @param key the key to look up
- * @param defaultValue return if the value is null or if the
- * conversion fails
- * @return the value in the Map as a long, <code>defaultValue</code> if null map input
- */
- public static long getLongValue(final Map map, final Object key, long defaultValue) {
- Long longObject = getLong(map, key);
- if (longObject == null) {
- return defaultValue;
- }
- return longObject.longValue();
- }
-
- /**
- * Gets a float from a Map in a null-safe manner,
- * using the default value if the the conversion fails.
- * <p>
- * The float is obtained from the results of {@link #getNumber(Map,Object)}.
- *
- * @param map the map to use
- * @param key the key to look up
- * @param defaultValue return if the value is null or if the
- * conversion fails
- * @return the value in the Map as a float, <code>defaultValue</code> if null map input
- */
- public static float getFloatValue(final Map map, final Object key, float defaultValue) {
- Float floatObject = getFloat(map, key);
- if (floatObject == null) {
- return defaultValue;
- }
- return floatObject.floatValue();
- }
-
- /**
- * Gets a double from a Map in a null-safe manner,
- * using the default value if the the conversion fails.
- * <p>
- * The double is obtained from the results of {@link #getNumber(Map,Object)}.
- *
- * @param map the map to use
- * @param key the key to look up
- * @param defaultValue return if the value is null or if the
- * conversion fails
- * @return the value in the Map as a double, <code>defaultValue</code> if null map input
- */
- public static double getDoubleValue(final Map map, final Object key, double defaultValue) {
- Double doubleObject = getDouble(map, key);
- if (doubleObject == null) {
- return defaultValue;
- }
- return doubleObject.doubleValue();
- }
-
- // Conversion methods
- //-------------------------------------------------------------------------
- /**
- * Gets a new Properties object initialised with the values from a Map.
- * A null input will return an empty properties object.
- *
- * @param map the map to convert to a Properties object, may not be null
- * @return the properties object
- */
- public static Properties toProperties(final Map map) {
- Properties answer = new Properties();
- if (map != null) {
- for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) {
- Map.Entry entry = (Map.Entry) iter.next();
- Object key = entry.getKey();
- Object value = entry.getValue();
- answer.put(key, value);
- }
- }
- return answer;
- }
-
- /**
- * Creates a new HashMap using data copied from a ResourceBundle.
- *
- * @param resourceBundle the resource bundle to convert, may not be null
- * @return the hashmap containing the data
- * @throws NullPointerException if the bundle is null
- */
- public static Map toMap(final ResourceBundle resourceBundle) {
- Enumeration enumeration = resourceBundle.getKeys();
- Map map = new HashMap();
-
- while (enumeration.hasMoreElements()) {
- String key = (String) enumeration.nextElement();
- Object value = resourceBundle.getObject(key);
- map.put(key, value);
- }
-
- return map;
- }
-
- // Printing methods
- //-------------------------------------------------------------------------
- /**
- * Prints the given map with nice line breaks.
- * <p>
- * This method prints a nicely formatted String describing the Map.
- * Each map entry will be printed with key and value.
- * When the value is a Map, recursive behaviour occurs.
- * <p>
- * This method is NOT thread-safe in any special way. You must manually
- * synchronize on either this class or the stream as required.
- *
- * @param out the stream to print to, must not be null
- * @param label The label to be used, may be <code>null</code>.
- * If <code>null</code>, the label is not output.
- * It typically represents the name of the property in a bean or similar.
- * @param map The map to print, may be <code>null</code>.
- * If <code>null</code>, the text 'null' is output.
- * @throws NullPointerException if the stream is <code>null</code>
- */
- public static void verbosePrint(
- final PrintStream out,
- final Object label,
- final Map map) {
-
- verbosePrintInternal(out, label, map, new ArrayStack(), false);
- }
-
- /**
- * Prints the given map with nice line breaks.
- * <p>
- * This method prints a nicely formatted String describing the Map.
- * Each map entry will be printed with key, value and value classname.
- * When the value is a Map, recursive behaviour occurs.
- * <p>
- * This method is NOT thread-safe in any special way. You must manually
- * synchronize on either this class or the stream as required.
- *
- * @param out the stream to print to, must not be null
- * @param label The label to be used, may be <code>null</code>.
- * If <code>null</code>, the label is not output.
- * It typically represents the name of the property in a bean or similar.
- * @param map The map to print, may be <code>null</code>.
- * If <code>null</code>, the text 'null' is output.
- * @throws NullPointerException if the stream is <code>null</code>
- */
- public static void debugPrint(
- final PrintStream out,
- final Object label,
- final Map map) {
-
- verbosePrintInternal(out, label, map, new ArrayStack(), true);
- }
-
- // Implementation methods
- //-------------------------------------------------------------------------
- /**
- * Logs the given exception to <code>System.out</code>.
- * <p>
- * This method exists as Jakarta Collections does not depend on logging.
- *
- * @param ex the exception to log
- */
- protected static void logInfo(final Exception ex) {
- System.out.println("INFO: Exception: " + ex);
- }
-
- /**
- * Implementation providing functionality for {@link #debugPrint} and for
- * {@link #verbosePrint}. This prints the given map with nice line breaks.
- * If the debug flag is true, it additionally prints the type of the object
- * value. If the contents of a map include the map itself, then the text
- * <em>(this Map)</em> is printed out. If the contents include a
- * parent container of the map, the the text <em>(ancestor[i] Map)</em> is
- * printed, where i actually indicates the number of levels which must be
- * traversed in the sequential list of ancestors (e.g. father, grandfather,
- * great-grandfather, etc).
- *
- * @param out the stream to print to
- * @param label the label to be used, may be <code>null</code>.
- * If <code>null</code>, the label is not output.
- * It typically represents the name of the property in a bean or similar.
- * @param map the map to print, may be <code>null</code>.
- * If <code>null</code>, the text 'null' is output
- * @param lineage a stack consisting of any maps in which the previous
- * argument is contained. This is checked to avoid infinite recursion when
- * printing the output
- * @param debug flag indicating whether type names should be output.
- * @throws NullPointerException if the stream is <code>null</code>
- */
- private static void verbosePrintInternal(
- final PrintStream out,
- final Object label,
- final Map map,
- final ArrayStack lineage,
- final boolean debug) {
-
- printIndent(out, lineage.size());
-
- if (map == null) {
- if (label != null) {
- out.print(label);
- out.print(" = ");
- }
- out.println("null");
- return;
- }
- if (label != null) {
- out.print(label);
- out.println(" = ");
- }
-
- printIndent(out, lineage.size());
- out.println("{");
-
- lineage.push(map);
-
- for (Iterator it = map.entrySet().iterator(); it.hasNext();) {
- Map.Entry entry = (Map.Entry) it.next();
- Object childKey = entry.getKey();
- Object childValue = entry.getValue();
- if (childValue instanceof Map && !lineage.contains(childValue)) {
- verbosePrintInternal(
- out,
- (childKey == null ? "null" : childKey),
- (Map) childValue,
- lineage,
- debug);
- } else {
- printIndent(out, lineage.size());
- out.print(childKey);
- out.print(" = ");
-
- final int lineageIndex = lineage.indexOf(childValue);
- if (lineageIndex == -1) {
- out.print(childValue);
- } else if (lineage.size() - 1 == lineageIndex) {
- out.print("(this Map)");
- } else {
- out.print(
- "(ancestor["
- + (lineage.size() - 1 - lineageIndex - 1)
- + "] Map)");
- }
-
- if (debug && childValue != null) {
- out.print(' ');
- out.println(childValue.getClass().getName());
- } else {
- out.println();
- }
- }
- }
-
- lineage.pop();
-
- printIndent(out, lineage.size());
- out.println(debug ? "} " + map.getClass().getName() : "}");
- }
-
- /**
- * Writes indentation to the given stream.
- *
- * @param out the stream to indent
- */
- private static void printIndent(final PrintStream out, final int indent) {
- for (int i = 0; i < indent; i++) {
- out.print(INDENT_STRING);
- }
- }
-
- // Misc
- //-----------------------------------------------------------------------
- /**
- * Inverts the supplied map returning a new HashMap such that the keys of
- * the input are swapped with the values.
- * <p>
- * This operation assumes that the inverse mapping is well defined.
- * If the input map had multiple entries with the same value mapped to
- * different keys, the returned map will map one of those keys to the
- * value, but the exact key which will be mapped is undefined.
- *
- * @see DoubleOrderedMap
- * @param map the map to invert, may not be null
- * @return a new HashMap containing the inverted data
- * @throws NullPointerException if the map is null
- */
- public static Map invertMap(Map map) {
- Map out = new HashMap(map.size());
- for (Iterator it = map.entrySet().iterator(); it.hasNext();) {
- Map.Entry entry = (Map.Entry) it.next();
- out.put(entry.getValue(), entry.getKey());
- }
- return out;
- }
-
- /**
- * Nice method for adding data to a map in such a way
- * as to not get NPE's. The point being that if the
- * value is null, map.put() will throw an exception.
- * That blows in the case of this class cause you may want to
- * essentially treat put("Not Null", null ) == put("Not Null", "")
- * We will still throw a NPE if the key is null cause that should
- * never happen.
- *
- * @param map the map to add to, may not be null
- * @param key the key
- * @param value the value
- * @throws NullPointerException if the map is null
- */
- public static void safeAddToMap(Map map, Object key, Object value) throws NullPointerException {
- if (value == null) {
- map.put ( key, "" );
- } else {
- map.put ( key, value );
- }
- }
-
- // Map decorators
- //-----------------------------------------------------------------------
- /**
- * Returns a synchronized map backed by the given map.
- * <p>
- * You must manually synchronize on the returned buffer's iterator to
- * avoid non-deterministic behavior:
- *
- * <pre>
- * Map m = MapUtils.synchronizedMap(myMap);
- * Set s = m.keySet(); // outside synchronized block
- * synchronized (m) { // synchronized on MAP!
- * Iterator i = s.iterator();
- * while (i.hasNext()) {
- * process (i.next());
- * }
- * }
- * </pre>
- *
- * This method uses the implementation in {@link java.util.Collections Collections}.
- *
- * @param map the map to synchronize, must not be null
- * @return a synchronized map backed by the given map
- * @throws IllegalArgumentException if the map is null
- */
- public static Map synchronizedMap(Map map) {
- return Collections.synchronizedMap(map);
- }
-
- /**
- * Returns an unmodifiable map backed by the given map.
- * <p>
- * This method uses the implementation in the decorators subpackage.
- *
- * @param map the map to make unmodifiable, must not be null
- * @return an unmodifiable map backed by the given map
- * @throws IllegalArgumentException if the map is null
- */
- public static Map unmodifiableMap(Map map) {
- return UnmodifiableMap.decorate(map);
- }
-
- /**
- * Returns a predicated (validating) map backed by the given map.
- * <p>
- * Only objects that pass the tests in the given predicates can be added to the map.
- * Trying to add an invalid object results in an IllegalArgumentException.
- * Keys must pass the key predicate, values must pass the value predicate.
- * It is important not to use the original map after invoking this method,
- * as it is a backdoor for adding invalid objects.
- *
- * @param map the map to predicate, must not be null
- * @param keyPred the predicate for keys, null means no check
- * @param valuePred the predicate for values, null means no check
- * @return a predicated map backed by the given map
- * @throws IllegalArgumentException if the Map is null
- */
- public static Map predicatedMap(Map map, Predicate keyPred, Predicate valuePred) {
- return PredicatedMap.decorate(map, keyPred, valuePred);
- }
-
- /**
- * Returns a typed map backed by the given map.
- * <p>
- * Only keys and values of the specified types can be added to the map.
- *
- * @param map the map to limit to a specific type, must not be null
- * @param keyType the type of keys which may be added to the map, must not be null
- * @param valueType the type of values which may be added to the map, must not be null
- * @return a typed map backed by the specified map
- * @throws IllegalArgumentException if the Map or Class is null
- */
- public static Map typedMap(Map map, Class keyType, Class valueType) {
- return TypedMap.decorate(map, keyType, valueType);
- }
-
- /**
- * Returns a transformed map backed by the given map.
- * <p>
- * Each object is passed through the transformers as it is added to the
- * Map. It is important not to use the original map after invoking this
- * method, as it is a backdoor for adding untransformed objects.
- *
- * @param map the map to transform, must not be null
- * @param keyTransformer the transformer for the map keys, null means no transformation
- * @param valueTransformer the transformer for the map values, null means no transformation
- * @return a transformed map backed by the given map
- * @throws IllegalArgumentException if the Map is null
- */
- public static Map transformedMap(Map map, Transformer keyTransformer, Transformer valueTransformer) {
- return TransformedMap.decorate(map, keyTransformer, valueTransformer);
- }
-
- /**
- * Returns a fixed-sized map backed by the given map.
- * Elements may not be added or removed from the returned map, but
- * existing elements can be changed (for instance, via the
- * {@link Map#put(Object,Object)} method).
- *
- * @param map the map whose size to fix, must not be null
- * @return a fixed-size map backed by that map
- * @throws IllegalArgumentException if the Map is null
- */
- public static Map fixedSizeMap(Map map) {
- return FixedSizeMap.decorate(map);
- }
-
- /**
- * Returns a "lazy" map whose values will be created on demand.
- * <p>
- * When the key passed to the returned map's {@link Map#get(Object)}
- * method is not present in the map, then the factory will be used
- * to create a new object and that object will become the value
- * associated with that key.
- * <p>
- * For instance:
- * <pre>
- * Factory factory = new Factory() {
- * public Object create() {
- * return new Date();
- * }
- * }
- * Map lazyMap = MapUtils.lazyMap(new HashMap(), factory);
- * Object obj = lazyMap.get("test");
- * </pre>
- *
- * After the above code is executed, <code>obj</code> will contain
- * a new <code>Date</code> instance. Furthermore, that <code>Date</code>
- * instance is the value for the <code>"test"</code> key in the map.
- *
- * @param map the map to make lazy, must not be null
- * @param factory the factory for creating new objects, must not be null
- * @return a lazy map backed by the given map
- * @throws IllegalArgumentException if the Map or Factory is null
- */
- public static Map lazyMap(Map map, Factory factory) {
- return LazyMap.decorate(map, factory);
- }
-
- /**
- * Returns a "lazy" map whose values will be created on demand.
- * <p>
- * When the key passed to the returned map's {@link Map#get(Object)}
- * method is not present in the map, then the factory will be used
- * to create a new object and that object will become the value
- * associated with that key. The factory is a {@link Transformer}
- * that will be passed the key which it must transform into the value.
- * <p>
- * For instance:
- * <pre>
- * Transformer factory = new Transformer() {
- * public Object transform(Object mapKey) {
- * return new File(mapKey);
- * }
- * }
- * Map lazyMap = MapUtils.lazyMap(new HashMap(), factory);
- * Object obj = lazyMap.get("C:/dev");
- * </pre>
- *
- * After the above code is executed, <code>obj</code> will contain
- * a new <code>File</code> instance for the C drive dev directory.
- * Furthermore, that <code>File</code> instance is the value for the
- * <code>"C:/dev"</code> key in the map.
- * <p>
- * If a lazy map is wrapped by a synchronized map, the result is a simple
- * synchronized cache. When an object is not is the cache, the cache itself
- * calls back to the factory Transformer to populate itself, all within the
- * same synchronized block.
- *
- * @param map the map to make lazy, must not be null
- * @param transformerFactory the factory for creating new objects, must not be null
- * @return a lazy map backed by the given map
- * @throws IllegalArgumentException if the Map or Transformer is null
- */
- public static Map lazyMap(Map map, Transformer transformerFactory) {
- return LazyMap.decorate(map, transformerFactory);
- }
-
- /**
- * Returns a map that maintains the order of keys that are added
- * backed by the given map.
- * <p>
- * If a key is added twice, the order is determined by the first add.
- * The order is observed through the keySet, values and entrySet.
- *
- * @param map the map to order, must not be null
- * @return an ordered map backed by the given map
- * @throws IllegalArgumentException if the Map is null
- */
- public static Map orderedMap(Map map) {
- return ListOrderedMap.decorate(map);
- }
-
- // SortedMap decorators
- //-----------------------------------------------------------------------
- /**
- * Returns a synchronized sorted map backed by the given sorted map.
- * <p>
- * You must manually synchronize on the returned buffer's iterator to
- * avoid non-deterministic behavior:
- *
- * <pre>
- * Map m = MapUtils.synchronizedSortedMap(myMap);
- * Set s = m.keySet(); // outside synchronized block
- * synchronized (m) { // synchronized on MAP!
- * Iterator i = s.iterator();
- * while (i.hasNext()) {
- * process (i.next());
- * }
- * }
- * </pre>
- *
- * This method uses the implementation in {@link java.util.Collections Collections}.
- *
- * @param map the map to synchronize, must not be null
- * @return a synchronized map backed by the given map
- * @throws IllegalArgumentException if the map is null
- */
- public static Map synchronizedSortedMap(SortedMap map) {
- return Collections.synchronizedSortedMap(map);
- }
-
- /**
- * Returns an unmodifiable sorted map backed by the given sorted map.
- * <p>
- * This method uses the implementation in the decorators subpackage.
- *
- * @param map the sorted map to make unmodifiable, must not be null
- * @return an unmodifiable map backed by the given map
- * @throws IllegalArgumentException if the map is null
- */
- public static Map unmodifiableSortedMap(SortedMap map) {
- return UnmodifiableSortedMap.decorate(map);
- }
-
- /**
- * Returns a predicated (validating) sorted map backed by the given map.
- * <p>
- * Only objects that pass the tests in the given predicates can be added to the map.
- * Trying to add an invalid object results in an IllegalArgumentException.
- * Keys must pass the key predicate, values must pass the value predicate.
- * It is important not to use the original map after invoking this method,
- * as it is a backdoor for adding invalid objects.
- *
- * @param map the map to predicate, must not be null
- * @param keyPred the predicate for keys, null means no check
- * @param valuePred the predicate for values, null means no check
- * @return a predicated map backed by the given map
- * @throws IllegalArgumentException if the SortedMap is null
- */
- public static SortedMap predicatedSortedMap(SortedMap map, Predicate keyPred, Predicate valuePred) {
- return PredicatedSortedMap.decorate(map, keyPred, valuePred);
- }
-
- /**
- * Returns a typed sorted map backed by the given map.
- * <p>
- * Only keys and values of the specified types can be added to the map.
- *
- * @param map the map to limit to a specific type, must not be null
- * @param keyType the type of keys which may be added to the map, must not be null
- * @param valueType the type of values which may be added to the map, must not be null
- * @return a typed map backed by the specified map
- */
- public static SortedMap typedSortedMap(SortedMap map, Class keyType, Class valueType) {
- return TypedSortedMap.decorate(map, keyType, valueType);
- }
-
- /**
- * Returns a transformed sorted map backed by the given map.
- * <p>
- * Each object is passed through the transformers as it is added to the
- * Map. It is important not to use the original map after invoking this
- * method, as it is a backdoor for adding untransformed objects.
- *
- * @param map the map to transform, must not be null
- * @param keyTransformer the transformer for the map keys, null means no transformation
- * @param valueTransformer the transformer for the map values, null means no transformation
- * @return a transformed map backed by the given map
- * @throws IllegalArgumentException if the SortedMap is null
- */
- public static SortedMap transformedSortedMap(SortedMap map, Transformer keyTransformer, Transformer valueTransformer) {
- return TransformedSortedMap.decorate(map, keyTransformer, valueTransformer);
- }
-
- /**
- * Returns a fixed-sized sorted map backed by the given sorted map.
- * Elements may not be added or removed from the returned map, but
- * existing elements can be changed (for instance, via the
- * {@link Map#put(Object,Object)} method).
- *
- * @param map the map whose size to fix, must not be null
- * @return a fixed-size map backed by that map
- * @throws IllegalArgumentException if the SortedMap is null
- */
- public static SortedMap fixedSizeSortedMap(SortedMap map) {
- return FixedSizeSortedMap.decorate(map);
- }
-
- /**
- * Returns a "lazy" sorted map whose values will be created on demand.
- * <p>
- * When the key passed to the returned map's {@link Map#get(Object)}
- * method is not present in the map, then the factory will be used
- * to create a new object and that object will become the value
- * associated with that key.
- * <p>
- * For instance:
- *
- * <pre>
- * Factory factory = new Factory() {
- * public Object create() {
- * return new Date();
- * }
- * }
- * SortedMap lazy = MapUtils.lazySortedMap(new TreeMap(), factory);
- * Object obj = lazy.get("test");
- * </pre>
- *
- * After the above code is executed, <code>obj</code> will contain
- * a new <code>Date</code> instance. Furthermore, that <code>Date</code>
- * instance is the value for the <code>"test"</code> key.
- *
- * @param map the map to make lazy, must not be null
- * @param factory the factory for creating new objects, must not be null
- * @return a lazy map backed by the given map
- * @throws IllegalArgumentException if the SortedMap or Factory is null
- */
- public static SortedMap lazySortedMap(SortedMap map, Factory factory) {
- return LazySortedMap.decorate(map, factory);
- }
-
- /**
- * Returns a "lazy" sorted map whose values will be created on demand.
- * <p>
- * When the key passed to the returned map's {@link Map#get(Object)}
- * method is not present in the map, then the factory will be used
- * to create a new object and that object will become the value
- * associated with that key. The factory is a {@link Transformer}
- * that will be passed the key which it must transform into the value.
- * <p>
- * For instance:
- * <pre>
- * Transformer factory = new Transformer() {
- * public Object transform(Object mapKey) {
- * return new File(mapKey);
- * }
- * }
- * SortedMap lazy = MapUtils.lazySortedMap(new TreeMap(), factory);
- * Object obj = lazy.get("C:/dev");
- * </pre>
- *
- * After the above code is executed, <code>obj</code> will contain
- * a new <code>File</code> instance for the C drive dev directory.
- * Furthermore, that <code>File</code> instance is the value for the
- * <code>"C:/dev"</code> key in the map.
- * <p>
- * If a lazy map is wrapped by a synchronized map, the result is a simple
- * synchronized cache. When an object is not is the cache, the cache itself
- * calls back to the factory Transformer to populate itself, all within the
- * same synchronized block.
- *
- * @param map the map to make lazy, must not be null
- * @param transformerFactory the factory for creating new objects, must not be null
- * @return a lazy map backed by the given map
- * @throws IllegalArgumentException if the Map or Transformer is null
- */
- public static SortedMap lazySortedMap(SortedMap map, Transformer transformerFactory) {
- return LazySortedMap.decorate(map, transformerFactory);
- }
-
- }