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