View Javadoc
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    *      https://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  
18  package org.apache.commons.collections4;
19  
20  import java.util.ArrayList;
21  import java.util.Collection;
22  import java.util.HashSet;
23  import java.util.List;
24  import java.util.Set;
25  
26  import org.apache.commons.collections4.bag.HashBag;
27  import org.apache.commons.collections4.multimap.ArrayListValuedHashMap;
28  import org.apache.commons.collections4.multimap.HashSetValuedHashMap;
29  import org.apache.commons.collections4.multimap.TransformedMultiValuedMap;
30  import org.apache.commons.collections4.multimap.UnmodifiableMultiValuedMap;
31  import org.apache.commons.collections4.multiset.HashMultiSet;
32  
33  /**
34   * Provides utility methods and decorators for {@link MultiValuedMap} instances.
35   * <p>
36   * It contains various type safe and null safe methods. Additionally, it provides the following decorators:
37   * </p>
38   * <ul>
39   * <li>{@link #unmodifiableMultiValuedMap(MultiValuedMap)}</li>
40   * <li>{@link #transformedMultiValuedMap(MultiValuedMap, Transformer, Transformer)}</li>
41   * </ul>
42   *
43   * @since 4.1
44   */
45  public class MultiMapUtils {
46  
47      /**
48       * An empty {@link UnmodifiableMultiValuedMap}.
49       */
50      @SuppressWarnings({ "rawtypes" })
51      public static final MultiValuedMap EMPTY_MULTI_VALUED_MAP = UnmodifiableMultiValuedMap.unmodifiableMultiValuedMap(new ArrayListValuedHashMap(0, 0));
52  
53      /**
54       * Returns an immutable empty {@code MultiValuedMap} if the argument is {@code null}, or the argument itself otherwise.
55       *
56       * @param <K> The type of key in the map.
57       * @param <V> The type of value in the map.
58       * @param map The map, may be null.
59       * @return An empty {@link MultiValuedMap} if the argument is null.
60       */
61      @SuppressWarnings("unchecked")
62      public static <K, V> MultiValuedMap<K, V> emptyIfNull(final MultiValuedMap<K, V> map) {
63          return map == null ? EMPTY_MULTI_VALUED_MAP : map;
64      }
65  
66      /**
67       * Returns immutable EMPTY_MULTI_VALUED_MAP with generic type safety.
68       *
69       * @param <K> The type of key in the map.
70       * @param <V> The type of value in the map.
71       * @return immutable and empty {@code MultiValuedMap}.
72       */
73      @SuppressWarnings("unchecked")
74      public static <K, V> MultiValuedMap<K, V> emptyMultiValuedMap() {
75          return EMPTY_MULTI_VALUED_MAP;
76      }
77      // Null safe methods
78  
79      /**
80       * Gets a Collection from {@code MultiValuedMap} in a null-safe manner.
81       *
82       * @param <K> The key type.
83       * @param <V> The value type.
84       * @param map The {@link MultiValuedMap} to use.
85       * @param key The key to look up.
86       * @return The Collection in the {@link MultiValuedMap}, or null if input map is null.
87       */
88      public static <K, V> Collection<V> getCollection(final MultiValuedMap<K, V> map, final K key) {
89          return map != null ? map.get(key) : null;
90      }
91  
92      /**
93       * Gets a Bag from {@code MultiValuedMap} in a null-safe manner.
94       *
95       * @param <K> The key type.
96       * @param <V> The value type.
97       * @param map The {@link MultiValuedMap} to use.
98       * @param key The key to look up.
99       * @return A new Bag containing the values from the {@link MultiValuedMap}, or null if input map is null.
100      * @deprecated Since 4.6.0, use {@link #getValuesAsMultiSet(MultiValuedMap, Object)} instead.
101      */
102     @Deprecated
103     public static <K, V> Bag<V> getValuesAsBag(final MultiValuedMap<K, V> map, final K key) {
104         return map != null ? new HashBag<>(map.get(key)) : null;
105     }
106 
107     /**
108      * Gets a List from {@code MultiValuedMap} in a null-safe manner.
109      *
110      * @param <K> The key type.
111      * @param <V> The value type.
112      * @param map The {@link MultiValuedMap} to use.
113      * @param key The key to look up.
114      * @return A new List containing the values from the {@link MultiValuedMap}, or null if input map is null.
115      */
116     public static <K, V> List<V> getValuesAsList(final MultiValuedMap<K, V> map, final K key) {
117         return map != null ? new ArrayList<>(map.get(key)) : null;
118     }
119 
120     /**
121      * Gets a MultiSet from {@code MultiValuedMap} 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 A new MultiSet containing the values from the {@link MultiValuedMap}, or null if input map is null.
128      * @since 4.6.0
129      */
130     public static <K, V> MultiSet<V> getValuesAsMultiSet(final MultiValuedMap<K, V> map, final K key) {
131         return map != null ? new HashMultiSet<>(map.get(key)) : null;
132     }
133 
134     /**
135      * Gets a Set from {@code MultiValuedMap} in a null-safe manner.
136      *
137      * @param <K> The key type.
138      * @param <V> The value type.
139      * @param map The {@link MultiValuedMap} to use.
140      * @param key The key to look up.
141      * @return A new Set containing the values from the {@link MultiValuedMap}, or null if input map is null.
142      */
143     public static <K, V> Set<V> getValuesAsSet(final MultiValuedMap<K, V> map, final K key) {
144         return map != null ? new HashSet<>(map.get(key)) : null;
145     }
146 
147     /**
148      * Inverts the mappings from an input MultiValuedMap by adding entries to an output MultiValuedMap. The input is unchanged.
149      * <p>
150      * Use this method to have complete control of the output MultiValuedMap or when merging several inverse mappings. In simple cases, consider using
151      * {@link MultiValuedMap#inverted()} method.
152      * </p>
153      *
154      * @param <K>    the input <em>value</em> type and output <em>key</em> type.
155      * @param <V>    the input <em>key</em> type and output <em>value</em> type.
156      * @param <M>    the output MultiValuedMap type where {@code K} is the <em>key</em> type and {@code V} is the <em>value</em> type.
157      * @param input  The input key-value mappings of type {@code <V, K>}.
158      * @param output The output value-key mappings of type {@code <K, V>}.
159      * @return The updated output MultiValuedMap of type {@code <K, V>}
160      * @see MultiValuedMap#inverted()
161      * @since 4.6.0
162      */
163     public static <K, V, M extends MultiValuedMap<K, V>> M invert(final MultiValuedMap<? extends V, ? extends K> input, final M output) {
164         input.entries().forEach(e -> output.put(e.getValue(), e.getKey()));
165         return output;
166     }
167 
168     /**
169      * Null-safe check if the specified {@code MultiValuedMap} is empty.
170      * <p>
171      * If the provided map is null, returns true.
172      * </p>
173      *
174      * @param map The map to check, may be null.
175      * @return true if the map is empty or null.
176      */
177     public static boolean isEmpty(final MultiValuedMap<?, ?> map) {
178         return map == null || map.isEmpty();
179     }
180 
181     /**
182      * Creates a {@link ListValuedMap} with an {@link ArrayList ArrayList} as collection class to store the values mapped to a key.
183      *
184      * @param <K> The key type.
185      * @param <V> The value type.
186      * @return A new {@code ListValuedMap}.
187      */
188     public static <K, V> ListValuedMap<K, V> newListValuedHashMap() {
189         return new ArrayListValuedHashMap<>();
190     }
191 
192     /**
193      * Creates a {@link SetValuedMap} with an {@link HashSet HashSet} as collection class to store the values mapped to a key.
194      *
195      * @param <K> The key type.
196      * @param <V> The value type.
197      * @return A new {@link SetValuedMap}.
198      */
199     public static <K, V> SetValuedMap<K, V> newSetValuedHashMap() {
200         return new HashSetValuedHashMap<>();
201     }
202 
203     /**
204      * Returns a {@code TransformedMultiValuedMap} backed by the given map.
205      * <p>
206      * This method returns a new {@code MultiValuedMap} (decorating the specified map) that will transform any new entries added to it. Existing entries in the
207      * specified map will not be transformed. If you want that behavior, see {@link TransformedMultiValuedMap#transformedMap}.
208      * </p>
209      * <p>
210      * 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
211      * is a back door for adding untransformed objects.
212      * </p>
213      * <p>
214      * If there are any elements already in the map being decorated, they are NOT transformed.
215      * </p>
216      *
217      * @param <K>              the key type.
218      * @param <V>              the value type.
219      * @param map              The {@link MultiValuedMap} to transform, must not be null, typically empty.
220      * @param keyTransformer   The transformer for the map keys, null means no transformation.
221      * @param valueTransformer The transformer for the map values, null means no transformation.
222      * @return A transformed {@code MultiValuedMap} backed by the given map.
223      * @throws NullPointerException if map is null.
224      */
225     public static <K, V> MultiValuedMap<K, V> transformedMultiValuedMap(final MultiValuedMap<K, V> map,
226             final Transformer<? super K, ? extends K> keyTransformer, final Transformer<? super V, ? extends V> valueTransformer) {
227         return TransformedMultiValuedMap.transformingMap(map, keyTransformer, valueTransformer);
228     }
229 
230     /**
231      * Returns an {@code UnmodifiableMultiValuedMap} backed by the given 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(final MultiValuedMap<? extends K, ? extends V> map) {
240         return UnmodifiableMultiValuedMap.<K, V>unmodifiableMultiValuedMap(map);
241     }
242 
243     /**
244      * Don't allow instances.
245      */
246     private MultiMapUtils() {
247         // empty
248     }
249 }