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 }