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 * https://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 */ 017 018package org.apache.commons.collections4; 019 020import java.util.ArrayList; 021import java.util.Collection; 022import java.util.HashSet; 023import java.util.List; 024import java.util.Set; 025 026import org.apache.commons.collections4.bag.HashBag; 027import org.apache.commons.collections4.multimap.ArrayListValuedHashMap; 028import org.apache.commons.collections4.multimap.HashSetValuedHashMap; 029import org.apache.commons.collections4.multimap.TransformedMultiValuedMap; 030import org.apache.commons.collections4.multimap.UnmodifiableMultiValuedMap; 031import org.apache.commons.collections4.multiset.HashMultiSet; 032 033/** 034 * Provides utility methods and decorators for {@link MultiValuedMap} instances. 035 * <p> 036 * It contains various type safe and null safe methods. Additionally, it provides the following decorators: 037 * </p> 038 * <ul> 039 * <li>{@link #unmodifiableMultiValuedMap(MultiValuedMap)}</li> 040 * <li>{@link #transformedMultiValuedMap(MultiValuedMap, Transformer, Transformer)}</li> 041 * </ul> 042 * 043 * @since 4.1 044 */ 045public class MultiMapUtils { 046 047 /** 048 * An empty {@link UnmodifiableMultiValuedMap}. 049 */ 050 @SuppressWarnings({ "rawtypes" }) 051 public static final MultiValuedMap EMPTY_MULTI_VALUED_MAP = UnmodifiableMultiValuedMap.unmodifiableMultiValuedMap(new ArrayListValuedHashMap(0, 0)); 052 053 /** 054 * Returns an immutable empty {@code MultiValuedMap} if the argument is {@code null}, or the argument itself otherwise. 055 * 056 * @param <K> The type of key in the map. 057 * @param <V> The type of value in the map. 058 * @param map The map, may be null. 059 * @return An empty {@link MultiValuedMap} if the argument is null. 060 */ 061 @SuppressWarnings("unchecked") 062 public static <K, V> MultiValuedMap<K, V> emptyIfNull(final MultiValuedMap<K, V> map) { 063 return map == null ? EMPTY_MULTI_VALUED_MAP : map; 064 } 065 066 /** 067 * Returns immutable EMPTY_MULTI_VALUED_MAP with generic type safety. 068 * 069 * @param <K> The type of key in the map. 070 * @param <V> The type of value in the map. 071 * @return immutable and empty {@code MultiValuedMap}. 072 */ 073 @SuppressWarnings("unchecked") 074 public static <K, V> MultiValuedMap<K, V> emptyMultiValuedMap() { 075 return EMPTY_MULTI_VALUED_MAP; 076 } 077 // Null safe methods 078 079 /** 080 * Gets a Collection from {@code MultiValuedMap} in a null-safe manner. 081 * 082 * @param <K> The key type. 083 * @param <V> The value type. 084 * @param map The {@link MultiValuedMap} to use. 085 * @param key The key to look up. 086 * @return The Collection in the {@link MultiValuedMap}, or null if input map is null. 087 */ 088 public static <K, V> Collection<V> getCollection(final MultiValuedMap<K, V> map, final K key) { 089 return map != null ? map.get(key) : null; 090 } 091 092 /** 093 * Gets a Bag from {@code MultiValuedMap} in a null-safe manner. 094 * 095 * @param <K> The key type. 096 * @param <V> The value type. 097 * @param map The {@link MultiValuedMap} to use. 098 * @param key The key to look up. 099 * @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}