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