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