001 /*
002 * Copyright (C) 2007 The Guava Authors
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 package com.google.common.collect;
018
019 import static com.google.common.base.Preconditions.checkNotNull;
020
021 import com.google.common.annotations.Beta;
022 import com.google.common.annotations.GwtCompatible;
023
024 import java.util.Collection;
025 import java.util.Comparator;
026 import java.util.Iterator;
027 import java.util.LinkedHashMap;
028 import java.util.List;
029 import java.util.Map;
030 import java.util.Map.Entry;
031 import java.util.Set;
032 import java.util.SortedSet;
033
034 import javax.annotation.Nullable;
035
036 /**
037 * Factory and utilities pertaining to the {@code MapConstraint} interface.
038 *
039 * @see Constraints
040 * @author Mike Bostock
041 * @since 3.0
042 */
043 @Beta
044 @GwtCompatible
045 public final class MapConstraints {
046 private MapConstraints() {}
047
048 /**
049 * Returns a constraint that verifies that neither the key nor the value is
050 * null. If either is null, a {@link NullPointerException} is thrown.
051 */
052 public static MapConstraint<Object, Object> notNull() {
053 return NotNullMapConstraint.INSTANCE;
054 }
055
056 // enum singleton pattern
057 private enum NotNullMapConstraint implements MapConstraint<Object, Object> {
058 INSTANCE;
059
060 @Override
061 public void checkKeyValue(Object key, Object value) {
062 checkNotNull(key);
063 checkNotNull(value);
064 }
065
066 @Override public String toString() {
067 return "Not null";
068 }
069 }
070
071 /**
072 * Returns a constrained view of the specified map, using the specified
073 * constraint. Any operations that add new mappings will call the provided
074 * constraint. However, this method does not verify that existing mappings
075 * satisfy the constraint.
076 *
077 * <p>The returned map is not serializable.
078 *
079 * @param map the map to constrain
080 * @param constraint the constraint that validates added entries
081 * @return a constrained view of the specified map
082 */
083 public static <K, V> Map<K, V> constrainedMap(
084 Map<K, V> map, MapConstraint<? super K, ? super V> constraint) {
085 return new ConstrainedMap<K, V>(map, constraint);
086 }
087
088 /**
089 * Returns a constrained view of the specified multimap, using the specified
090 * constraint. Any operations that add new mappings will call the provided
091 * constraint. However, this method does not verify that existing mappings
092 * satisfy the constraint.
093 *
094 * <p>Note that the generated multimap's {@link Multimap#removeAll} and
095 * {@link Multimap#replaceValues} methods return collections that are not
096 * constrained.
097 *
098 * <p>The returned multimap is not serializable.
099 *
100 * @param multimap the multimap to constrain
101 * @param constraint the constraint that validates added entries
102 * @return a constrained view of the multimap
103 */
104 public static <K, V> Multimap<K, V> constrainedMultimap(
105 Multimap<K, V> multimap, MapConstraint<? super K, ? super V> constraint) {
106 return new ConstrainedMultimap<K, V>(multimap, constraint);
107 }
108
109 /**
110 * Returns a constrained view of the specified list multimap, using the
111 * specified constraint. Any operations that add new mappings will call the
112 * provided constraint. However, this method does not verify that existing
113 * mappings satisfy the constraint.
114 *
115 * <p>Note that the generated multimap's {@link Multimap#removeAll} and
116 * {@link Multimap#replaceValues} methods return collections that are not
117 * constrained.
118 *
119 * <p>The returned multimap is not serializable.
120 *
121 * @param multimap the multimap to constrain
122 * @param constraint the constraint that validates added entries
123 * @return a constrained view of the specified multimap
124 */
125 public static <K, V> ListMultimap<K, V> constrainedListMultimap(
126 ListMultimap<K, V> multimap,
127 MapConstraint<? super K, ? super V> constraint) {
128 return new ConstrainedListMultimap<K, V>(multimap, constraint);
129 }
130
131 /**
132 * Returns a constrained view of the specified set multimap, using the
133 * specified constraint. Any operations that add new mappings will call the
134 * provided constraint. However, this method does not verify that existing
135 * mappings satisfy the constraint.
136 *
137 * <p>Note that the generated multimap's {@link Multimap#removeAll} and
138 * {@link Multimap#replaceValues} methods return collections that are not
139 * constrained.
140 * <p>The returned multimap is not serializable.
141 *
142 * @param multimap the multimap to constrain
143 * @param constraint the constraint that validates added entries
144 * @return a constrained view of the specified multimap
145 */
146 public static <K, V> SetMultimap<K, V> constrainedSetMultimap(
147 SetMultimap<K, V> multimap,
148 MapConstraint<? super K, ? super V> constraint) {
149 return new ConstrainedSetMultimap<K, V>(multimap, constraint);
150 }
151
152 /**
153 * Returns a constrained view of the specified sorted-set multimap, using the
154 * specified constraint. Any operations that add new mappings will call the
155 * provided constraint. However, this method does not verify that existing
156 * mappings satisfy the constraint.
157 *
158 * <p>Note that the generated multimap's {@link Multimap#removeAll} and
159 * {@link Multimap#replaceValues} methods return collections that are not
160 * constrained.
161 * <p>The returned multimap is not serializable.
162 *
163 * @param multimap the multimap to constrain
164 * @param constraint the constraint that validates added entries
165 * @return a constrained view of the specified multimap
166 */
167 public static <K, V> SortedSetMultimap<K, V> constrainedSortedSetMultimap(
168 SortedSetMultimap<K, V> multimap,
169 MapConstraint<? super K, ? super V> constraint) {
170 return new ConstrainedSortedSetMultimap<K, V>(multimap, constraint);
171 }
172
173 /**
174 * Returns a constrained view of the specified entry, using the specified
175 * constraint. The {@link Entry#setValue} operation will be verified with the
176 * constraint.
177 *
178 * @param entry the entry to constrain
179 * @param constraint the constraint for the entry
180 * @return a constrained view of the specified entry
181 */
182 private static <K, V> Entry<K, V> constrainedEntry(
183 final Entry<K, V> entry,
184 final MapConstraint<? super K, ? super V> constraint) {
185 checkNotNull(entry);
186 checkNotNull(constraint);
187 return new ForwardingMapEntry<K, V>() {
188 @Override protected Entry<K, V> delegate() {
189 return entry;
190 }
191 @Override public V setValue(V value) {
192 constraint.checkKeyValue(getKey(), value);
193 return entry.setValue(value);
194 }
195 };
196 }
197
198 /**
199 * Returns a constrained view of the specified {@code asMap} entry, using the
200 * specified constraint. The {@link Entry#setValue} operation will be verified
201 * with the constraint, and the collection returned by {@link Entry#getValue}
202 * will be similarly constrained.
203 *
204 * @param entry the {@code asMap} entry to constrain
205 * @param constraint the constraint for the entry
206 * @return a constrained view of the specified entry
207 */
208 private static <K, V> Entry<K, Collection<V>> constrainedAsMapEntry(
209 final Entry<K, Collection<V>> entry,
210 final MapConstraint<? super K, ? super V> constraint) {
211 checkNotNull(entry);
212 checkNotNull(constraint);
213 return new ForwardingMapEntry<K, Collection<V>>() {
214 @Override protected Entry<K, Collection<V>> delegate() {
215 return entry;
216 }
217 @Override public Collection<V> getValue() {
218 return Constraints.constrainedTypePreservingCollection(
219 entry.getValue(), new Constraint<V>() {
220 @Override
221 public V checkElement(V value) {
222 constraint.checkKeyValue(getKey(), value);
223 return value;
224 }
225 });
226 }
227 };
228 }
229
230 /**
231 * Returns a constrained view of the specified set of {@code asMap} entries,
232 * using the specified constraint. The {@link Entry#setValue} operation will
233 * be verified with the constraint, and the collection returned by {@link
234 * Entry#getValue} will be similarly constrained. The {@code add} and {@code
235 * addAll} operations simply forward to the underlying set, which throws an
236 * {@link UnsupportedOperationException} per the multimap specification.
237 *
238 * @param entries the entries to constrain
239 * @param constraint the constraint for the entries
240 * @return a constrained view of the entries
241 */
242 private static <K, V> Set<Entry<K, Collection<V>>> constrainedAsMapEntries(
243 Set<Entry<K, Collection<V>>> entries,
244 MapConstraint<? super K, ? super V> constraint) {
245 return new ConstrainedAsMapEntries<K, V>(entries, constraint);
246 }
247
248 /**
249 * Returns a constrained view of the specified collection (or set) of entries,
250 * using the specified constraint. The {@link Entry#setValue} operation will
251 * be verified with the constraint, along with add operations on the returned
252 * collection. The {@code add} and {@code addAll} operations simply forward to
253 * the underlying collection, which throws an {@link
254 * UnsupportedOperationException} per the map and multimap specification.
255 *
256 * @param entries the entries to constrain
257 * @param constraint the constraint for the entries
258 * @return a constrained view of the specified entries
259 */
260 private static <K, V> Collection<Entry<K, V>> constrainedEntries(
261 Collection<Entry<K, V>> entries,
262 MapConstraint<? super K, ? super V> constraint) {
263 if (entries instanceof Set) {
264 return constrainedEntrySet((Set<Entry<K, V>>) entries, constraint);
265 }
266 return new ConstrainedEntries<K, V>(entries, constraint);
267 }
268
269 /**
270 * Returns a constrained view of the specified set of entries, using the
271 * specified constraint. The {@link Entry#setValue} operation will be verified
272 * with the constraint, along with add operations on the returned set. The
273 * {@code add} and {@code addAll} operations simply forward to the underlying
274 * set, which throws an {@link UnsupportedOperationException} per the map and
275 * multimap specification.
276 *
277 * <p>The returned multimap is not serializable.
278 *
279 * @param entries the entries to constrain
280 * @param constraint the constraint for the entries
281 * @return a constrained view of the specified entries
282 */
283 private static <K, V> Set<Entry<K, V>> constrainedEntrySet(
284 Set<Entry<K, V>> entries,
285 MapConstraint<? super K, ? super V> constraint) {
286 return new ConstrainedEntrySet<K, V>(entries, constraint);
287 }
288
289 /** @see MapConstraints#constrainedMap */
290 static class ConstrainedMap<K, V> extends ForwardingMap<K, V> {
291 private final Map<K, V> delegate;
292 final MapConstraint<? super K, ? super V> constraint;
293 private transient Set<Entry<K, V>> entrySet;
294
295 ConstrainedMap(
296 Map<K, V> delegate, MapConstraint<? super K, ? super V> constraint) {
297 this.delegate = checkNotNull(delegate);
298 this.constraint = checkNotNull(constraint);
299 }
300 @Override protected Map<K, V> delegate() {
301 return delegate;
302 }
303 @Override public Set<Entry<K, V>> entrySet() {
304 Set<Entry<K, V>> result = entrySet;
305 if (result == null) {
306 entrySet = result =
307 constrainedEntrySet(delegate.entrySet(), constraint);
308 }
309 return result;
310 }
311 @Override public V put(K key, V value) {
312 constraint.checkKeyValue(key, value);
313 return delegate.put(key, value);
314 }
315 @Override public void putAll(Map<? extends K, ? extends V> map) {
316 delegate.putAll(checkMap(map, constraint));
317 }
318 }
319
320 /**
321 * Returns a constrained view of the specified bimap, using the specified
322 * constraint. Any operations that modify the bimap will have the associated
323 * keys and values verified with the constraint.
324 *
325 * <p>The returned bimap is not serializable.
326 *
327 * @param map the bimap to constrain
328 * @param constraint the constraint that validates added entries
329 * @return a constrained view of the specified bimap
330 */
331 public static <K, V> BiMap<K, V> constrainedBiMap(
332 BiMap<K, V> map, MapConstraint<? super K, ? super V> constraint) {
333 return new ConstrainedBiMap<K, V>(map, null, constraint);
334 }
335
336 /** @see MapConstraints#constrainedBiMap */
337 private static class ConstrainedBiMap<K, V> extends ConstrainedMap<K, V>
338 implements BiMap<K, V> {
339 /*
340 * We could switch to racy single-check lazy init and remove volatile, but
341 * there's a downside. That's because this field is also written in the
342 * constructor. Without volatile, the constructor's write of the existing
343 * inverse BiMap could occur after inverse()'s read of the field's initial
344 * null value, leading inverse() to overwrite the existing inverse with a
345 * doubly indirect version. This wouldn't be catastrophic, but it's
346 * something to keep in mind if we make the change.
347 *
348 * Note that UnmodifiableBiMap *does* use racy single-check lazy init.
349 * TODO(cpovirk): pick one and standardize
350 */
351 volatile BiMap<V, K> inverse;
352
353 ConstrainedBiMap(BiMap<K, V> delegate, @Nullable BiMap<V, K> inverse,
354 MapConstraint<? super K, ? super V> constraint) {
355 super(delegate, constraint);
356 this.inverse = inverse;
357 }
358
359 @Override protected BiMap<K, V> delegate() {
360 return (BiMap<K, V>) super.delegate();
361 }
362
363 @Override
364 public V forcePut(K key, V value) {
365 constraint.checkKeyValue(key, value);
366 return delegate().forcePut(key, value);
367 }
368
369 @Override
370 public BiMap<V, K> inverse() {
371 if (inverse == null) {
372 inverse = new ConstrainedBiMap<V, K>(delegate().inverse(), this,
373 new InverseConstraint<V, K>(constraint));
374 }
375 return inverse;
376 }
377
378 @Override public Set<V> values() {
379 return delegate().values();
380 }
381 }
382
383 /** @see MapConstraints#constrainedBiMap */
384 private static class InverseConstraint<K, V> implements MapConstraint<K, V> {
385 final MapConstraint<? super V, ? super K> constraint;
386
387 public InverseConstraint(MapConstraint<? super V, ? super K> constraint) {
388 this.constraint = checkNotNull(constraint);
389 }
390 @Override
391 public void checkKeyValue(K key, V value) {
392 constraint.checkKeyValue(value, key);
393 }
394 }
395
396 /** @see MapConstraints#constrainedMultimap */
397 private static class ConstrainedMultimap<K, V>
398 extends ForwardingMultimap<K, V> {
399 final MapConstraint<? super K, ? super V> constraint;
400 final Multimap<K, V> delegate;
401 transient Collection<Entry<K, V>> entries;
402 transient Map<K, Collection<V>> asMap;
403
404 public ConstrainedMultimap(Multimap<K, V> delegate,
405 MapConstraint<? super K, ? super V> constraint) {
406 this.delegate = checkNotNull(delegate);
407 this.constraint = checkNotNull(constraint);
408 }
409
410 @Override protected Multimap<K, V> delegate() {
411 return delegate;
412 }
413
414 @Override public Map<K, Collection<V>> asMap() {
415 Map<K, Collection<V>> result = asMap;
416 if (result == null) {
417 final Map<K, Collection<V>> asMapDelegate = delegate.asMap();
418
419 asMap = result = new ForwardingMap<K, Collection<V>>() {
420 Set<Entry<K, Collection<V>>> entrySet;
421 Collection<Collection<V>> values;
422
423 @Override protected Map<K, Collection<V>> delegate() {
424 return asMapDelegate;
425 }
426
427 @Override public Set<Entry<K, Collection<V>>> entrySet() {
428 Set<Entry<K, Collection<V>>> result = entrySet;
429 if (result == null) {
430 entrySet = result = constrainedAsMapEntries(
431 asMapDelegate.entrySet(), constraint);
432 }
433 return result;
434 }
435
436 @SuppressWarnings("unchecked")
437 @Override public Collection<V> get(Object key) {
438 try {
439 Collection<V> collection = ConstrainedMultimap.this.get((K) key);
440 return collection.isEmpty() ? null : collection;
441 } catch (ClassCastException e) {
442 return null; // key wasn't a K
443 }
444 }
445
446 @Override public Collection<Collection<V>> values() {
447 Collection<Collection<V>> result = values;
448 if (result == null) {
449 values = result = new ConstrainedAsMapValues<K, V>(
450 delegate().values(), entrySet());
451 }
452 return result;
453 }
454
455 @Override public boolean containsValue(Object o) {
456 return values().contains(o);
457 }
458 };
459 }
460 return result;
461 }
462
463 @Override public Collection<Entry<K, V>> entries() {
464 Collection<Entry<K, V>> result = entries;
465 if (result == null) {
466 entries = result = constrainedEntries(delegate.entries(), constraint);
467 }
468 return result;
469 }
470
471 @Override public Collection<V> get(final K key) {
472 return Constraints.constrainedTypePreservingCollection(
473 delegate.get(key), new Constraint<V>() {
474 @Override
475 public V checkElement(V value) {
476 constraint.checkKeyValue(key, value);
477 return value;
478 }
479 });
480 }
481
482 @Override public boolean put(K key, V value) {
483 constraint.checkKeyValue(key, value);
484 return delegate.put(key, value);
485 }
486
487 @Override public boolean putAll(K key, Iterable<? extends V> values) {
488 return delegate.putAll(key, checkValues(key, values, constraint));
489 }
490
491 @Override public boolean putAll(
492 Multimap<? extends K, ? extends V> multimap) {
493 boolean changed = false;
494 for (Entry<? extends K, ? extends V> entry : multimap.entries()) {
495 changed |= put(entry.getKey(), entry.getValue());
496 }
497 return changed;
498 }
499
500 @Override public Collection<V> replaceValues(
501 K key, Iterable<? extends V> values) {
502 return delegate.replaceValues(key, checkValues(key, values, constraint));
503 }
504 }
505
506 /** @see ConstrainedMultimap#asMap */
507 private static class ConstrainedAsMapValues<K, V>
508 extends ForwardingCollection<Collection<V>> {
509 final Collection<Collection<V>> delegate;
510 final Set<Entry<K, Collection<V>>> entrySet;
511
512 /**
513 * @param entrySet map entries, linking each key with its corresponding
514 * values, that already enforce the constraint
515 */
516 ConstrainedAsMapValues(Collection<Collection<V>> delegate,
517 Set<Entry<K, Collection<V>>> entrySet) {
518 this.delegate = delegate;
519 this.entrySet = entrySet;
520 }
521 @Override protected Collection<Collection<V>> delegate() {
522 return delegate;
523 }
524
525 @Override public Iterator<Collection<V>> iterator() {
526 final Iterator<Entry<K, Collection<V>>> iterator = entrySet.iterator();
527 return new Iterator<Collection<V>>() {
528 @Override
529 public boolean hasNext() {
530 return iterator.hasNext();
531 }
532 @Override
533 public Collection<V> next() {
534 return iterator.next().getValue();
535 }
536 @Override
537 public void remove() {
538 iterator.remove();
539 }
540 };
541 }
542
543 @Override public Object[] toArray() {
544 return standardToArray();
545 }
546 @Override public <T> T[] toArray(T[] array) {
547 return standardToArray(array);
548 }
549 @Override public boolean contains(Object o) {
550 return standardContains(o);
551 }
552 @Override public boolean containsAll(Collection<?> c) {
553 return standardContainsAll(c);
554 }
555 @Override public boolean remove(Object o) {
556 return standardRemove(o);
557 }
558 @Override public boolean removeAll(Collection<?> c) {
559 return standardRemoveAll(c);
560 }
561 @Override public boolean retainAll(Collection<?> c) {
562 return standardRetainAll(c);
563 }
564 }
565
566 /** @see MapConstraints#constrainedEntries */
567 private static class ConstrainedEntries<K, V>
568 extends ForwardingCollection<Entry<K, V>> {
569 final MapConstraint<? super K, ? super V> constraint;
570 final Collection<Entry<K, V>> entries;
571
572 ConstrainedEntries(Collection<Entry<K, V>> entries,
573 MapConstraint<? super K, ? super V> constraint) {
574 this.entries = entries;
575 this.constraint = constraint;
576 }
577 @Override protected Collection<Entry<K, V>> delegate() {
578 return entries;
579 }
580
581 @Override public Iterator<Entry<K, V>> iterator() {
582 final Iterator<Entry<K, V>> iterator = entries.iterator();
583 return new ForwardingIterator<Entry<K, V>>() {
584 @Override public Entry<K, V> next() {
585 return constrainedEntry(iterator.next(), constraint);
586 }
587 @Override protected Iterator<Entry<K, V>> delegate() {
588 return iterator;
589 }
590 };
591 }
592
593 // See Collections.CheckedMap.CheckedEntrySet for details on attacks.
594
595 @Override public Object[] toArray() {
596 return standardToArray();
597 }
598 @Override public <T> T[] toArray(T[] array) {
599 return standardToArray(array);
600 }
601 @Override public boolean contains(Object o) {
602 return Maps.containsEntryImpl(delegate(), o);
603 }
604 @Override public boolean containsAll(Collection<?> c) {
605 return standardContainsAll(c);
606 }
607 @Override public boolean remove(Object o) {
608 return Maps.removeEntryImpl(delegate(), o);
609 }
610 @Override public boolean removeAll(Collection<?> c) {
611 return standardRemoveAll(c);
612 }
613 @Override public boolean retainAll(Collection<?> c) {
614 return standardRetainAll(c);
615 }
616 }
617
618 /** @see MapConstraints#constrainedEntrySet */
619 static class ConstrainedEntrySet<K, V>
620 extends ConstrainedEntries<K, V> implements Set<Entry<K, V>> {
621 ConstrainedEntrySet(Set<Entry<K, V>> entries,
622 MapConstraint<? super K, ? super V> constraint) {
623 super(entries, constraint);
624 }
625
626 // See Collections.CheckedMap.CheckedEntrySet for details on attacks.
627
628 @Override public boolean equals(@Nullable Object object) {
629 return Sets.equalsImpl(this, object);
630 }
631
632 @Override public int hashCode() {
633 return Sets.hashCodeImpl(this);
634 }
635 }
636
637 /** @see MapConstraints#constrainedAsMapEntries */
638 static class ConstrainedAsMapEntries<K, V>
639 extends ForwardingSet<Entry<K, Collection<V>>> {
640 private final MapConstraint<? super K, ? super V> constraint;
641 private final Set<Entry<K, Collection<V>>> entries;
642
643 ConstrainedAsMapEntries(Set<Entry<K, Collection<V>>> entries,
644 MapConstraint<? super K, ? super V> constraint) {
645 this.entries = entries;
646 this.constraint = constraint;
647 }
648
649 @Override protected Set<Entry<K, Collection<V>>> delegate() {
650 return entries;
651 }
652
653 @Override public Iterator<Entry<K, Collection<V>>> iterator() {
654 final Iterator<Entry<K, Collection<V>>> iterator = entries.iterator();
655 return new ForwardingIterator<Entry<K, Collection<V>>>() {
656 @Override public Entry<K, Collection<V>> next() {
657 return constrainedAsMapEntry(iterator.next(), constraint);
658 }
659 @Override protected Iterator<Entry<K, Collection<V>>> delegate() {
660 return iterator;
661 }
662 };
663 }
664
665 // See Collections.CheckedMap.CheckedEntrySet for details on attacks.
666
667 @Override public Object[] toArray() {
668 return standardToArray();
669 }
670
671 @Override public <T> T[] toArray(T[] array) {
672 return standardToArray(array);
673 }
674
675 @Override public boolean contains(Object o) {
676 return Maps.containsEntryImpl(delegate(), o);
677 }
678
679 @Override public boolean containsAll(Collection<?> c) {
680 return standardContainsAll(c);
681 }
682
683 @Override public boolean equals(@Nullable Object object) {
684 return standardEquals(object);
685 }
686
687 @Override public int hashCode() {
688 return standardHashCode();
689 }
690
691 @Override public boolean remove(Object o) {
692 return Maps.removeEntryImpl(delegate(), o);
693 }
694
695 @Override public boolean removeAll(Collection<?> c) {
696 return standardRemoveAll(c);
697 }
698
699 @Override public boolean retainAll(Collection<?> c) {
700 return standardRetainAll(c);
701 }
702 }
703
704 private static class ConstrainedListMultimap<K, V>
705 extends ConstrainedMultimap<K, V> implements ListMultimap<K, V> {
706 ConstrainedListMultimap(ListMultimap<K, V> delegate,
707 MapConstraint<? super K, ? super V> constraint) {
708 super(delegate, constraint);
709 }
710 @Override public List<V> get(K key) {
711 return (List<V>) super.get(key);
712 }
713 @Override public List<V> removeAll(Object key) {
714 return (List<V>) super.removeAll(key);
715 }
716 @Override public List<V> replaceValues(
717 K key, Iterable<? extends V> values) {
718 return (List<V>) super.replaceValues(key, values);
719 }
720 }
721
722 private static class ConstrainedSetMultimap<K, V>
723 extends ConstrainedMultimap<K, V> implements SetMultimap<K, V> {
724 ConstrainedSetMultimap(SetMultimap<K, V> delegate,
725 MapConstraint<? super K, ? super V> constraint) {
726 super(delegate, constraint);
727 }
728 @Override public Set<V> get(K key) {
729 return (Set<V>) super.get(key);
730 }
731 @Override public Set<Map.Entry<K, V>> entries() {
732 return (Set<Map.Entry<K, V>>) super.entries();
733 }
734 @Override public Set<V> removeAll(Object key) {
735 return (Set<V>) super.removeAll(key);
736 }
737 @Override public Set<V> replaceValues(
738 K key, Iterable<? extends V> values) {
739 return (Set<V>) super.replaceValues(key, values);
740 }
741 }
742
743 private static class ConstrainedSortedSetMultimap<K, V>
744 extends ConstrainedSetMultimap<K, V> implements SortedSetMultimap<K, V> {
745 ConstrainedSortedSetMultimap(SortedSetMultimap<K, V> delegate,
746 MapConstraint<? super K, ? super V> constraint) {
747 super(delegate, constraint);
748 }
749 @Override public SortedSet<V> get(K key) {
750 return (SortedSet<V>) super.get(key);
751 }
752 @Override public SortedSet<V> removeAll(Object key) {
753 return (SortedSet<V>) super.removeAll(key);
754 }
755 @Override public SortedSet<V> replaceValues(
756 K key, Iterable<? extends V> values) {
757 return (SortedSet<V>) super.replaceValues(key, values);
758 }
759 @Override
760 public Comparator<? super V> valueComparator() {
761 return ((SortedSetMultimap<K, V>) delegate()).valueComparator();
762 }
763 }
764
765 private static <K, V> Collection<V> checkValues(K key,
766 Iterable<? extends V> values,
767 MapConstraint<? super K, ? super V> constraint) {
768 Collection<V> copy = Lists.newArrayList(values);
769 for (V value : copy) {
770 constraint.checkKeyValue(key, value);
771 }
772 return copy;
773 }
774
775 private static <K, V> Map<K, V> checkMap(Map<? extends K, ? extends V> map,
776 MapConstraint<? super K, ? super V> constraint) {
777 Map<K, V> copy = new LinkedHashMap<K, V>(map);
778 for (Entry<K, V> entry : copy.entrySet()) {
779 constraint.checkKeyValue(entry.getKey(), entry.getValue());
780 }
781 return copy;
782 }
783 }