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