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