xref: /aosp_15_r20/external/aws-sdk-java-v2/utils/src/main/java/software/amazon/awssdk/utils/Validate.java (revision 8a52c7834d808308836a99fc2a6e0ed8db339086)
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 &gt; 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 &gt;= min &amp;&amp; i &lt;= max, "The value must be between &#37;d and &#37;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 &quot;The validated object can not be converted to the&quot;
598      * followed by the name of the class and &quot;class&quot;</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