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
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    }