1 /* 2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 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 * A copy of the License is located at 7 * 8 * http://aws.amazon.com/apache2.0 9 * 10 * or in the "license" file accompanying this file. This file is distributed 11 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 * express or implied. See the License for the specific language governing 13 * permissions and limitations under the License. 14 */ 15 16 package software.amazon.awssdk.utils; 17 18 import java.time.Duration; 19 import java.util.Collection; 20 import java.util.Iterator; 21 import java.util.Map; 22 import java.util.function.Predicate; 23 import java.util.function.Supplier; 24 import software.amazon.awssdk.annotations.SdkProtectedApi; 25 26 /** 27 * <p>This class assists in validating arguments. The validation methods are 28 * based along the following principles: 29 * <ul> 30 * <li>An invalid {@code null} argument causes a {@link NullPointerException}.</li> 31 * <li>A non-{@code null} argument causes an {@link IllegalArgumentException}.</li> 32 * <li>An invalid index into an array/collection/map/string causes an {@link IndexOutOfBoundsException}.</li> 33 * </ul> 34 * 35 * <p>All exceptions messages are 36 * <a href="http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Formatter.html#syntax">format strings</a> 37 * as defined by the Java platform. For example:</p> 38 * 39 * <pre> 40 * Validate.isTrue(i > 0, "The value must be greater than zero: %d", i); 41 * Validate.notNull(surname, "The surname must not be %s", null); 42 * </pre> 43 * 44 * <p>This class's source was modified from the Apache commons-lang library: https://github.com/apache/commons-lang/</p> 45 * 46 * <p>#ThreadSafe#</p> 47 * @see java.lang.String#format(String, Object...) 48 */ 49 @SdkProtectedApi 50 public final class Validate { 51 private static final String DEFAULT_IS_NULL_EX_MESSAGE = "The validated object is null"; 52 Validate()53 private Validate() { 54 } 55 56 // isTrue 57 //--------------------------------------------------------------------------------- 58 59 /** 60 * <p>Validate that the argument condition is {@code true}; otherwise 61 * throwing an exception with the specified message. This method is useful when 62 * validating according to an arbitrary boolean expression, such as validating a 63 * primitive number or using your own custom validation expression.</p> 64 * 65 * <pre> 66 * Validate.isTrue(i >= min && i <= max, "The value must be between %d and %d", min, max); 67 * Validate.isTrue(myObject.isOk(), "The object is not okay");</pre> 68 * 69 * @param expression the boolean expression to check 70 * @param message the {@link String#format(String, Object...)} exception message if invalid, not null 71 * @param values the optional values for the formatted exception message, null array not recommended 72 * @throws IllegalArgumentException if expression is {@code false} 73 */ isTrue(final boolean expression, final String message, final Object... values)74 public static void isTrue(final boolean expression, final String message, final Object... values) { 75 if (!expression) { 76 throw new IllegalArgumentException(String.format(message, values)); 77 } 78 } 79 80 // isFalse 81 //--------------------------------------------------------------------------------- 82 83 /** 84 * <p>Validate that the argument condition is {@code false}; otherwise 85 * throwing an exception with the specified message. This method is useful when 86 * validating according to an arbitrary boolean expression, such as validating a 87 * primitive number or using your own custom validation expression.</p> 88 * 89 * <pre> 90 * Validate.isFalse(myObject.permitsSomething(), "The object is not allowed to permit something");</pre> 91 * 92 * @param expression the boolean expression to check 93 * @param message the {@link String#format(String, Object...)} exception message if not false, not null 94 * @param values the optional values for the formatted exception message, null array not recommended 95 * @throws IllegalArgumentException if expression is {@code true} 96 */ isFalse(final boolean expression, final String message, final Object... values)97 public static void isFalse(final boolean expression, final String message, final Object... values) { 98 isTrue(!expression, message, values); 99 } 100 101 // notNull 102 //--------------------------------------------------------------------------------- 103 104 /** 105 * <p>Validate that the specified argument is not {@code null}; 106 * otherwise throwing an exception with the specified message. 107 * 108 * <pre>Validate.notNull(myObject, "The object must not be null");</pre> 109 * 110 * @param <T> the object type 111 * @param object the object to check 112 * @param message the {@link String#format(String, Object...)} exception message if invalid, not null 113 * @param values the optional values for the formatted exception message 114 * @return the validated object (never {@code null} for method chaining) 115 * @throws NullPointerException if the object is {@code null} 116 */ notNull(final T object, final String message, final Object... values)117 public static <T> T notNull(final T object, final String message, final Object... values) { 118 if (object == null) { 119 throw new NullPointerException(String.format(message, values)); 120 } 121 return object; 122 } 123 124 /** 125 * <p>Validate that the specified argument is {@code null}; 126 * otherwise throwing an exception with the specified message. 127 * 128 * <pre>Validate.isNull(myObject, "The object must be null");</pre> 129 * 130 * @param <T> the object type 131 * @param object the object to check 132 * @param message the {@link String#format(String, Object...)} exception message if invalid, not null 133 * @param values the optional values for the formatted exception message 134 * @throws IllegalArgumentException if the object is not {@code null} 135 */ isNull(final T object, final String message, final Object... values)136 public static <T> void isNull(final T object, final String message, final Object... values) { 137 if (object != null) { 138 throw new IllegalArgumentException(String.format(message, values)); 139 } 140 } 141 142 /** 143 * <p>Validate that the specified field/param is not {@code null}; 144 * otherwise throwing an exception with a precanned message that includes the parameter name. 145 * 146 * <pre>Validate.paramNotNull(myObject, "myObject");</pre> 147 * 148 * @param <T> the object type 149 * @param object the object to check 150 * @param paramName The name of the param or field being checked. 151 * @return the validated object (never {@code null} for method chaining) 152 * @throws NullPointerException if the object is {@code null} 153 */ paramNotNull(final T object, final String paramName)154 public static <T> T paramNotNull(final T object, final String paramName) { 155 if (object == null) { 156 throw new NullPointerException(String.format("%s must not be null.", paramName)); 157 } 158 return object; 159 } 160 161 /** 162 * <p>Validate that the specified char sequence is neither 163 * {@code null}, a length of zero (no characters), empty nor 164 * whitespace; otherwise throwing an exception with the specified 165 * message. 166 * 167 * <pre>Validate.paramNotBlank(myCharSequence, "myCharSequence");</pre> 168 * 169 * @param <T> the char sequence type 170 * @param chars the character sequence to check 171 * @param paramName The name of the param or field being checked. 172 * @return the validated char sequence (never {@code null} for method chaining) 173 * @throws NullPointerException if the char sequence is {@code null} 174 */ paramNotBlank(final T chars, final String paramName)175 public static <T extends CharSequence> T paramNotBlank(final T chars, final String paramName) { 176 if (chars == null) { 177 throw new NullPointerException(String.format("%s must not be null.", paramName)); 178 } 179 if (StringUtils.isBlank(chars)) { 180 throw new IllegalArgumentException(String.format("%s must not be blank or empty.", paramName)); 181 } 182 return chars; 183 } 184 185 /** 186 * <p>Validate the stateful predicate is true for the given object and return the object; 187 * otherwise throw an exception with the specified message.</p> 188 * 189 * {@code String value = Validate.validState(someString, s -> s.length() == 0, "must be blank got: %s", someString);} 190 * 191 * 192 * @param <T> the object type 193 * @param object the object to check 194 * @param test the predicate to apply, will return true if the object is valid 195 * @param message the {@link String#format(String, Object...)} exception message if invalid, not null 196 * @param values the optional values for the formatted exception message 197 * @return the validated object 198 * @throws NullPointerException if the object is {@code null} 199 */ validState(final T object, final Predicate<T> test, final String message, final Object... values)200 public static <T> T validState(final T object, final Predicate<T> test, final String message, final Object... values) { 201 if (!test.test(object)) { 202 throw new IllegalStateException(String.format(message, values)); 203 } 204 return object; 205 } 206 207 // notEmpty array 208 //--------------------------------------------------------------------------------- 209 210 /** 211 * <p>Validate that the specified argument array is neither {@code null} 212 * nor a length of zero (no elements); otherwise throwing an exception 213 * with the specified message. 214 * 215 * <pre>Validate.notEmpty(myArray, "The array must not be empty");</pre> 216 * 217 * @param <T> the array type 218 * @param array the array to check, validated not null by this method 219 * @param message the {@link String#format(String, Object...)} exception message if invalid, not null 220 * @param values the optional values for the formatted exception message, null array not recommended 221 * @return the validated array (never {@code null} method for chaining) 222 * @throws NullPointerException if the array is {@code null} 223 * @throws IllegalArgumentException if the array is empty 224 */ notEmpty(final T[] array, final String message, final Object... values)225 public static <T> T[] notEmpty(final T[] array, final String message, final Object... values) { 226 if (array == null) { 227 throw new NullPointerException(String.format(message, values)); 228 } 229 if (array.length == 0) { 230 throw new IllegalArgumentException(String.format(message, values)); 231 } 232 return array; 233 } 234 235 // notEmpty collection 236 //--------------------------------------------------------------------------------- 237 238 /** 239 * <p>Validate that the specified argument collection is neither {@code null} 240 * nor a size of zero (no elements); otherwise throwing an exception 241 * with the specified message. 242 * 243 * <pre>Validate.notEmpty(myCollection, "The collection must not be empty");</pre> 244 * 245 * @param <T> the collection type 246 * @param collection the collection to check, validated not null by this method 247 * @param message the {@link String#format(String, Object...)} exception message if invalid, not null 248 * @param values the optional values for the formatted exception message, null array not recommended 249 * @return the validated collection (never {@code null} method for chaining) 250 * @throws NullPointerException if the collection is {@code null} 251 * @throws IllegalArgumentException if the collection is empty 252 */ notEmpty(final T collection, final String message, final Object... values)253 public static <T extends Collection<?>> T notEmpty(final T collection, final String message, final Object... values) { 254 if (collection == null) { 255 throw new NullPointerException(String.format(message, values)); 256 } 257 if (collection.isEmpty()) { 258 throw new IllegalArgumentException(String.format(message, values)); 259 } 260 return collection; 261 } 262 263 // notEmpty map 264 //--------------------------------------------------------------------------------- 265 266 /** 267 * <p>Validate that the specified argument map is neither {@code null} 268 * nor a size of zero (no elements); otherwise throwing an exception 269 * with the specified message. 270 * 271 * <pre>Validate.notEmpty(myMap, "The map must not be empty");</pre> 272 * 273 * @param <T> the map type 274 * @param map the map to check, validated not null by this method 275 * @param message the {@link String#format(String, Object...)} exception message if invalid, not null 276 * @param values the optional values for the formatted exception message, null array not recommended 277 * @return the validated map (never {@code null} method for chaining) 278 * @throws NullPointerException if the map is {@code null} 279 * @throws IllegalArgumentException if the map is empty 280 */ notEmpty(final T map, final String message, final Object... values)281 public static <T extends Map<?, ?>> T notEmpty(final T map, final String message, final Object... values) { 282 if (map == null) { 283 throw new NullPointerException(String.format(message, values)); 284 } 285 if (map.isEmpty()) { 286 throw new IllegalArgumentException(String.format(message, values)); 287 } 288 return map; 289 } 290 291 // notEmpty string 292 //--------------------------------------------------------------------------------- 293 294 /** 295 * <p>Validate that the specified argument character sequence is 296 * neither {@code null} nor a length of zero (no characters); 297 * otherwise throwing an exception with the specified message. 298 * 299 * <pre>Validate.notEmpty(myString, "The string must not be empty");</pre> 300 * 301 * @param <T> the character sequence type 302 * @param chars the character sequence to check, validated not null by this method 303 * @param message the {@link String#format(String, Object...)} exception message if invalid, not null 304 * @param values the optional values for the formatted exception message, null array not recommended 305 * @return the validated character sequence (never {@code null} method for chaining) 306 * @throws NullPointerException if the character sequence is {@code null} 307 * @throws IllegalArgumentException if the character sequence is empty 308 */ notEmpty(final T chars, final String message, final Object... values)309 public static <T extends CharSequence> T notEmpty(final T chars, final String message, final Object... values) { 310 if (chars == null) { 311 throw new NullPointerException(String.format(message, values)); 312 } 313 if (chars.length() == 0) { 314 throw new IllegalArgumentException(String.format(message, values)); 315 } 316 return chars; 317 } 318 319 // notBlank string 320 //--------------------------------------------------------------------------------- 321 322 /** 323 * <p>Validate that the specified argument character sequence is 324 * neither {@code null}, a length of zero (no characters), empty 325 * nor whitespace; otherwise throwing an exception with the specified 326 * message. 327 * 328 * <pre>Validate.notBlank(myString, "The string must not be blank");</pre> 329 * 330 * @param <T> the character sequence type 331 * @param chars the character sequence to check, validated not null by this method 332 * @param message the {@link String#format(String, Object...)} exception message if invalid, not null 333 * @param values the optional values for the formatted exception message, null array not recommended 334 * @return the validated character sequence (never {@code null} method for chaining) 335 * @throws NullPointerException if the character sequence is {@code null} 336 * @throws IllegalArgumentException if the character sequence is blank 337 */ notBlank(final T chars, final String message, final Object... values)338 public static <T extends CharSequence> T notBlank(final T chars, final String message, final Object... values) { 339 if (chars == null) { 340 throw new NullPointerException(String.format(message, values)); 341 } 342 if (StringUtils.isBlank(chars)) { 343 throw new IllegalArgumentException(String.format(message, values)); 344 } 345 return chars; 346 } 347 348 // noNullElements array 349 //--------------------------------------------------------------------------------- 350 351 /** 352 * <p>Validate that the specified argument array is neither 353 * {@code null} nor contains any elements that are {@code null}; 354 * otherwise throwing an exception with the specified message. 355 * 356 * <pre>Validate.noNullElements(myArray, "The array is null or contains null.");</pre> 357 * 358 * @param <T> the array type 359 * @param array the array to check, validated not null by this method 360 * @param message the {@link String#format(String, Object...)} exception message if invalid, not null 361 * @param values the optional values for the formatted exception message 362 * @return the validated array (never {@code null} method for chaining) 363 * @throws NullPointerException if the array is {@code null} 364 * @throws IllegalArgumentException if an element is {@code null} 365 */ noNullElements(final T[] array, final String message, final Object... values)366 public static <T> T[] noNullElements(final T[] array, final String message, final Object... values) { 367 Validate.notNull(array, message); 368 for (T anArray : array) { 369 if (anArray == null) { 370 throw new IllegalArgumentException(String.format(message, values)); 371 } 372 } 373 return array; 374 } 375 376 // noNullElements iterable 377 //--------------------------------------------------------------------------------- 378 379 /** 380 * <p>Validate that the specified argument iterable is neither 381 * {@code null} nor contains any elements that are {@code null}; 382 * otherwise throwing an exception with the specified message. 383 * 384 * <pre>Validate.noNullElements(myCollection, "The collection is null or contains null.");</pre> 385 * 386 * @param <T> the iterable type 387 * @param iterable the iterable to check, validated not null by this method 388 * @param message the {@link String#format(String, Object...)} exception message if invalid, not null 389 * @param values the optional values for the formatted exception message. 390 * @return the validated iterable (never {@code null} method for chaining) 391 * @throws NullPointerException if the array is {@code null} 392 * @throws IllegalArgumentException if an element is {@code null} 393 */ noNullElements(final T iterable, final String message, final Object... values)394 public static <T extends Iterable<?>> T noNullElements(final T iterable, final String message, final Object... values) { 395 Validate.notNull(iterable, DEFAULT_IS_NULL_EX_MESSAGE); 396 int i = 0; 397 for (Iterator<?> it = iterable.iterator(); it.hasNext(); i++) { 398 if (it.next() == null) { 399 throw new IllegalArgumentException(String.format(message, values)); 400 } 401 } 402 return iterable; 403 } 404 405 // validState 406 //--------------------------------------------------------------------------------- 407 408 /** 409 * <p>Validate that the stateful condition is {@code true}; otherwise 410 * throwing an exception with the specified message. This method is useful when 411 * validating according to an arbitrary boolean expression, such as validating a 412 * primitive number or using your own custom validation expression.</p> 413 * 414 * <pre>Validate.validState(this.isOk(), "The state is not OK: %s", myObject);</pre> 415 * 416 * @param expression the boolean expression to check 417 * @param message the {@link String#format(String, Object...)} exception message if invalid, not null 418 * @param values the optional values for the formatted exception message, null array not recommended 419 * @throws IllegalStateException if expression is {@code false} 420 */ validState(final boolean expression, final String message, final Object... values)421 public static void validState(final boolean expression, final String message, final Object... values) { 422 if (!expression) { 423 throw new IllegalStateException(String.format(message, values)); 424 } 425 } 426 427 // inclusiveBetween 428 //--------------------------------------------------------------------------------- 429 430 /** 431 * <p>Validate that the specified argument object fall between the two 432 * inclusive values specified; otherwise, throws an exception with the 433 * specified message.</p> 434 * 435 * <pre>Validate.inclusiveBetween(0, 2, 1, "Not in boundaries");</pre> 436 * 437 * @param <T> the type of the argument object 438 * @param start the inclusive start value, not null 439 * @param end the inclusive end value, not null 440 * @param value the object to validate, not null 441 * @param message the {@link String#format(String, Object...)} exception message if invalid, not null 442 * @param values the optional values for the formatted exception message, null array not recommended 443 * @throws IllegalArgumentException if the value falls outside the boundaries 444 */ inclusiveBetween(final U start, final U end, final T value, final String message, final Object... values)445 public static <T extends Comparable<U>, U> T inclusiveBetween(final U start, final U end, final T value, 446 final String message, final Object... values) { 447 if (value.compareTo(start) < 0 || value.compareTo(end) > 0) { 448 throw new IllegalArgumentException(String.format(message, values)); 449 } 450 return value; 451 } 452 453 /** 454 * Validate that the specified primitive value falls between the two 455 * inclusive values specified; otherwise, throws an exception with the 456 * specified message. 457 * 458 * <pre>Validate.inclusiveBetween(0, 2, 1, "Not in range");</pre> 459 * 460 * @param start the inclusive start value 461 * @param end the inclusive end value 462 * @param value the value to validate 463 * @param message the exception message if invalid, not null 464 * 465 * @throws IllegalArgumentException if the value falls outside the boundaries 466 */ inclusiveBetween(final long start, final long end, final long value, final String message)467 public static long inclusiveBetween(final long start, final long end, final long value, final String message) { 468 if (value < start || value > end) { 469 throw new IllegalArgumentException(message); 470 } 471 return value; 472 } 473 474 /** 475 * Validate that the specified primitive value falls between the two 476 * inclusive values specified; otherwise, throws an exception with the 477 * specified message. 478 * 479 * <pre>Validate.inclusiveBetween(0.1, 2.1, 1.1, "Not in range");</pre> 480 * 481 * @param start the inclusive start value 482 * @param end the inclusive end value 483 * @param value the value to validate 484 * @param message the exception message if invalid, not null 485 * 486 * @throws IllegalArgumentException if the value falls outside the boundaries 487 */ inclusiveBetween(final double start, final double end, final double value, final String message)488 public static double inclusiveBetween(final double start, final double end, final double value, final String message) { 489 if (value < start || value > end) { 490 throw new IllegalArgumentException(message); 491 } 492 return value; 493 } 494 495 // exclusiveBetween 496 //--------------------------------------------------------------------------------- 497 498 /** 499 * <p>Validate that the specified argument object fall between the two 500 * exclusive values specified; otherwise, throws an exception with the 501 * specified message.</p> 502 * 503 * <pre>Validate.exclusiveBetween(0, 2, 1, "Not in boundaries");</pre> 504 * 505 * @param <T> the type of the argument object 506 * @param start the exclusive start value, not null 507 * @param end the exclusive end value, not null 508 * @param value the object to validate, not null 509 * @param message the {@link String#format(String, Object...)} exception message if invalid, not null 510 * @param values the optional values for the formatted exception message, null array not recommended 511 * @throws IllegalArgumentException if the value falls outside the boundaries 512 */ exclusiveBetween(final U start, final U end, final T value, final String message, final Object... values)513 public static <T extends Comparable<U>, U> T exclusiveBetween(final U start, final U end, final T value, 514 final String message, final Object... values) { 515 if (value.compareTo(start) <= 0 || value.compareTo(end) >= 0) { 516 throw new IllegalArgumentException(String.format(message, values)); 517 } 518 return value; 519 } 520 521 /** 522 * Validate that the specified primitive value falls between the two 523 * exclusive values specified; otherwise, throws an exception with the 524 * specified message. 525 * 526 * <pre>Validate.exclusiveBetween(0, 2, 1, "Not in range");</pre> 527 * 528 * @param start the exclusive start value 529 * @param end the exclusive end value 530 * @param value the value to validate 531 * @param message the exception message if invalid, not null 532 * 533 * @throws IllegalArgumentException if the value falls outside the boundaries 534 */ exclusiveBetween(final long start, final long end, final long value, final String message)535 public static long exclusiveBetween(final long start, final long end, final long value, final String message) { 536 if (value <= start || value >= end) { 537 throw new IllegalArgumentException(message); 538 } 539 return value; 540 } 541 542 /** 543 * Validate that the specified primitive value falls between the two 544 * exclusive values specified; otherwise, throws an exception with the 545 * specified message. 546 * 547 * <pre>Validate.exclusiveBetween(0.1, 2.1, 1.1, "Not in range");</pre> 548 * 549 * @param start the exclusive start value 550 * @param end the exclusive end value 551 * @param value the value to validate 552 * @param message the exception message if invalid, not null 553 * 554 * @throws IllegalArgumentException if the value falls outside the boundaries 555 */ exclusiveBetween(final double start, final double end, final double value, final String message)556 public static double exclusiveBetween(final double start, final double end, final double value, final String message) { 557 if (value <= start || value >= end) { 558 throw new IllegalArgumentException(message); 559 } 560 return value; 561 } 562 563 // isInstanceOf 564 //--------------------------------------------------------------------------------- 565 566 /** 567 * <p>Validate that the argument is an instance of the specified class; otherwise 568 * throwing an exception with the specified message. This method is useful when 569 * validating according to an arbitrary class</p> 570 * 571 * <pre>Validate.isInstanceOf(OkClass.class, object, "Wrong class, object is of class %s", 572 * object.getClass().getName());</pre> 573 * 574 * @param type the class the object must be validated against, not null 575 * @param obj the object to check, null throws an exception 576 * @param message the {@link String#format(String, Object...)} exception message if invalid, not null 577 * @param values the optional values for the formatted exception message, null array not recommended 578 * @throws IllegalArgumentException if argument is not of specified class 579 */ isInstanceOf(final Class<U> type, final T obj, final String message, final Object... values)580 public static <T, U> U isInstanceOf(final Class<U> type, final T obj, final String message, final Object... values) { 581 if (!type.isInstance(obj)) { 582 throw new IllegalArgumentException(String.format(message, values)); 583 } 584 return type.cast(obj); 585 } 586 587 // isAssignableFrom 588 //--------------------------------------------------------------------------------- 589 590 /** 591 * Validates that the argument can be converted to the specified class, if not throws an exception. 592 * 593 * <p>This method is useful when validating if there will be no casting errors.</p> 594 * 595 * <pre>Validate.isAssignableFrom(SuperClass.class, object.getClass());</pre> 596 * 597 * <p>The message of the exception is "The validated object can not be converted to the" 598 * followed by the name of the class and "class"</p> 599 * 600 * @param superType the class the class must be validated against, not null 601 * @param type the class to check, not null 602 * @param message the {@link String#format(String, Object...)} exception message if invalid, not null 603 * @param values the optional values for the formatted exception message, null array not recommended 604 * @throws IllegalArgumentException if argument can not be converted to the specified class 605 */ isAssignableFrom(final Class<T> superType, final Class<?> type, final String message, final Object... values)606 public static <T> Class<? extends T> isAssignableFrom(final Class<T> superType, final Class<?> type, 607 final String message, final Object... values) { 608 if (!superType.isAssignableFrom(type)) { 609 throw new IllegalArgumentException(String.format(message, values)); 610 } 611 612 return (Class<? extends T>) type; 613 } 614 615 /** 616 * Asserts that the given number is positive (non-negative and non-zero). 617 * 618 * @param num Number to validate 619 * @param fieldName Field name to display in exception message if not positive. 620 * @return Number if positive. 621 */ isPositive(int num, String fieldName)622 public static int isPositive(int num, String fieldName) { 623 if (num <= 0) { 624 throw new IllegalArgumentException(String.format("%s must be positive", fieldName)); 625 } 626 return num; 627 } 628 629 /** 630 * Asserts that the given number is positive (non-negative and non-zero). 631 * 632 * @param num Number to validate 633 * @param fieldName Field name to display in exception message if not positive. 634 * @return Number if positive. 635 */ isPositive(long num, String fieldName)636 public static long isPositive(long num, String fieldName) { 637 if (num <= 0) { 638 throw new IllegalArgumentException(String.format("%s must be positive", fieldName)); 639 } 640 return num; 641 } 642 isPositive(double num, String fieldName)643 public static double isPositive(double num, String fieldName) { 644 if (num <= 0) { 645 throw new IllegalArgumentException(String.format("%s must be positive", fieldName)); 646 } 647 return num; 648 } 649 isNotNegative(int num, String fieldName)650 public static int isNotNegative(int num, String fieldName) { 651 652 if (num < 0) { 653 throw new IllegalArgumentException(String.format("%s must not be negative", fieldName)); 654 } 655 656 return num; 657 } 658 isNotNegativeOrNull(Long num, String fieldName)659 public static Long isNotNegativeOrNull(Long num, String fieldName) { 660 661 if (num == null) { 662 return null; 663 } 664 665 if (num < 0) { 666 throw new IllegalArgumentException(String.format("%s must not be negative", fieldName)); 667 } 668 669 return num; 670 } 671 isNotNegative(long num, String fieldName)672 public static long isNotNegative(long num, String fieldName) { 673 674 if (num < 0) { 675 throw new IllegalArgumentException(String.format("%s must not be negative", fieldName)); 676 } 677 678 return num; 679 } 680 681 /** 682 * Asserts that the given duration is positive (non-negative and non-zero). 683 * 684 * @param duration Number to validate 685 * @param fieldName Field name to display in exception message if not positive. 686 * @return Duration if positive. 687 */ isPositive(Duration duration, String fieldName)688 public static Duration isPositive(Duration duration, String fieldName) { 689 if (duration == null) { 690 throw new IllegalArgumentException(String.format("%s cannot be null", fieldName)); 691 } 692 693 if (duration.isNegative() || duration.isZero()) { 694 throw new IllegalArgumentException(String.format("%s must be positive", fieldName)); 695 } 696 return duration; 697 } 698 699 /** 700 * Asserts that the given duration is positive (non-negative and non-zero) or null. 701 * 702 * @param duration Number to validate 703 * @param fieldName Field name to display in exception message if not positive. 704 * @return Duration if positive or null. 705 */ isPositiveOrNull(Duration duration, String fieldName)706 public static Duration isPositiveOrNull(Duration duration, String fieldName) { 707 if (duration == null) { 708 return null; 709 } 710 711 return isPositive(duration, fieldName); 712 } 713 714 /** 715 * Asserts that the given boxed integer is positive (non-negative and non-zero) or null. 716 * 717 * @param num Boxed integer to validate 718 * @param fieldName Field name to display in exception message if not positive. 719 * @return Duration if positive or null. 720 */ isPositiveOrNull(Integer num, String fieldName)721 public static Integer isPositiveOrNull(Integer num, String fieldName) { 722 if (num == null) { 723 return null; 724 } 725 726 return isPositive(num, fieldName); 727 } 728 729 /** 730 * Asserts that the given boxed double is positive (non-negative and non-zero) or null. 731 * 732 * @param num Boxed double to validate 733 * @param fieldName Field name to display in exception message if not positive. 734 * @return Duration if double or null. 735 */ isPositiveOrNull(Double num, String fieldName)736 public static Double isPositiveOrNull(Double num, String fieldName) { 737 if (num == null) { 738 return null; 739 } 740 741 return isPositive(num, fieldName); 742 } 743 744 /** 745 * Asserts that the given boxed long is positive (non-negative and non-zero) or null. 746 * 747 * @param num Boxed long to validate 748 * @param fieldName Field name to display in exception message if not positive. 749 * @return Duration if positive or null. 750 */ isPositiveOrNull(Long num, String fieldName)751 public static Long isPositiveOrNull(Long num, String fieldName) { 752 if (num == null) { 753 return null; 754 } 755 756 return isPositive(num, fieldName); 757 } 758 759 /** 760 * Asserts that the given duration is positive, including zero. 761 * 762 * @param duration Number to validate 763 * @param fieldName Field name to display in exception message if not positive. 764 * @return Duration if positive or zero. 765 */ isNotNegative(Duration duration, String fieldName)766 public static Duration isNotNegative(Duration duration, String fieldName) { 767 if (duration == null) { 768 throw new IllegalArgumentException(String.format("%s cannot be null", fieldName)); 769 } 770 771 if (duration.isNegative()) { 772 throw new IllegalArgumentException(String.format("%s must not be negative", fieldName)); 773 } 774 775 return duration; 776 } 777 778 /** 779 * Returns the param if non null, otherwise gets a default value from the provided {@link Supplier}. 780 * 781 * @param param Param to return if non null. 782 * @param defaultValue Supplier of default value. 783 * @param <T> Type of value. 784 * @return Value of param or default value if param was null. 785 */ getOrDefault(T param, Supplier<T> defaultValue)786 public static <T> T getOrDefault(T param, Supplier<T> defaultValue) { 787 paramNotNull(defaultValue, "defaultValue"); 788 return param != null ? param : defaultValue.get(); 789 } 790 791 /** 792 * Verify that only one of the objects is non null. If all objects are null this method 793 * does not throw. 794 * 795 * @param message Error message if more than one object is non-null. 796 * @param objs Objects to validate. 797 * @throws IllegalArgumentException if more than one of the objects was non-null. 798 */ mutuallyExclusive(String message, Object... objs)799 public static void mutuallyExclusive(String message, Object... objs) { 800 boolean oneProvided = false; 801 for (Object o : objs) { 802 if (o != null) { 803 if (oneProvided) { 804 throw new IllegalArgumentException(message); 805 } else { 806 oneProvided = true; 807 } 808 } 809 } 810 } 811 } 812