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