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