001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.collections4; 018 019import java.util.ArrayList; 020import java.util.Collection; 021import java.util.HashSet; 022import java.util.List; 023import java.util.Set; 024 025import org.apache.commons.collections4.bag.HashBag; 026import org.apache.commons.collections4.multimap.ArrayListValuedHashMap; 027import org.apache.commons.collections4.multimap.HashSetValuedHashMap; 028import org.apache.commons.collections4.multimap.TransformedMultiValuedMap; 029import org.apache.commons.collections4.multimap.UnmodifiableMultiValuedMap; 030 031/** 032 * Provides utility methods and decorators for {@link MultiValuedMap} instances. 033 * <p> 034 * It contains various type safe and null safe methods. Additionally, it provides 035 * the following decorators: 036 * <ul> 037 * <li>{@link #unmodifiableMultiValuedMap(MultiValuedMap)}</li> 038 * <li>{@link #transformedMultiValuedMap(MultiValuedMap, Transformer, Transformer)}</li> 039 * </ul> 040 * 041 * @since 4.1 042 */ 043public class MultiMapUtils { 044 045 /** 046 * <code>MultiMapUtils</code> should not normally be instantiated. 047 */ 048 private MultiMapUtils() {} 049 050 /** 051 * An empty {@link UnmodifiableMultiValuedMap}. 052 */ 053 @SuppressWarnings({ "rawtypes", "unchecked" }) 054 public static final MultiValuedMap EMPTY_MULTI_VALUED_MAP = 055 UnmodifiableMultiValuedMap.unmodifiableMultiValuedMap(new ArrayListValuedHashMap(0, 0)); 056 057 /** 058 * Returns immutable EMPTY_MULTI_VALUED_MAP with generic type safety. 059 * 060 * @param <K> the type of key in the map 061 * @param <V> the type of value in the map 062 * @return immutable and empty <code>MultiValuedMap</code> 063 */ 064 @SuppressWarnings("unchecked") 065 public static <K, V> MultiValuedMap<K, V> emptyMultiValuedMap() { 066 return EMPTY_MULTI_VALUED_MAP; 067 } 068 069 // Null safe methods 070 071 /** 072 * Returns an immutable empty <code>MultiValuedMap</code> if the argument is 073 * <code>null</code>, or the argument itself otherwise. 074 * 075 * @param <K> the type of key in the map 076 * @param <V> the type of value in the map 077 * @param map the map, may be null 078 * @return an empty {@link MultiValuedMap} if the argument is null 079 */ 080 @SuppressWarnings("unchecked") 081 public static <K, V> MultiValuedMap<K, V> emptyIfNull(final MultiValuedMap<K, V> map) { 082 return map == null ? EMPTY_MULTI_VALUED_MAP : map; 083 } 084 085 /** 086 * Null-safe check if the specified <code>MultiValuedMap</code> is empty. 087 * <p> 088 * If the provided map is null, returns true. 089 * 090 * @param map the map to check, may be null 091 * @return true if the map is empty or null 092 */ 093 public static boolean isEmpty(final MultiValuedMap<?, ?> map) { 094 return map == null || map.isEmpty(); 095 } 096 097 // Null safe getters 098 // ------------------------------------------------------------------------- 099 100 /** 101 * Gets a Collection from <code>MultiValuedMap</code> in a null-safe manner. 102 * 103 * @param <K> the key type 104 * @param <V> the value type 105 * @param map the {@link MultiValuedMap} to use 106 * @param key the key to look up 107 * @return the Collection in the {@link MultiValuedMap}, or null if input map is null 108 */ 109 public static <K, V> Collection<V> getCollection(final MultiValuedMap<K, V> map, final K key) { 110 if (map != null) { 111 return map.get(key); 112 } 113 return null; 114 } 115 116 // TODO: review the getValuesAsXXX methods - depending on the actual MultiValuedMap type, changes 117 // to the returned collection might update the backing map. This should be clarified and/or prevented. 118 119 /** 120 * Gets a List from <code>MultiValuedMap</code> in a null-safe manner. 121 * 122 * @param <K> the key type 123 * @param <V> the value type 124 * @param map the {@link MultiValuedMap} to use 125 * @param key the key to look up 126 * @return the Collection in the {@link MultiValuedMap} as List, or null if input map is null 127 */ 128 public static <K, V> List<V> getValuesAsList(final MultiValuedMap<K, V> map, final K key) { 129 if (map != null) { 130 final Collection<V> col = map.get(key); 131 if (col instanceof List) { 132 return (List<V>) col; 133 } 134 return new ArrayList<>(col); 135 } 136 return null; 137 } 138 139 /** 140 * Gets a Set from <code>MultiValuedMap</code> in a null-safe manner. 141 * 142 * @param <K> the key type 143 * @param <V> the value type 144 * @param map the {@link MultiValuedMap} to use 145 * @param key the key to look up 146 * @return the Collection in the {@link MultiValuedMap} as Set, or null if input map is null 147 */ 148 public static <K, V> Set<V> getValuesAsSet(final MultiValuedMap<K, V> map, final K key) { 149 if (map != null) { 150 final Collection<V> col = map.get(key); 151 if (col instanceof Set) { 152 return (Set<V>) col; 153 } 154 return new HashSet<>(col); 155 } 156 return null; 157 } 158 159 /** 160 * Gets a Bag from <code>MultiValuedMap</code> in a null-safe manner. 161 * 162 * @param <K> the key type 163 * @param <V> the value type 164 * @param map the {@link MultiValuedMap} to use 165 * @param key the key to look up 166 * @return the Collection in the {@link MultiValuedMap} as Bag, or null if input map is null 167 */ 168 public static <K, V> Bag<V> getValuesAsBag(final MultiValuedMap<K, V> map, final K key) { 169 if (map != null) { 170 final Collection<V> col = map.get(key); 171 if (col instanceof Bag) { 172 return (Bag<V>) col; 173 } 174 return new HashBag<>(col); 175 } 176 return null; 177 } 178 179 // Factory Methods 180 // ----------------------------------------------------------------------- 181 182 /** 183 * Creates a {@link ListValuedMap} with an {@link java.util.ArrayList ArrayList} as 184 * collection class to store the values mapped to a key. 185 * 186 * @param <K> the key type 187 * @param <V> the value type 188 * @return a new <code>ListValuedMap</code> 189 */ 190 public static <K, V> ListValuedMap<K, V> newListValuedHashMap() { 191 return new ArrayListValuedHashMap<>(); 192 } 193 194 /** 195 * Creates a {@link SetValuedMap} with an {@link java.util.HashSet HashSet} as 196 * collection class to store the values mapped to a key. 197 * 198 * @param <K> the key type 199 * @param <V> the value type 200 * @return a new {@link SetValuedMap} 201 */ 202 public static <K, V> SetValuedMap<K, V> newSetValuedHashMap() { 203 return new HashSetValuedHashMap<>(); 204 } 205 206 // MultiValuedMap Decorators 207 // ----------------------------------------------------------------------- 208 209 /** 210 * Returns an <code>UnmodifiableMultiValuedMap</code> backed by the given 211 * map. 212 * 213 * @param <K> the key type 214 * @param <V> the value type 215 * @param map the {@link MultiValuedMap} to decorate, must not be null 216 * @return an unmodifiable {@link MultiValuedMap} backed by the provided map 217 * @throws NullPointerException if map is null 218 */ 219 public static <K, V> MultiValuedMap<K, V> unmodifiableMultiValuedMap( 220 final MultiValuedMap<? extends K, ? extends V> map) { 221 return UnmodifiableMultiValuedMap.<K, V>unmodifiableMultiValuedMap(map); 222 } 223 224 /** 225 * Returns a <code>TransformedMultiValuedMap</code> backed by the given map. 226 * <p> 227 * This method returns a new <code>MultiValuedMap</code> (decorating the 228 * specified map) that will transform any new entries added to it. Existing 229 * entries in the specified map will not be transformed. If you want that 230 * behaviour, see {@link TransformedMultiValuedMap#transformedMap}. 231 * <p> 232 * Each object is passed through the transformers as it is added to the Map. 233 * It is important not to use the original map after invoking this method, 234 * as it is a back door for adding untransformed objects. 235 * <p> 236 * If there are any elements already in the map being decorated, they are 237 * NOT transformed. 238 * 239 * @param <K> the key type 240 * @param <V> the value type 241 * @param map the {@link MultiValuedMap} to transform, must not be null, typically empty 242 * @param keyTransformer the transformer for the map keys, null means no transformation 243 * @param valueTransformer the transformer for the map values, null means no transformation 244 * @return a transformed <code>MultiValuedMap</code> backed by the given map 245 * @throws NullPointerException if map is null 246 */ 247 public static <K, V> MultiValuedMap<K, V> transformedMultiValuedMap(final MultiValuedMap<K, V> map, 248 final Transformer<? super K, ? extends K> keyTransformer, 249 final Transformer<? super V, ? extends V> valueTransformer) { 250 return TransformedMultiValuedMap.transformingMap(map, keyTransformer, valueTransformer); 251 } 252 253}