1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.collections4.map;
18
19 import java.io.IOException;
20 import java.io.ObjectInputStream;
21 import java.io.ObjectOutputStream;
22 import java.io.Serializable;
23 import java.util.AbstractCollection;
24 import java.util.ArrayList;
25 import java.util.Collection;
26 import java.util.HashMap;
27 import java.util.Iterator;
28 import java.util.Map;
29 import java.util.Set;
30
31 import org.apache.commons.collections4.CollectionUtils;
32 import org.apache.commons.collections4.Factory;
33 import org.apache.commons.collections4.FunctorException;
34 import org.apache.commons.collections4.MultiMap;
35 import org.apache.commons.collections4.Transformer;
36 import org.apache.commons.collections4.iterators.EmptyIterator;
37 import org.apache.commons.collections4.iterators.IteratorChain;
38 import org.apache.commons.collections4.iterators.LazyIteratorChain;
39 import org.apache.commons.collections4.iterators.TransformIterator;
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71 @Deprecated
72 public class MultiValueMap<K, V> extends AbstractMapDecorator<K, Object> implements MultiMap<K, V>, Serializable {
73
74
75
76
77 private static final class ReflectionFactory<T extends Collection<?>> implements Factory<T>, Serializable {
78
79
80 private static final long serialVersionUID = 2986114157496788874L;
81
82 private final Class<T> clazz;
83
84 ReflectionFactory(final Class<T> clazz) {
85 this.clazz = clazz;
86 }
87
88 @Override
89 public T create() {
90 try {
91 return clazz.getDeclaredConstructor().newInstance();
92 } catch (final Exception ex) {
93 throw new FunctorException("Cannot instantiate class: " + clazz, ex);
94 }
95 }
96
97 private void readObject(final ObjectInputStream is) throws IOException, ClassNotFoundException {
98 is.defaultReadObject();
99
100 if (clazz != null && !Collection.class.isAssignableFrom(clazz)) {
101 throw new UnsupportedOperationException();
102 }
103 }
104 }
105
106
107
108
109 private final class Values extends AbstractCollection<V> {
110 @Override
111 public void clear() {
112 MultiValueMap.this.clear();
113 }
114
115 @Override
116 public Iterator<V> iterator() {
117 final IteratorChain<V> chain = new IteratorChain<>();
118 for (final K k : keySet()) {
119 chain.addIterator(new ValuesIterator(k));
120 }
121 return chain;
122 }
123
124 @Override
125 public int size() {
126 return totalSize();
127 }
128 }
129
130
131
132 private final class ValuesIterator implements Iterator<V> {
133 private final Object key;
134 private final Collection<V> values;
135 private final Iterator<V> iterator;
136
137 ValuesIterator(final Object key) {
138 this.key = key;
139 this.values = getCollection(key);
140 this.iterator = values.iterator();
141 }
142
143 @Override
144 public boolean hasNext() {
145 return iterator.hasNext();
146 }
147
148 @Override
149 public V next() {
150 return iterator.next();
151 }
152
153 @Override
154 public void remove() {
155 iterator.remove();
156 if (values.isEmpty()) {
157 MultiValueMap.this.remove(key);
158 }
159 }
160 }
161
162
163 private static final long serialVersionUID = -2214159910087182007L;
164
165
166
167
168
169
170
171
172
173
174
175
176
177 public static <K, V, C extends Collection<V>> MultiValueMap<K, V> multiValueMap(final Map<K, ? super C> map,
178 final Class<C> collectionClass) {
179 return new MultiValueMap<>(map, new ReflectionFactory<>(collectionClass));
180 }
181
182
183
184
185
186
187
188
189
190
191
192
193
194 public static <K, V, C extends Collection<V>> MultiValueMap<K, V> multiValueMap(final Map<K, ? super C> map,
195 final Factory<C> collectionFactory) {
196 return new MultiValueMap<>(map, collectionFactory);
197 }
198
199
200
201
202
203
204
205
206
207
208
209 @SuppressWarnings({ "unchecked", "rawtypes" })
210 public static <K, V> MultiValueMap<K, V> multiValueMap(final Map<K, ? super Collection<V>> map) {
211 return MultiValueMap.<K, V, ArrayList>multiValueMap((Map<K, ? super Collection>) map, ArrayList.class);
212 }
213
214
215 private final Factory<? extends Collection<V>> collectionFactory;
216
217
218 private transient Collection<V> valuesView;
219
220
221
222
223
224 @SuppressWarnings({ "unchecked", "rawtypes" })
225 public MultiValueMap() {
226 this(new HashMap<>(), new ReflectionFactory(ArrayList.class));
227 }
228
229
230
231
232
233
234
235
236
237 @SuppressWarnings("unchecked")
238 protected <C extends Collection<V>> MultiValueMap(final Map<K, ? super C> map,
239 final Factory<C> collectionFactory) {
240 super((Map<K, Object>) map);
241 if (collectionFactory == null) {
242 throw new IllegalArgumentException("The factory must not be null");
243 }
244 this.collectionFactory = collectionFactory;
245 }
246
247
248
249
250 @Override
251 public void clear() {
252
253
254
255
256
257
258
259
260 decorated().clear();
261 }
262
263
264
265
266
267
268
269
270
271 @Override
272 @SuppressWarnings("unchecked")
273 public boolean containsValue(final Object value) {
274 final Set<Map.Entry<K, Object>> pairs = decorated().entrySet();
275 if (pairs != null) {
276 for (final Map.Entry<K, Object> entry : pairs) {
277 if (((Collection<V>) entry.getValue()).contains(value)) {
278 return true;
279 }
280 }
281 }
282 return false;
283 }
284
285
286
287
288
289
290
291
292 public boolean containsValue(final Object key, final Object value) {
293 final Collection<V> coll = getCollection(key);
294 if (coll == null) {
295 return false;
296 }
297 return coll.contains(value);
298 }
299
300
301
302
303
304
305
306
307
308
309
310 protected Collection<V> createCollection(final int size) {
311 return collectionFactory.create();
312 }
313
314
315
316
317
318
319
320
321
322
323 @Override
324 public Set<Entry<K, Object>> entrySet() {
325 return super.entrySet();
326 }
327
328
329
330
331
332
333
334
335 @SuppressWarnings("unchecked")
336 public Collection<V> getCollection(final Object key) {
337 return (Collection<V>) decorated().get(key);
338 }
339
340
341
342
343
344
345
346
347
348
349
350
351
352 public Iterator<Entry<K, V>> iterator() {
353 final Collection<K> allKeys = new ArrayList<>(keySet());
354 final Iterator<K> keyIterator = allKeys.iterator();
355
356 return new LazyIteratorChain<Entry<K, V>>() {
357 @Override
358 protected Iterator<? extends Entry<K, V>> nextIterator(final int count) {
359 if ( ! keyIterator.hasNext() ) {
360 return null;
361 }
362 final K key = keyIterator.next();
363 final Transformer<V, Entry<K, V>> transformer = input -> new Entry<K, V>() {
364 @Override
365 public K getKey() {
366 return key;
367 }
368 @Override
369 public V getValue() {
370 return input;
371 }
372 @Override
373 public V setValue(final V value) {
374 throw new UnsupportedOperationException();
375 }
376 };
377 return new TransformIterator<>(new ValuesIterator(key), transformer);
378 }
379 };
380 }
381
382
383
384
385
386
387
388 public Iterator<V> iterator(final Object key) {
389 if (!containsKey(key)) {
390 return EmptyIterator.<V>emptyIterator();
391 }
392 return new ValuesIterator(key);
393 }
394
395
396
397
398
399
400
401
402
403
404
405 @Override
406 @SuppressWarnings("unchecked")
407 public Object put(final K key, final Object value) {
408 boolean result = false;
409 Collection<V> coll = getCollection(key);
410 if (coll == null) {
411 coll = createCollection(1);
412 coll.add((V) value);
413 if (!coll.isEmpty()) {
414
415 decorated().put(key, coll);
416 result = true;
417 }
418 } else {
419 result = coll.add((V) value);
420 }
421 return result ? value : null;
422 }
423
424
425
426
427
428
429
430
431
432 public boolean putAll(final K key, final Collection<V> values) {
433 if (values == null || values.isEmpty()) {
434 return false;
435 }
436 boolean result = false;
437 Collection<V> coll = getCollection(key);
438 if (coll == null) {
439 coll = createCollection(values.size());
440 coll.addAll(values);
441 if (!coll.isEmpty()) {
442
443 decorated().put(key, coll);
444 result = true;
445 }
446 } else {
447 result = coll.addAll(values);
448 }
449 return result;
450 }
451
452
453
454
455
456
457
458
459
460
461
462
463 @Override
464 @SuppressWarnings("unchecked")
465 public void putAll(final Map<? extends K, ?> map) {
466 if (map instanceof MultiMap) {
467 for (final Map.Entry<? extends K, Object> entry : ((MultiMap<? extends K, V>) map).entrySet()) {
468 putAll(entry.getKey(), (Collection<V>) entry.getValue());
469 }
470 } else {
471 for (final Map.Entry<? extends K, ?> entry : map.entrySet()) {
472 put(entry.getKey(), entry.getValue());
473 }
474 }
475 }
476
477
478
479
480
481
482
483
484
485 @SuppressWarnings("unchecked")
486 private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
487 in.defaultReadObject();
488 map = (Map<K, Object>) in.readObject();
489 }
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504 @Override
505 public boolean removeMapping(final Object key, final Object value) {
506 final Collection<V> valuesForKey = getCollection(key);
507 if (valuesForKey == null) {
508 return false;
509 }
510 final boolean removed = valuesForKey.remove(value);
511 if (!removed) {
512 return false;
513 }
514 if (valuesForKey.isEmpty()) {
515 remove(key);
516 }
517 return true;
518 }
519
520
521
522
523
524
525
526 public int size(final Object key) {
527 final Collection<V> coll = getCollection(key);
528 if (coll == null) {
529 return 0;
530 }
531 return coll.size();
532 }
533
534
535
536
537
538
539 public int totalSize() {
540 int total = 0;
541 for (final Object v : decorated().values()) {
542 total += CollectionUtils.size(v);
543 }
544 return total;
545 }
546
547
548
549
550
551
552
553
554 @Override
555 @SuppressWarnings("unchecked")
556 public Collection<Object> values() {
557 final Collection<V> vs = valuesView;
558 return (Collection<Object>) (vs != null ? vs : (valuesView = new Values()));
559 }
560
561
562
563
564
565
566
567
568 private void writeObject(final ObjectOutputStream out) throws IOException {
569 out.defaultWriteObject();
570 out.writeObject(map);
571 }
572
573 }