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.collections4;
18
19 import java.util.ArrayList;
20 import java.util.Collection;
21 import java.util.HashSet;
22 import java.util.List;
23 import java.util.Set;
24
25 import org.apache.commons.collections4.bag.HashBag;
26 import org.apache.commons.collections4.multimap.ArrayListValuedHashMap;
27 import org.apache.commons.collections4.multimap.HashSetValuedHashMap;
28 import org.apache.commons.collections4.multimap.TransformedMultiValuedMap;
29 import org.apache.commons.collections4.multimap.UnmodifiableMultiValuedMap;
30
31 /**
32 * Provides utility methods and decorators for {@link MultiValuedMap} instances.
33 * <p>
34 * It contains various type safe and null safe methods. Additionally, it provides
35 * the following decorators:
36 * </p>
37 * <ul>
38 * <li>{@link #unmodifiableMultiValuedMap(MultiValuedMap)}</li>
39 * <li>{@link #transformedMultiValuedMap(MultiValuedMap, Transformer, Transformer)}</li>
40 * </ul>
41 *
42 * @since 4.1
43 */
44 public class MultiMapUtils {
45
46 /**
47 * An empty {@link UnmodifiableMultiValuedMap}.
48 */
49 @SuppressWarnings({ "rawtypes", "unchecked" })
50 public static final MultiValuedMap EMPTY_MULTI_VALUED_MAP =
51 UnmodifiableMultiValuedMap.unmodifiableMultiValuedMap(new ArrayListValuedHashMap(0, 0));
52
53 /**
54 * Returns an immutable empty {@code MultiValuedMap} if the argument is
55 * {@code null}, or the argument itself otherwise.
56 *
57 * @param <K> the type of key in the map
58 * @param <V> the type of value in the map
59 * @param map the map, may be null
60 * @return an empty {@link MultiValuedMap} if the argument is null
61 */
62 @SuppressWarnings("unchecked")
63 public static <K, V> MultiValuedMap<K, V> emptyIfNull(final MultiValuedMap<K, V> map) {
64 return map == null ? EMPTY_MULTI_VALUED_MAP : map;
65 }
66
67 /**
68 * Returns immutable EMPTY_MULTI_VALUED_MAP with generic type safety.
69 *
70 * @param <K> the type of key in the map
71 * @param <V> the type of value in the map
72 * @return immutable and empty {@code MultiValuedMap}
73 */
74 @SuppressWarnings("unchecked")
75 public static <K, V> MultiValuedMap<K, V> emptyMultiValuedMap() {
76 return EMPTY_MULTI_VALUED_MAP;
77 }
78
79 // Null safe methods
80
81 /**
82 * Gets a Collection from {@code MultiValuedMap} in a null-safe manner.
83 *
84 * @param <K> the key type
85 * @param <V> the value type
86 * @param map the {@link MultiValuedMap} to use
87 * @param key the key to look up
88 * @return the Collection in the {@link MultiValuedMap}, or null if input map is null
89 */
90 public static <K, V> Collection<V> getCollection(final MultiValuedMap<K, V> map, final K key) {
91 if (map != null) {
92 return map.get(key);
93 }
94 return null;
95 }
96
97 /**
98 * Gets a Bag from {@code MultiValuedMap} in a null-safe manner.
99 *
100 * @param <K> the key type
101 * @param <V> the value type
102 * @param map the {@link MultiValuedMap} to use
103 * @param key the key to look up
104 * @return the Collection in the {@link MultiValuedMap} as Bag, or null if input map is null
105 */
106 public static <K, V> Bag<V> getValuesAsBag(final MultiValuedMap<K, V> map, final K key) {
107 if (map != null) {
108 final Collection<V> col = map.get(key);
109 if (col instanceof Bag) {
110 return (Bag<V>) col;
111 }
112 return new HashBag<>(col);
113 }
114 return null;
115 }
116
117 /**
118 * Gets a List from {@code MultiValuedMap} in a null-safe manner.
119 *
120 * @param <K> the key type
121 * @param <V> the value type
122 * @param map the {@link MultiValuedMap} to use
123 * @param key the key to look up
124 * @return the Collection in the {@link MultiValuedMap} as List, or null if input map is null
125 */
126 public static <K, V> List<V> getValuesAsList(final MultiValuedMap<K, V> map, final K key) {
127 if (map != null) {
128 final Collection<V> col = map.get(key);
129 if (col instanceof List) {
130 return (List<V>) col;
131 }
132 return new ArrayList<>(col);
133 }
134 return null;
135 }
136
137 // TODO: review the getValuesAsXXX methods - depending on the actual MultiValuedMap type, changes
138 // to the returned collection might update the backing map. This should be clarified and/or prevented.
139
140 /**
141 * Gets a Set from {@code MultiValuedMap} 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 * Null-safe check if the specified {@code MultiValuedMap} is empty.
162 * <p>
163 * If the provided map is null, returns true.
164 * </p>
165 *
166 * @param map the map to check, may be null
167 * @return true if the map is empty or null
168 */
169 public static boolean isEmpty(final MultiValuedMap<?, ?> map) {
170 return map == null || map.isEmpty();
171 }
172
173 /**
174 * Creates a {@link ListValuedMap} with an {@link java.util.ArrayList ArrayList} as
175 * collection class to store the values mapped to a key.
176 *
177 * @param <K> the key type
178 * @param <V> the value type
179 * @return a new {@code ListValuedMap}
180 */
181 public static <K, V> ListValuedMap<K, V> newListValuedHashMap() {
182 return new ArrayListValuedHashMap<>();
183 }
184
185 /**
186 * Creates a {@link SetValuedMap} with an {@link java.util.HashSet HashSet} as
187 * collection class to store the values mapped to a key.
188 *
189 * @param <K> the key type
190 * @param <V> the value type
191 * @return a new {@link SetValuedMap}
192 */
193 public static <K, V> SetValuedMap<K, V> newSetValuedHashMap() {
194 return new HashSetValuedHashMap<>();
195 }
196
197 /**
198 * Returns a {@code TransformedMultiValuedMap} backed by the given map.
199 * <p>
200 * This method returns a new {@code MultiValuedMap} (decorating the
201 * specified map) that will transform any new entries added to it. Existing
202 * entries in the specified map will not be transformed. If you want that
203 * behavior, see {@link TransformedMultiValuedMap#transformedMap}.
204 * </p>
205 * <p>
206 * Each object is passed through the transformers as it is added to the Map.
207 * It is important not to use the original map after invoking this method,
208 * as it is a back door for adding untransformed objects.
209 * </p>
210 * <p>
211 * If there are any elements already in the map being decorated, they are
212 * NOT transformed.
213 * </p>
214 *
215 * @param <K> the key type
216 * @param <V> the value type
217 * @param map the {@link MultiValuedMap} to transform, must not be null, typically empty
218 * @param keyTransformer the transformer for the map keys, null means no transformation
219 * @param valueTransformer the transformer for the map values, null means no transformation
220 * @return a transformed {@code MultiValuedMap} backed by the given map
221 * @throws NullPointerException if map is null
222 */
223 public static <K, V> MultiValuedMap<K, V> transformedMultiValuedMap(final MultiValuedMap<K, V> map,
224 final Transformer<? super K, ? extends K> keyTransformer,
225 final Transformer<? super V, ? extends V> valueTransformer) {
226 return TransformedMultiValuedMap.transformingMap(map, keyTransformer, valueTransformer);
227 }
228
229 /**
230 * Returns an {@code UnmodifiableMultiValuedMap} backed by the given
231 * map.
232 *
233 * @param <K> the key type
234 * @param <V> the value type
235 * @param map the {@link MultiValuedMap} to decorate, must not be null
236 * @return an unmodifiable {@link MultiValuedMap} backed by the provided map
237 * @throws NullPointerException if map is null
238 */
239 public static <K, V> MultiValuedMap<K, V> unmodifiableMultiValuedMap(
240 final MultiValuedMap<? extends K, ? extends V> map) {
241 return UnmodifiableMultiValuedMap.<K, V>unmodifiableMultiValuedMap(map);
242 }
243
244 /**
245 * Don't allow instances.
246 */
247 private MultiMapUtils() {
248 // empty
249 }
250
251 }