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 * </p> 037 * <ul> 038 * <li>{@link #unmodifiableMultiValuedMap(MultiValuedMap)}</li> 039 * <li>{@link #transformedMultiValuedMap(MultiValuedMap, Transformer, Transformer)}</li> 040 * </ul> 041 * 042 * @since 4.1 043 */ 044public class MultiMapUtils { 045 046 /** 047 * <code>MultiMapUtils</code> should not normally be instantiated. 048 */ 049 private MultiMapUtils() {} 050 051 /** 052 * An empty {@link UnmodifiableMultiValuedMap}. 053 */ 054 @SuppressWarnings({ "rawtypes", "unchecked" }) 055 public static final MultiValuedMap EMPTY_MULTI_VALUED_MAP = 056 UnmodifiableMultiValuedMap.unmodifiableMultiValuedMap(new ArrayListValuedHashMap(0, 0)); 057 058 /** 059 * Returns immutable EMPTY_MULTI_VALUED_MAP with generic type safety. 060 * 061 * @param <K> the type of key in the map 062 * @param <V> the type of value in the map 063 * @return immutable and empty <code>MultiValuedMap</code> 064 */ 065 @SuppressWarnings("unchecked") 066 public static <K, V> MultiValuedMap<K, V> emptyMultiValuedMap() { 067 return EMPTY_MULTI_VALUED_MAP; 068 } 069 070 // Null safe methods 071 072 /** 073 * Returns an immutable empty <code>MultiValuedMap</code> if the argument is 074 * <code>null</code>, or the argument itself otherwise. 075 * 076 * @param <K> the type of key in the map 077 * @param <V> the type of value in the map 078 * @param map the map, may be null 079 * @return an empty {@link MultiValuedMap} if the argument is null 080 */ 081 @SuppressWarnings("unchecked") 082 public static <K, V> MultiValuedMap<K, V> emptyIfNull(final MultiValuedMap<K, V> map) { 083 return map == null ? EMPTY_MULTI_VALUED_MAP : map; 084 } 085 086 /** 087 * Null-safe check if the specified <code>MultiValuedMap</code> is empty. 088 * <p> 089 * If the provided map is null, returns true. 090 * 091 * @param map the map to check, may be null 092 * @return true if the map is empty or null 093 */ 094 public static boolean isEmpty(final MultiValuedMap<?, ?> map) { 095 return map == null || map.isEmpty(); 096 } 097 098 // Null safe getters 099 // ------------------------------------------------------------------------- 100 101 /** 102 * Gets a Collection from <code>MultiValuedMap</code> in a null-safe manner. 103 * 104 * @param <K> the key type 105 * @param <V> the value type 106 * @param map the {@link MultiValuedMap} to use 107 * @param key the key to look up 108 * @return the Collection in the {@link MultiValuedMap}, or null if input map is null 109 */ 110 public static <K, V> Collection<V> getCollection(final MultiValuedMap<K, V> map, final K key) { 111 if (map != null) { 112 return map.get(key); 113 } 114 return null; 115 } 116 117 // TODO: review the getValuesAsXXX methods - depending on the actual MultiValuedMap type, changes 118 // to the returned collection might update the backing map. This should be clarified and/or prevented. 119 120 /** 121 * Gets a List from <code>MultiValuedMap</code> in a null-safe manner. 122 * 123 * @param <K> the key type 124 * @param <V> the value type 125 * @param map the {@link MultiValuedMap} to use 126 * @param key the key to look up 127 * @return the Collection in the {@link MultiValuedMap} as List, or null if input map is null 128 */ 129 public static <K, V> List<V> getValuesAsList(final MultiValuedMap<K, V> map, final K key) { 130 if (map != null) { 131 final Collection<V> col = map.get(key); 132 if (col instanceof List) { 133 return (List<V>) col; 134 } 135 return new ArrayList<>(col); 136 } 137 return null; 138 } 139 140 /** 141 * Gets a Set from <code>MultiValuedMap</code> in a null-safe manner. 142 * 143 * @param <K> the key type 144 * @param <V> the value type 145 * @param map the {@link MultiValuedMap} to use 146 * @param key the key to look up 147 * @return the Collection in the {@link MultiValuedMap} as Set, or null if input map is null 148 */ 149 public static <K, V> Set<V> getValuesAsSet(final MultiValuedMap<K, V> map, final K key) { 150 if (map != null) { 151 final Collection<V> col = map.get(key); 152 if (col instanceof Set) { 153 return (Set<V>) col; 154 } 155 return new HashSet<>(col); 156 } 157 return null; 158 } 159 160 /** 161 * Gets a Bag from <code>MultiValuedMap</code> in a null-safe manner. 162 * 163 * @param <K> the key type 164 * @param <V> the value type 165 * @param map the {@link MultiValuedMap} to use 166 * @param key the key to look up 167 * @return the Collection in the {@link MultiValuedMap} as Bag, or null if input map is null 168 */ 169 public static <K, V> Bag<V> getValuesAsBag(final MultiValuedMap<K, V> map, final K key) { 170 if (map != null) { 171 final Collection<V> col = map.get(key); 172 if (col instanceof Bag) { 173 return (Bag<V>) col; 174 } 175 return new HashBag<>(col); 176 } 177 return null; 178 } 179 180 // Factory Methods 181 // ----------------------------------------------------------------------- 182 183 /** 184 * Creates a {@link ListValuedMap} with an {@link java.util.ArrayList ArrayList} as 185 * collection class to store the values mapped to a key. 186 * 187 * @param <K> the key type 188 * @param <V> the value type 189 * @return a new <code>ListValuedMap</code> 190 */ 191 public static <K, V> ListValuedMap<K, V> newListValuedHashMap() { 192 return new ArrayListValuedHashMap<>(); 193 } 194 195 /** 196 * Creates a {@link SetValuedMap} with an {@link java.util.HashSet HashSet} as 197 * collection class to store the values mapped to a key. 198 * 199 * @param <K> the key type 200 * @param <V> the value type 201 * @return a new {@link SetValuedMap} 202 */ 203 public static <K, V> SetValuedMap<K, V> newSetValuedHashMap() { 204 return new HashSetValuedHashMap<>(); 205 } 206 207 // MultiValuedMap Decorators 208 // ----------------------------------------------------------------------- 209 210 /** 211 * Returns an <code>UnmodifiableMultiValuedMap</code> backed by the given 212 * map. 213 * 214 * @param <K> the key type 215 * @param <V> the value type 216 * @param map the {@link MultiValuedMap} to decorate, must not be null 217 * @return an unmodifiable {@link MultiValuedMap} backed by the provided map 218 * @throws NullPointerException if map is null 219 */ 220 public static <K, V> MultiValuedMap<K, V> unmodifiableMultiValuedMap( 221 final MultiValuedMap<? extends K, ? extends V> map) { 222 return UnmodifiableMultiValuedMap.<K, V>unmodifiableMultiValuedMap(map); 223 } 224 225 /** 226 * Returns a <code>TransformedMultiValuedMap</code> backed by the given map. 227 * <p> 228 * This method returns a new <code>MultiValuedMap</code> (decorating the 229 * specified map) that will transform any new entries added to it. Existing 230 * entries in the specified map will not be transformed. If you want that 231 * behaviour, see {@link TransformedMultiValuedMap#transformedMap}. 232 * <p> 233 * Each object is passed through the transformers as it is added to the Map. 234 * It is important not to use the original map after invoking this method, 235 * as it is a back door for adding untransformed objects. 236 * <p> 237 * If there are any elements already in the map being decorated, they are 238 * NOT transformed. 239 * 240 * @param <K> the key type 241 * @param <V> the value type 242 * @param map the {@link MultiValuedMap} to transform, must not be null, typically empty 243 * @param keyTransformer the transformer for the map keys, null means no transformation 244 * @param valueTransformer the transformer for the map values, null means no transformation 245 * @return a transformed <code>MultiValuedMap</code> backed by the given map 246 * @throws NullPointerException if map is null 247 */ 248 public static <K, V> MultiValuedMap<K, V> transformedMultiValuedMap(final MultiValuedMap<K, V> map, 249 final Transformer<? super K, ? extends K> keyTransformer, 250 final Transformer<? super V, ? extends V> valueTransformer) { 251 return TransformedMultiValuedMap.transformingMap(map, keyTransformer, valueTransformer); 252 } 253 254}