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.common.base.Preconditions; 024 025import java.util.Collection; 026import java.util.List; 027import java.util.ListIterator; 028import java.util.RandomAccess; 029import java.util.Set; 030import java.util.SortedSet; 031 032/** 033 * Factories and utilities pertaining to the {@link Constraint} interface. 034 * 035 * @see MapConstraints 036 * @author Mike Bostock 037 * @author Jared Levy 038 * @since 3.0 039 * @deprecated Use {@link Preconditions} for basic checks. In place of 040 * constrained collections, we encourage you to check your preconditions 041 * explicitly instead of leaving that work to the collection implementation. 042 * For the specific case of rejecting null, consider the immutable 043 * collections. 044 * This class is scheduled for removal in Guava 16.0. 045 */ 046@Beta 047@Deprecated 048@GwtCompatible 049public final class Constraints { 050 private Constraints() {} 051 052 // enum singleton pattern 053 private enum NotNullConstraint implements Constraint<Object> { 054 INSTANCE; 055 056 @Override 057 public Object checkElement(Object element) { 058 return checkNotNull(element); 059 } 060 061 @Override public String toString() { 062 return "Not null"; 063 } 064 } 065 066 /** 067 * Returns a constraint that verifies that the element is not null. If the 068 * element is null, a {@link NullPointerException} is thrown. 069 */ 070 // safe to narrow the type since checkElement returns its argument directly 071 @SuppressWarnings("unchecked") 072 public static <E> Constraint<E> notNull() { 073 return (Constraint<E>) NotNullConstraint.INSTANCE; 074 } 075 076 /** 077 * Returns a constrained view of the specified collection, using the specified 078 * constraint. Any operations that add new elements to the collection will 079 * call the provided constraint. However, this method does not verify that 080 * existing elements satisfy the constraint. 081 * 082 * <p>The returned collection is not serializable. 083 * 084 * @param collection the collection to constrain 085 * @param constraint the constraint that validates added elements 086 * @return a constrained view of the collection 087 */ 088 public static <E> Collection<E> constrainedCollection( 089 Collection<E> collection, Constraint<? super E> constraint) { 090 return new ConstrainedCollection<E>(collection, constraint); 091 } 092 093 /** @see Constraints#constrainedCollection */ 094 static class ConstrainedCollection<E> extends ForwardingCollection<E> { 095 private final Collection<E> delegate; 096 private final Constraint<? super E> constraint; 097 098 public ConstrainedCollection( 099 Collection<E> delegate, Constraint<? super E> constraint) { 100 this.delegate = checkNotNull(delegate); 101 this.constraint = checkNotNull(constraint); 102 } 103 @Override protected Collection<E> delegate() { 104 return delegate; 105 } 106 @Override public boolean add(E element) { 107 constraint.checkElement(element); 108 return delegate.add(element); 109 } 110 @Override public boolean addAll(Collection<? extends E> elements) { 111 return delegate.addAll(checkElements(elements, constraint)); 112 } 113 } 114 115 /** 116 * Returns a constrained view of the specified set, using the specified 117 * constraint. Any operations that add new elements to the set will call the 118 * provided constraint. However, this method does not verify that existing 119 * elements satisfy the constraint. 120 * 121 * <p>The returned set is not serializable. 122 * 123 * @param set the set to constrain 124 * @param constraint the constraint that validates added elements 125 * @return a constrained view of the set 126 */ 127 public static <E> Set<E> constrainedSet( 128 Set<E> set, Constraint<? super E> constraint) { 129 return new ConstrainedSet<E>(set, constraint); 130 } 131 132 /** @see Constraints#constrainedSet */ 133 static class ConstrainedSet<E> extends ForwardingSet<E> { 134 private final Set<E> delegate; 135 private final Constraint<? super E> constraint; 136 137 public ConstrainedSet(Set<E> delegate, Constraint<? super E> constraint) { 138 this.delegate = checkNotNull(delegate); 139 this.constraint = checkNotNull(constraint); 140 } 141 @Override protected Set<E> delegate() { 142 return delegate; 143 } 144 @Override public boolean add(E element) { 145 constraint.checkElement(element); 146 return delegate.add(element); 147 } 148 @Override public boolean addAll(Collection<? extends E> elements) { 149 return delegate.addAll(checkElements(elements, constraint)); 150 } 151 } 152 153 /** 154 * Returns a constrained view of the specified sorted set, using the specified 155 * constraint. Any operations that add new elements to the sorted set will 156 * call the provided constraint. However, this method does not verify that 157 * existing elements satisfy the constraint. 158 * 159 * <p>The returned set is not serializable. 160 * 161 * @param sortedSet the sorted set to constrain 162 * @param constraint the constraint that validates added elements 163 * @return a constrained view of the sorted set 164 */ 165 public static <E> SortedSet<E> constrainedSortedSet( 166 SortedSet<E> sortedSet, Constraint<? super E> constraint) { 167 return new ConstrainedSortedSet<E>(sortedSet, constraint); 168 } 169 170 /** @see Constraints#constrainedSortedSet */ 171 private static class ConstrainedSortedSet<E> extends ForwardingSortedSet<E> { 172 final SortedSet<E> delegate; 173 final Constraint<? super E> constraint; 174 175 ConstrainedSortedSet( 176 SortedSet<E> delegate, Constraint<? super E> constraint) { 177 this.delegate = checkNotNull(delegate); 178 this.constraint = checkNotNull(constraint); 179 } 180 @Override protected SortedSet<E> delegate() { 181 return delegate; 182 } 183 @Override public SortedSet<E> headSet(E toElement) { 184 return constrainedSortedSet(delegate.headSet(toElement), constraint); 185 } 186 @Override public SortedSet<E> subSet(E fromElement, E toElement) { 187 return constrainedSortedSet( 188 delegate.subSet(fromElement, toElement), constraint); 189 } 190 @Override public SortedSet<E> tailSet(E fromElement) { 191 return constrainedSortedSet(delegate.tailSet(fromElement), constraint); 192 } 193 @Override public boolean add(E element) { 194 constraint.checkElement(element); 195 return delegate.add(element); 196 } 197 @Override public boolean addAll(Collection<? extends E> elements) { 198 return delegate.addAll(checkElements(elements, constraint)); 199 } 200 } 201 202 /** 203 * Returns a constrained view of the specified list, using the specified 204 * constraint. Any operations that add new elements to the list will call the 205 * provided constraint. However, this method does not verify that existing 206 * elements satisfy the constraint. 207 * 208 * <p>If {@code list} implements {@link RandomAccess}, so will the returned 209 * list. The returned list is not serializable. 210 * 211 * @param list the list to constrain 212 * @param constraint the constraint that validates added elements 213 * @return a constrained view of the list 214 */ 215 public static <E> List<E> constrainedList( 216 List<E> list, Constraint<? super E> constraint) { 217 return (list instanceof RandomAccess) 218 ? new ConstrainedRandomAccessList<E>(list, constraint) 219 : new ConstrainedList<E>(list, constraint); 220 } 221 222 /** @see Constraints#constrainedList */ 223 @GwtCompatible 224 private static class ConstrainedList<E> extends ForwardingList<E> { 225 final List<E> delegate; 226 final Constraint<? super E> constraint; 227 228 ConstrainedList(List<E> delegate, Constraint<? super E> constraint) { 229 this.delegate = checkNotNull(delegate); 230 this.constraint = checkNotNull(constraint); 231 } 232 @Override protected List<E> delegate() { 233 return delegate; 234 } 235 236 @Override public boolean add(E element) { 237 constraint.checkElement(element); 238 return delegate.add(element); 239 } 240 @Override public void add(int index, E element) { 241 constraint.checkElement(element); 242 delegate.add(index, element); 243 } 244 @Override public boolean addAll(Collection<? extends E> elements) { 245 return delegate.addAll(checkElements(elements, constraint)); 246 } 247 @Override public boolean addAll(int index, Collection<? extends E> elements) 248 { 249 return delegate.addAll(index, checkElements(elements, constraint)); 250 } 251 @Override public ListIterator<E> listIterator() { 252 return constrainedListIterator(delegate.listIterator(), constraint); 253 } 254 @Override public ListIterator<E> listIterator(int index) { 255 return constrainedListIterator(delegate.listIterator(index), constraint); 256 } 257 @Override public E set(int index, E element) { 258 constraint.checkElement(element); 259 return delegate.set(index, element); 260 } 261 @Override public List<E> subList(int fromIndex, int toIndex) { 262 return constrainedList( 263 delegate.subList(fromIndex, toIndex), constraint); 264 } 265 } 266 267 /** @see Constraints#constrainedList */ 268 static class ConstrainedRandomAccessList<E> extends ConstrainedList<E> 269 implements RandomAccess { 270 ConstrainedRandomAccessList( 271 List<E> delegate, Constraint<? super E> constraint) { 272 super(delegate, constraint); 273 } 274 } 275 276 /** 277 * Returns a constrained view of the specified list iterator, using the 278 * specified constraint. Any operations that would add new elements to the 279 * underlying list will be verified by the constraint. 280 * 281 * @param listIterator the iterator for which to return a constrained view 282 * @param constraint the constraint for elements in the list 283 * @return a constrained view of the specified iterator 284 */ 285 private static <E> ListIterator<E> constrainedListIterator( 286 ListIterator<E> listIterator, Constraint<? super E> constraint) { 287 return new ConstrainedListIterator<E>(listIterator, constraint); 288 } 289 290 /** @see Constraints#constrainedListIterator */ 291 static class ConstrainedListIterator<E> extends ForwardingListIterator<E> { 292 private final ListIterator<E> delegate; 293 private final Constraint<? super E> constraint; 294 295 public ConstrainedListIterator( 296 ListIterator<E> delegate, Constraint<? super E> constraint) { 297 this.delegate = delegate; 298 this.constraint = constraint; 299 } 300 @Override protected ListIterator<E> delegate() { 301 return delegate; 302 } 303 304 @Override public void add(E element) { 305 constraint.checkElement(element); 306 delegate.add(element); 307 } 308 @Override public void set(E element) { 309 constraint.checkElement(element); 310 delegate.set(element); 311 } 312 } 313 314 static <E> Collection<E> constrainedTypePreservingCollection( 315 Collection<E> collection, Constraint<E> constraint) { 316 if (collection instanceof SortedSet) { 317 return constrainedSortedSet((SortedSet<E>) collection, constraint); 318 } else if (collection instanceof Set) { 319 return constrainedSet((Set<E>) collection, constraint); 320 } else if (collection instanceof List) { 321 return constrainedList((List<E>) collection, constraint); 322 } else { 323 return constrainedCollection(collection, constraint); 324 } 325 } 326 327 /** 328 * Returns a constrained view of the specified multiset, using the specified 329 * constraint. Any operations that add new elements to the multiset will call 330 * the provided constraint. However, this method does not verify that 331 * existing elements satisfy the constraint. 332 * 333 * <p>The returned multiset is not serializable. 334 * 335 * @param multiset the multiset to constrain 336 * @param constraint the constraint that validates added elements 337 * @return a constrained view of the multiset 338 */ 339 public static <E> Multiset<E> constrainedMultiset( 340 Multiset<E> multiset, Constraint<? super E> constraint) { 341 return new ConstrainedMultiset<E>(multiset, constraint); 342 } 343 344 /** @see Constraints#constrainedMultiset */ 345 static class ConstrainedMultiset<E> extends ForwardingMultiset<E> { 346 private Multiset<E> delegate; 347 private final Constraint<? super E> constraint; 348 349 public ConstrainedMultiset( 350 Multiset<E> delegate, Constraint<? super E> constraint) { 351 this.delegate = checkNotNull(delegate); 352 this.constraint = checkNotNull(constraint); 353 } 354 @Override protected Multiset<E> delegate() { 355 return delegate; 356 } 357 @Override public boolean add(E element) { 358 return standardAdd(element); 359 } 360 @Override public boolean addAll(Collection<? extends E> elements) { 361 return delegate.addAll(checkElements(elements, constraint)); 362 } 363 @Override public int add(E element, int occurrences) { 364 constraint.checkElement(element); 365 return delegate.add(element, occurrences); 366 } 367 @Override public int setCount(E element, int count) { 368 constraint.checkElement(element); 369 return delegate.setCount(element, count); 370 } 371 @Override public boolean setCount(E element, int oldCount, int newCount) { 372 constraint.checkElement(element); 373 return delegate.setCount(element, oldCount, newCount); 374 } 375 } 376 377 /* 378 * TODO(kevinb): For better performance, avoid making a copy of the elements 379 * by having addAll() call add() repeatedly instead. 380 */ 381 382 private static <E> Collection<E> checkElements( 383 Collection<E> elements, Constraint<? super E> constraint) { 384 Collection<E> copy = Lists.newArrayList(elements); 385 for (E element : copy) { 386 constraint.checkElement(element); 387 } 388 return copy; 389 } 390}