1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.printservice.recommendation.util; 18 19 import android.text.TextUtils; 20 21 import androidx.annotation.IntRange; 22 import androidx.annotation.NonNull; 23 24 import java.util.Collection; 25 26 /** 27 * Simple static methods to be called at the start of your own methods to verify 28 * correct arguments and state. 29 */ 30 public class Preconditions { 31 checkArgument(boolean expression)32 public static void checkArgument(boolean expression) { 33 if (!expression) { 34 throw new IllegalArgumentException(); 35 } 36 } 37 38 /** 39 * Ensures that an expression checking an argument is true. 40 * 41 * @param expression the expression to check 42 * @param errorMessage the exception message to use if the check fails; will 43 * be converted to a string using {@link String#valueOf(Object)} 44 * @throws IllegalArgumentException if {@code expression} is false 45 */ checkArgument(boolean expression, final Object errorMessage)46 public static void checkArgument(boolean expression, final Object errorMessage) { 47 if (!expression) { 48 throw new IllegalArgumentException(String.valueOf(errorMessage)); 49 } 50 } 51 52 /** 53 * Ensures that an expression checking an argument is true. 54 * 55 * @param expression the expression to check 56 * @param messageTemplate a printf-style message template to use if the check fails; will 57 * be converted to a string using {@link String#format(String, Object...)} 58 * @param messageArgs arguments for {@code messageTemplate} 59 * @throws IllegalArgumentException if {@code expression} is false 60 */ checkArgument(boolean expression, final String messageTemplate, final Object... messageArgs)61 public static void checkArgument(boolean expression, 62 final String messageTemplate, 63 final Object... messageArgs) { 64 if (!expression) { 65 throw new IllegalArgumentException(String.format(messageTemplate, messageArgs)); 66 } 67 } 68 69 /** 70 * Ensures that an string reference passed as a parameter to the calling 71 * method is not empty. 72 * 73 * @param string an string reference 74 * @return the string reference that was validated 75 * @throws IllegalArgumentException if {@code string} is empty 76 */ checkStringNotEmpty(final T string)77 public static @NonNull <T extends CharSequence> T checkStringNotEmpty(final T string) { 78 if (TextUtils.isEmpty(string)) { 79 throw new IllegalArgumentException(); 80 } 81 return string; 82 } 83 84 /** 85 * Ensures that an string reference passed as a parameter to the calling 86 * method is not empty. 87 * 88 * @param string an string reference 89 * @param errorMessage the exception message to use if the check fails; will 90 * be converted to a string using {@link String#valueOf(Object)} 91 * @return the string reference that was validated 92 * @throws IllegalArgumentException if {@code string} is empty 93 */ checkStringNotEmpty(final T string, final Object errorMessage)94 public static @NonNull <T extends CharSequence> T checkStringNotEmpty(final T string, 95 final Object errorMessage) { 96 if (TextUtils.isEmpty(string)) { 97 throw new IllegalArgumentException(String.valueOf(errorMessage)); 98 } 99 return string; 100 } 101 102 /** 103 * Ensures that an object reference passed as a parameter to the calling 104 * method is not null. 105 * 106 * @param reference an object reference 107 * @return the non-null reference that was validated 108 * @throws NullPointerException if {@code reference} is null 109 */ checkNotNull(final T reference)110 public static @NonNull <T> T checkNotNull(final T reference) { 111 if (reference == null) { 112 throw new NullPointerException(); 113 } 114 return reference; 115 } 116 117 /** 118 * Ensures that an object reference passed as a parameter to the calling 119 * method is not null. 120 * 121 * @param reference an object reference 122 * @param errorMessage the exception message to use if the check fails; will 123 * be converted to a string using {@link String#valueOf(Object)} 124 * @return the non-null reference that was validated 125 * @throws NullPointerException if {@code reference} is null 126 */ checkNotNull(final T reference, final Object errorMessage)127 public static @NonNull <T> T checkNotNull(final T reference, final Object errorMessage) { 128 if (reference == null) { 129 throw new NullPointerException(String.valueOf(errorMessage)); 130 } 131 return reference; 132 } 133 134 /** 135 * Ensures that an object reference passed as a parameter to the calling 136 * method is not null. 137 * 138 * @param reference an object reference 139 * @param messageTemplate a printf-style message template to use if the check fails; will 140 * be converted to a string using {@link String#format(String, Object...)} 141 * @param messageArgs arguments for {@code messageTemplate} 142 * @return the non-null reference that was validated 143 * @throws NullPointerException if {@code reference} is null 144 */ checkNotNull(final T reference, final String messageTemplate, final Object... messageArgs)145 public static @NonNull <T> T checkNotNull(final T reference, 146 final String messageTemplate, 147 final Object... messageArgs) { 148 if (reference == null) { 149 throw new NullPointerException(String.format(messageTemplate, messageArgs)); 150 } 151 return reference; 152 } 153 154 /** 155 * Ensures the truth of an expression involving the state of the calling 156 * instance, but not involving any parameters to the calling method. 157 * 158 * @param expression a boolean expression 159 * @param message exception message 160 * @throws IllegalStateException if {@code expression} is false 161 */ checkState(final boolean expression, String message)162 public static void checkState(final boolean expression, String message) { 163 if (!expression) { 164 throw new IllegalStateException(message); 165 } 166 } 167 168 /** 169 * Ensures the truth of an expression involving the state of the calling 170 * instance, but not involving any parameters to the calling method. 171 * 172 * @param expression a boolean expression 173 * @throws IllegalStateException if {@code expression} is false 174 */ checkState(final boolean expression)175 public static void checkState(final boolean expression) { 176 checkState(expression, null); 177 } 178 179 /** 180 * Check the requested flags, throwing if any requested flags are outside 181 * the allowed set. 182 * 183 * @return the validated requested flags. 184 */ checkFlagsArgument(final int requestedFlags, final int allowedFlags)185 public static int checkFlagsArgument(final int requestedFlags, final int allowedFlags) { 186 if ((requestedFlags & allowedFlags) != requestedFlags) { 187 throw new IllegalArgumentException("Requested flags 0x" 188 + Integer.toHexString(requestedFlags) + ", but only 0x" 189 + Integer.toHexString(allowedFlags) + " are allowed"); 190 } 191 192 return requestedFlags; 193 } 194 195 /** 196 * Ensures that that the argument numeric value is non-negative. 197 * 198 * @param value a numeric int value 199 * @param errorMessage the exception message to use if the check fails 200 * @return the validated numeric value 201 * @throws IllegalArgumentException if {@code value} was negative 202 */ checkArgumentNonnegative(final int value, final String errorMessage)203 public static @IntRange(from = 0) int checkArgumentNonnegative(final int value, 204 final String errorMessage) { 205 if (value < 0) { 206 throw new IllegalArgumentException(errorMessage); 207 } 208 209 return value; 210 } 211 212 /** 213 * Ensures that that the argument numeric value is non-negative. 214 * 215 * @param value a numeric int value 216 * 217 * @return the validated numeric value 218 * @throws IllegalArgumentException if {@code value} was negative 219 */ checkArgumentNonnegative(final int value)220 public static @IntRange(from = 0) int checkArgumentNonnegative(final int value) { 221 if (value < 0) { 222 throw new IllegalArgumentException(); 223 } 224 225 return value; 226 } 227 228 /** 229 * Ensures that that the argument numeric value is non-negative. 230 * 231 * @param value a numeric long value 232 * @return the validated numeric value 233 * @throws IllegalArgumentException if {@code value} was negative 234 */ checkArgumentNonnegative(final long value)235 public static long checkArgumentNonnegative(final long value) { 236 if (value < 0) { 237 throw new IllegalArgumentException(); 238 } 239 240 return value; 241 } 242 243 /** 244 * Ensures that that the argument numeric value is non-negative. 245 * 246 * @param value a numeric long value 247 * @param errorMessage the exception message to use if the check fails 248 * @return the validated numeric value 249 * @throws IllegalArgumentException if {@code value} was negative 250 */ checkArgumentNonnegative(final long value, final String errorMessage)251 public static long checkArgumentNonnegative(final long value, final String errorMessage) { 252 if (value < 0) { 253 throw new IllegalArgumentException(errorMessage); 254 } 255 256 return value; 257 } 258 259 /** 260 * Ensures that that the argument numeric value is positive. 261 * 262 * @param value a numeric int value 263 * @param errorMessage the exception message to use if the check fails 264 * @return the validated numeric value 265 * @throws IllegalArgumentException if {@code value} was not positive 266 */ checkArgumentPositive(final int value, final String errorMessage)267 public static int checkArgumentPositive(final int value, final String errorMessage) { 268 if (value <= 0) { 269 throw new IllegalArgumentException(errorMessage); 270 } 271 272 return value; 273 } 274 275 /** 276 * Ensures that the argument floating point value is a finite number. 277 * 278 * <p>A finite number is defined to be both representable (that is, not NaN) and 279 * not infinite (that is neither positive or negative infinity).</p> 280 * 281 * @param value a floating point value 282 * @param valueName the name of the argument to use if the check fails 283 * 284 * @return the validated floating point value 285 * 286 * @throws IllegalArgumentException if {@code value} was not finite 287 */ checkArgumentFinite(final float value, final String valueName)288 public static float checkArgumentFinite(final float value, final String valueName) { 289 if (Float.isNaN(value)) { 290 throw new IllegalArgumentException(valueName + " must not be NaN"); 291 } else if (Float.isInfinite(value)) { 292 throw new IllegalArgumentException(valueName + " must not be infinite"); 293 } 294 295 return value; 296 } 297 298 /** 299 * Ensures that the argument floating point value is within the inclusive range. 300 * 301 * <p>While this can be used to range check against +/- infinity, note that all NaN numbers 302 * will always be out of range.</p> 303 * 304 * @param value a floating point value 305 * @param lower the lower endpoint of the inclusive range 306 * @param upper the upper endpoint of the inclusive range 307 * @param valueName the name of the argument to use if the check fails 308 * 309 * @return the validated floating point value 310 * 311 * @throws IllegalArgumentException if {@code value} was not within the range 312 */ checkArgumentInRange(float value, float lower, float upper, String valueName)313 public static float checkArgumentInRange(float value, float lower, float upper, 314 String valueName) { 315 if (Float.isNaN(value)) { 316 throw new IllegalArgumentException(valueName + " must not be NaN"); 317 } else if (value < lower) { 318 throw new IllegalArgumentException( 319 String.format( 320 "%s is out of range of [%f, %f] (too low)", valueName, lower, upper)); 321 } else if (value > upper) { 322 throw new IllegalArgumentException( 323 String.format( 324 "%s is out of range of [%f, %f] (too high)", valueName, lower, upper)); 325 } 326 327 return value; 328 } 329 330 /** 331 * Ensures that the argument int value is within the inclusive range. 332 * 333 * @param value a int value 334 * @param lower the lower endpoint of the inclusive range 335 * @param upper the upper endpoint of the inclusive range 336 * @param valueName the name of the argument to use if the check fails 337 * 338 * @return the validated int value 339 * 340 * @throws IllegalArgumentException if {@code value} was not within the range 341 */ checkArgumentInRange(int value, int lower, int upper, String valueName)342 public static int checkArgumentInRange(int value, int lower, int upper, 343 String valueName) { 344 if (value < lower) { 345 throw new IllegalArgumentException( 346 String.format( 347 "%s is out of range of [%d, %d] (too low)", valueName, lower, upper)); 348 } else if (value > upper) { 349 throw new IllegalArgumentException( 350 String.format( 351 "%s is out of range of [%d, %d] (too high)", valueName, lower, upper)); 352 } 353 354 return value; 355 } 356 357 /** 358 * Ensures that the argument long value is within the inclusive range. 359 * 360 * @param value a long value 361 * @param lower the lower endpoint of the inclusive range 362 * @param upper the upper endpoint of the inclusive range 363 * @param valueName the name of the argument to use if the check fails 364 * 365 * @return the validated long value 366 * 367 * @throws IllegalArgumentException if {@code value} was not within the range 368 */ checkArgumentInRange(long value, long lower, long upper, String valueName)369 public static long checkArgumentInRange(long value, long lower, long upper, 370 String valueName) { 371 if (value < lower) { 372 throw new IllegalArgumentException( 373 String.format( 374 "%s is out of range of [%d, %d] (too low)", valueName, lower, upper)); 375 } else if (value > upper) { 376 throw new IllegalArgumentException( 377 String.format( 378 "%s is out of range of [%d, %d] (too high)", valueName, lower, upper)); 379 } 380 381 return value; 382 } 383 384 /** 385 * Ensures that the array is not {@code null}, and none of its elements are {@code null}. 386 * 387 * @param value an array of boxed objects 388 * @param valueName the name of the argument to use if the check fails 389 * 390 * @return the validated array 391 * 392 * @throws NullPointerException if the {@code value} or any of its elements were {@code null} 393 */ checkArrayElementsNotNull(final T[] value, final String valueName)394 public static <T> T[] checkArrayElementsNotNull(final T[] value, final String valueName) { 395 if (value == null) { 396 throw new NullPointerException(valueName + " must not be null"); 397 } 398 399 for (int i = 0; i < value.length; ++i) { 400 if (value[i] == null) { 401 throw new NullPointerException( 402 String.format("%s[%d] must not be null", valueName, i)); 403 } 404 } 405 406 return value; 407 } 408 409 /** 410 * Ensures that the {@link Collection} is not {@code null}, and none of its elements are 411 * {@code null}. 412 * 413 * @param value a {@link Collection} of boxed objects 414 * @param valueName the name of the argument to use if the check fails 415 * 416 * @return the validated {@link Collection} 417 * 418 * @throws NullPointerException if the {@code value} or any of its elements were {@code null} 419 */ checkCollectionElementsNotNull( final C value, final String valueName)420 public static @NonNull <C extends Collection<T>, T> C checkCollectionElementsNotNull( 421 final C value, final String valueName) { 422 if (value == null) { 423 throw new NullPointerException(valueName + " must not be null"); 424 } 425 426 long ctr = 0; 427 for (T elem : value) { 428 if (elem == null) { 429 throw new NullPointerException( 430 String.format("%s[%d] must not be null", valueName, ctr)); 431 } 432 ++ctr; 433 } 434 435 return value; 436 } 437 438 /** 439 * Ensures that the {@link Collection} is not {@code null}, and contains at least one element. 440 * 441 * @param value a {@link Collection} of boxed elements. 442 * @param valueName the name of the argument to use if the check fails. 443 444 * @return the validated {@link Collection} 445 * 446 * @throws NullPointerException if the {@code value} was {@code null} 447 * @throws IllegalArgumentException if the {@code value} was empty 448 */ checkCollectionNotEmpty(final Collection<T> value, final String valueName)449 public static <T> Collection<T> checkCollectionNotEmpty(final Collection<T> value, 450 final String valueName) { 451 if (value == null) { 452 throw new NullPointerException(valueName + " must not be null"); 453 } 454 if (value.isEmpty()) { 455 throw new IllegalArgumentException(valueName + " is empty"); 456 } 457 return value; 458 } 459 460 /** 461 * Ensures that all elements in the argument floating point array are within the inclusive range 462 * 463 * <p>While this can be used to range check against +/- infinity, note that all NaN numbers 464 * will always be out of range.</p> 465 * 466 * @param value a floating point array of values 467 * @param lower the lower endpoint of the inclusive range 468 * @param upper the upper endpoint of the inclusive range 469 * @param valueName the name of the argument to use if the check fails 470 * 471 * @return the validated floating point value 472 * 473 * @throws IllegalArgumentException if any of the elements in {@code value} were out of range 474 * @throws NullPointerException if the {@code value} was {@code null} 475 */ checkArrayElementsInRange(float[] value, float lower, float upper, String valueName)476 public static float[] checkArrayElementsInRange(float[] value, float lower, float upper, 477 String valueName) { 478 checkNotNull(value, valueName + " must not be null"); 479 480 for (int i = 0; i < value.length; ++i) { 481 float v = value[i]; 482 483 if (Float.isNaN(v)) { 484 throw new IllegalArgumentException(valueName + "[" + i + "] must not be NaN"); 485 } else if (v < lower) { 486 throw new IllegalArgumentException( 487 String.format("%s[%d] is out of range of [%f, %f] (too low)", 488 valueName, i, lower, upper)); 489 } else if (v > upper) { 490 throw new IllegalArgumentException( 491 String.format("%s[%d] is out of range of [%f, %f] (too high)", 492 valueName, i, lower, upper)); 493 } 494 } 495 496 return value; 497 } 498 499 /** 500 * Ensures that all elements in the argument integer array are within the inclusive range 501 * 502 * @param value an integer array of values 503 * @param lower the lower endpoint of the inclusive range 504 * @param upper the upper endpoint of the inclusive range 505 * @param valueName the name of the argument to use if the check fails 506 * 507 * @return the validated integer array 508 * 509 * @throws IllegalArgumentException if any of the elements in {@code value} were out of range 510 * @throws NullPointerException if the {@code value} was {@code null} 511 */ checkArrayElementsInRange(int[] value, int lower, int upper, String valueName)512 public static int[] checkArrayElementsInRange(int[] value, int lower, int upper, 513 String valueName) { 514 checkNotNull(value, valueName + " must not be null"); 515 516 for (int i = 0; i < value.length; ++i) { 517 int v = value[i]; 518 519 if (v < lower) { 520 throw new IllegalArgumentException( 521 String.format("%s[%d] is out of range of [%d, %d] (too low)", 522 valueName, i, lower, upper)); 523 } else if (v > upper) { 524 throw new IllegalArgumentException( 525 String.format("%s[%d] is out of range of [%d, %d] (too high)", 526 valueName, i, lower, upper)); 527 } 528 } 529 530 return value; 531 } 532 } 533