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.Serializable;
20 import java.util.AbstractSet;
21 import java.util.Collection;
22 import java.util.Collections;
23 import java.util.Iterator;
24 import java.util.Map;
25 import java.util.NoSuchElementException;
26 import java.util.Set;
27
28 import org.apache.commons.collections4.BoundedMap;
29 import org.apache.commons.collections4.KeyValue;
30 import org.apache.commons.collections4.OrderedMap;
31 import org.apache.commons.collections4.OrderedMapIterator;
32 import org.apache.commons.collections4.ResettableIterator;
33 import org.apache.commons.collections4.iterators.SingletonIterator;
34 import org.apache.commons.collections4.keyvalue.TiedMapEntry;
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63 public class SingletonMap<K, V>
64 implements OrderedMap<K, V>, BoundedMap<K, V>, KeyValue<K, V>, Serializable, Cloneable {
65
66
67 private static final long serialVersionUID = -8931271118676803261L;
68
69
70 private final K key;
71
72 private V value;
73
74
75
76
77 public SingletonMap() {
78 super();
79 this.key = null;
80 }
81
82
83
84
85
86
87
88 public SingletonMap(final K key, final V value) {
89 super();
90 this.key = key;
91 this.value = value;
92 }
93
94
95
96
97
98
99 public SingletonMap(final KeyValue<K, V> keyValue) {
100 super();
101 this.key = keyValue.getKey();
102 this.value = keyValue.getValue();
103 }
104
105
106
107
108
109
110 public SingletonMap(final Map.Entry<? extends K, ? extends V> mapEntry) {
111 super();
112 this.key = mapEntry.getKey();
113 this.value = mapEntry.getValue();
114 }
115
116
117
118
119
120
121
122
123 public SingletonMap(final Map<? extends K, ? extends V> map) {
124 super();
125 if (map.size() != 1) {
126 throw new IllegalArgumentException("The map size must be 1");
127 }
128 final Map.Entry<? extends K, ? extends V> entry = map.entrySet().iterator().next();
129 this.key = entry.getKey();
130 this.value = entry.getValue();
131 }
132
133
134
135
136
137
138
139
140 @Override
141 public K getKey() {
142 return key;
143 }
144
145
146
147
148
149
150 @Override
151 public V getValue() {
152 return value;
153 }
154
155
156
157
158
159
160
161 public V setValue(final V value) {
162 final V old = this.value;
163 this.value = value;
164 return old;
165 }
166
167
168
169
170
171
172
173
174 @Override
175 public boolean isFull() {
176 return true;
177 }
178
179
180
181
182
183
184 @Override
185 public int maxSize() {
186 return 1;
187 }
188
189
190
191
192
193
194
195
196
197 @Override
198 public V get(final Object key) {
199 if (isEqualKey(key)) {
200 return value;
201 }
202 return null;
203 }
204
205
206
207
208
209
210 @Override
211 public int size() {
212 return 1;
213 }
214
215
216
217
218
219
220 @Override
221 public boolean isEmpty() {
222 return false;
223 }
224
225
226
227
228
229
230
231
232 @Override
233 public boolean containsKey(final Object key) {
234 return isEqualKey(key);
235 }
236
237
238
239
240
241
242
243 @Override
244 public boolean containsValue(final Object value) {
245 return isEqualValue(value);
246 }
247
248
249
250
251
252
253
254
255
256
257
258
259
260 @Override
261 public V put(final K key, final V value) {
262 if (isEqualKey(key)) {
263 return setValue(value);
264 }
265 throw new IllegalArgumentException("Cannot put new key/value pair - Map is fixed size singleton");
266 }
267
268
269
270
271
272
273
274
275
276
277
278
279 @Override
280 public void putAll(final Map<? extends K, ? extends V> map) {
281 switch (map.size()) {
282 case 0:
283 return;
284
285 case 1:
286 final Map.Entry<? extends K, ? extends V> entry = map.entrySet().iterator().next();
287 put(entry.getKey(), entry.getValue());
288 return;
289
290 default:
291 throw new IllegalArgumentException("The map size must be 0 or 1");
292 }
293 }
294
295
296
297
298
299
300
301
302 @Override
303 public V remove(final Object key) {
304 throw new UnsupportedOperationException();
305 }
306
307
308
309
310 @Override
311 public void clear() {
312 throw new UnsupportedOperationException();
313 }
314
315
316
317
318
319
320
321
322
323 @Override
324 public Set<Map.Entry<K, V>> entrySet() {
325 final Map.Entry<K, V> entry = new TiedMapEntry<>(this, getKey());
326 return Collections.singleton(entry);
327 }
328
329
330
331
332
333
334
335
336 @Override
337 public Set<K> keySet() {
338 return Collections.singleton(key);
339 }
340
341
342
343
344
345
346
347
348 @Override
349 public Collection<V> values() {
350 return new SingletonValues<>(this);
351 }
352
353
354
355
356 @Override
357 public OrderedMapIterator<K, V> mapIterator() {
358 return new SingletonMapIterator<>(this);
359 }
360
361
362
363
364
365
366 @Override
367 public K firstKey() {
368 return getKey();
369 }
370
371
372
373
374
375
376 @Override
377 public K lastKey() {
378 return getKey();
379 }
380
381
382
383
384
385
386
387 @Override
388 public K nextKey(final K key) {
389 return null;
390 }
391
392
393
394
395
396
397
398 @Override
399 public K previousKey(final K key) {
400 return null;
401 }
402
403
404
405
406
407
408
409
410 protected boolean isEqualKey(final Object key) {
411 return key == null ? getKey() == null : key.equals(getKey());
412 }
413
414
415
416
417
418
419
420 protected boolean isEqualValue(final Object value) {
421 return value == null ? getValue() == null : value.equals(getValue());
422 }
423
424
425
426
427
428 static class SingletonMapIterator<K, V> implements OrderedMapIterator<K, V>, ResettableIterator<K> {
429 private final SingletonMap<K, V> parent;
430 private boolean hasNext = true;
431 private boolean canGetSet = false;
432
433 SingletonMapIterator(final SingletonMap<K, V> parent) {
434 super();
435 this.parent = parent;
436 }
437
438 @Override
439 public boolean hasNext() {
440 return hasNext;
441 }
442
443 @Override
444 public K next() {
445 if (hasNext == false) {
446 throw new NoSuchElementException(AbstractHashedMap.NO_NEXT_ENTRY);
447 }
448 hasNext = false;
449 canGetSet = true;
450 return parent.getKey();
451 }
452
453 @Override
454 public boolean hasPrevious() {
455 return hasNext == false;
456 }
457
458 @Override
459 public K previous() {
460 if (hasNext == true) {
461 throw new NoSuchElementException(AbstractHashedMap.NO_PREVIOUS_ENTRY);
462 }
463 hasNext = true;
464 return parent.getKey();
465 }
466
467 @Override
468 public void remove() {
469 throw new UnsupportedOperationException();
470 }
471
472 @Override
473 public K getKey() {
474 if (canGetSet == false) {
475 throw new IllegalStateException(AbstractHashedMap.GETKEY_INVALID);
476 }
477 return parent.getKey();
478 }
479
480 @Override
481 public V getValue() {
482 if (canGetSet == false) {
483 throw new IllegalStateException(AbstractHashedMap.GETVALUE_INVALID);
484 }
485 return parent.getValue();
486 }
487
488 @Override
489 public V setValue(final V value) {
490 if (canGetSet == false) {
491 throw new IllegalStateException(AbstractHashedMap.SETVALUE_INVALID);
492 }
493 return parent.setValue(value);
494 }
495
496 @Override
497 public void reset() {
498 hasNext = true;
499 }
500
501 @Override
502 public String toString() {
503 if (hasNext) {
504 return "Iterator[]";
505 }
506 return "Iterator[" + getKey() + "=" + getValue() + "]";
507 }
508 }
509
510
511
512
513
514 static class SingletonValues<V> extends AbstractSet<V> implements Serializable {
515 private static final long serialVersionUID = -3689524741863047872L;
516 private final SingletonMap<?, V> parent;
517
518 SingletonValues(final SingletonMap<?, V> parent) {
519 super();
520 this.parent = parent;
521 }
522
523 @Override
524 public int size() {
525 return 1;
526 }
527 @Override
528 public boolean isEmpty() {
529 return false;
530 }
531 @Override
532 public boolean contains(final Object object) {
533 return parent.containsValue(object);
534 }
535 @Override
536 public void clear() {
537 throw new UnsupportedOperationException();
538 }
539 @Override
540 public Iterator<V> iterator() {
541 return new SingletonIterator<>(parent.getValue(), false);
542 }
543 }
544
545
546
547
548
549
550
551 @Override
552 @SuppressWarnings("unchecked")
553 public SingletonMap<K, V> clone() {
554 try {
555 return (SingletonMap<K, V>) super.clone();
556 } catch (final CloneNotSupportedException ex) {
557 throw new InternalError();
558 }
559 }
560
561
562
563
564
565
566
567 @Override
568 public boolean equals(final Object obj) {
569 if (obj == this) {
570 return true;
571 }
572 if (obj instanceof Map == false) {
573 return false;
574 }
575 final Map<?,?> other = (Map<?,?>) obj;
576 if (other.size() != 1) {
577 return false;
578 }
579 final Map.Entry<?,?> entry = other.entrySet().iterator().next();
580 return isEqualKey(entry.getKey()) && isEqualValue(entry.getValue());
581 }
582
583
584
585
586
587
588 @Override
589 public int hashCode() {
590 return (getKey() == null ? 0 : getKey().hashCode()) ^
591 (getValue() == null ? 0 : getValue().hashCode());
592 }
593
594
595
596
597
598
599 @Override
600 public String toString() {
601 return new StringBuilder(128)
602 .append('{')
603 .append(getKey() == this ? "(this Map)" : getKey())
604 .append('=')
605 .append(getValue() == this ? "(this Map)" : getValue())
606 .append('}')
607 .toString();
608 }
609
610 }