1 /*
2 * Copyright 2009-2022 the original author or authors.
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 * https://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 package org.mybatis.guice;
17
18 import java.util.Collection;
19 import java.util.NoSuchElementException;
20
21 /**
22 * Simple static methods to be called at the start of your own methods to verify correct arguments and state. This
23 * allows constructs such as
24 *
25 * <pre>
26 * if (count <= 0) {
27 * throw new IllegalArgumentException("must be positive: " + count);
28 * }
29 * </pre>
30 * <p>
31 * to be replaced with the more compact
32 * </p>
33 *
34 * <pre>
35 * checkArgument(count > 0, "must be positive: %s", count);
36 * </pre>
37 * <p>
38 * Note that the sense of the expression is inverted; with {@code Preconditions} you declare what you expect to be
39 * <i>true</i>, just as you do with an <a href="http://java.sun.com/j2se/1.5.0/docs/guide/language/assert.html">
40 * {@code assert}</a> or a JUnit {@code assertTrue()} call.
41 * </p>
42 * <p>
43 * Take care not to confuse precondition checking with other similar types of checks! Precondition exceptions --
44 * including those provided here, but also {@link IndexOutOfBoundsException}, {@link NoSuchElementException},
45 * {@link UnsupportedOperationException} and others -- are used to signal that the <i>calling method</i> has made an
46 * error. This tells the caller that it should not have invoked the method when it did, with the arguments it did, or
47 * perhaps <i>ever</i>. Postcondition or other invariant failures should not throw these types of exceptions.
48 * </p>
49 * <p>
50 * <b>Note:</b> The methods of the {@code Preconditions} class are highly unusual in one way: they are <i>supposed
51 * to</i> throw exceptions, and promise in their specifications to do so even when given perfectly valid input. That is,
52 * {@code null} is a valid parameter to the method {@link #checkNotNull(Object)} -- and technically this parameter could
53 * be even marked as {@link com.google.inject.internal.util.Nullable} -- yet the method will still throw an exception
54 * anyway, because that's what its contract says to do.
55 * </p>
56 * <p>
57 * This class may be used with the Google Web Toolkit (GWT).
58 * </p>
59 *
60 * @author Kevin Bourrillion
61 */
62 final class Preconditions {
63 private Preconditions() {
64 }
65
66 /**
67 * Ensures the truth of an expression involving one or more parameters to the calling method.
68 *
69 * @param expression
70 * a boolean expression
71 *
72 * @throws IllegalArgumentException
73 * if {@code expression} is false
74 */
75 public static void checkArgument(boolean expression) {
76 if (!expression) {
77 throw new IllegalArgumentException();
78 }
79 }
80
81 /**
82 * Ensures the truth of an expression involving one or more parameters to the calling method.
83 *
84 * @param expression
85 * a boolean expression
86 * @param errorMessage
87 * the exception message to use if the check fails; will be converted to a string using
88 * {@link String#valueOf(Object)}
89 *
90 * @throws IllegalArgumentException
91 * if {@code expression} is false
92 */
93 public static void checkArgument(boolean expression, Object errorMessage) {
94 if (!expression) {
95 throw new IllegalArgumentException(String.valueOf(errorMessage));
96 }
97 }
98
99 /**
100 * Ensures the truth of an expression involving one or more parameters to the calling method.
101 *
102 * @param expression
103 * a boolean expression
104 * @param errorMessageTemplate
105 * a template for the exception message should the check fail. The message is formed by replacing each
106 * {@code %s} placeholder in the template with an argument. These are matched by position - the first
107 * {@code %s} gets {@code errorMessageArgs[0]}, etc. Unmatched arguments will be appended to the formatted
108 * message in square braces. Unmatched placeholders will be left as-is.
109 * @param errorMessageArgs
110 * the arguments to be substituted into the message template. Arguments are converted to strings using
111 * {@link String#valueOf(Object)}.
112 *
113 * @throws IllegalArgumentException
114 * if {@code expression} is false
115 * @throws NullPointerException
116 * if the check fails and either {@code
117 * errorMessageTemplate} or {@code errorMessageArgs} is null (don't let this happen)
118 */
119 public static void checkArgument(boolean expression, String errorMessageTemplate, Object... errorMessageArgs) {
120 if (!expression) {
121 throw new IllegalArgumentException(format(errorMessageTemplate, errorMessageArgs));
122 }
123 }
124
125 /**
126 * Ensures the truth of an expression involving the state of the calling instance, but not involving any parameters to
127 * the calling method.
128 *
129 * @param expression
130 * a boolean expression
131 *
132 * @throws IllegalStateException
133 * if {@code expression} is false
134 */
135 public static void checkState(boolean expression) {
136 if (!expression) {
137 throw new IllegalStateException();
138 }
139 }
140
141 /**
142 * Ensures the truth of an expression involving the state of the calling instance, but not involving any parameters to
143 * the calling method.
144 *
145 * @param expression
146 * a boolean expression
147 * @param errorMessage
148 * the exception message to use if the check fails; will be converted to a string using
149 * {@link String#valueOf(Object)}
150 *
151 * @throws IllegalStateException
152 * if {@code expression} is false
153 */
154 public static void checkState(boolean expression, Object errorMessage) {
155 if (!expression) {
156 throw new IllegalStateException(String.valueOf(errorMessage));
157 }
158 }
159
160 /**
161 * Ensures the truth of an expression involving the state of the calling instance, but not involving any parameters to
162 * the calling method.
163 *
164 * @param expression
165 * a boolean expression
166 * @param errorMessageTemplate
167 * a template for the exception message should the check fail. The message is formed by replacing each
168 * {@code %s} placeholder in the template with an argument. These are matched by position - the first
169 * {@code %s} gets {@code errorMessageArgs[0]}, etc. Unmatched arguments will be appended to the formatted
170 * message in square braces. Unmatched placeholders will be left as-is.
171 * @param errorMessageArgs
172 * the arguments to be substituted into the message template. Arguments are converted to strings using
173 * {@link String#valueOf(Object)}.
174 *
175 * @throws IllegalStateException
176 * if {@code expression} is false
177 * @throws NullPointerException
178 * if the check fails and either {@code
179 * errorMessageTemplate} or {@code errorMessageArgs} is null (don't let this happen)
180 */
181 public static void checkState(boolean expression, String errorMessageTemplate, Object... errorMessageArgs) {
182 if (!expression) {
183 throw new IllegalStateException(format(errorMessageTemplate, errorMessageArgs));
184 }
185 }
186
187 /**
188 * Ensures that an object reference passed as a parameter to the calling method is not null.
189 *
190 * @param reference
191 * an object reference
192 *
193 * @return the non-null reference that was validated
194 *
195 * @throws NullPointerException
196 * if {@code reference} is null
197 */
198 public static <T> T checkNotNull(T reference) {
199 if (reference == null) {
200 throw new NullPointerException();
201 }
202 return reference;
203 }
204
205 /**
206 * Ensures that an object reference passed as a parameter to the calling method is not null.
207 *
208 * @param reference
209 * an object reference
210 * @param errorMessage
211 * the exception message to use if the check fails; will be converted to a string using
212 * {@link String#valueOf(Object)}
213 *
214 * @return the non-null reference that was validated
215 *
216 * @throws NullPointerException
217 * if {@code reference} is null
218 */
219 public static <T> T checkNotNull(T reference, Object errorMessage) {
220 if (reference == null) {
221 throw new NullPointerException(String.valueOf(errorMessage));
222 }
223 return reference;
224 }
225
226 /**
227 * Ensures that an object reference passed as a parameter to the calling method is not null.
228 *
229 * @param reference
230 * an object reference
231 * @param errorMessageTemplate
232 * a template for the exception message should the check fail. The message is formed by replacing each
233 * {@code %s} placeholder in the template with an argument. These are matched by position - the first
234 * {@code %s} gets {@code errorMessageArgs[0]}, etc. Unmatched arguments will be appended to the formatted
235 * message in square braces. Unmatched placeholders will be left as-is.
236 * @param errorMessageArgs
237 * the arguments to be substituted into the message template. Arguments are converted to strings using
238 * {@link String#valueOf(Object)}.
239 *
240 * @return the non-null reference that was validated
241 *
242 * @throws NullPointerException
243 * if {@code reference} is null
244 */
245 public static <T> T checkNotNull(T reference, String errorMessageTemplate, Object... errorMessageArgs) {
246 if (reference == null) {
247 // If either of these parameters is null, the right thing happens anyway
248 throw new NullPointerException(format(errorMessageTemplate, errorMessageArgs));
249 }
250 return reference;
251 }
252
253 /**
254 * Ensures that an {@code Iterable} object passed as a parameter to the calling method is not null and contains no
255 * null elements.
256 *
257 * @param iterable
258 * the iterable to check the contents of
259 *
260 * @return the non-null {@code iterable} reference just validated
261 *
262 * @throws NullPointerException
263 * if {@code iterable} is null or contains at least one null element
264 */
265 public static <T extends Iterable<?>> T checkContentsNotNull(T iterable) {
266 if (containsOrIsNull(iterable)) {
267 throw new NullPointerException();
268 }
269 return iterable;
270 }
271
272 /**
273 * Ensures that an {@code Iterable} object passed as a parameter to the calling method is not null and contains no
274 * null elements.
275 *
276 * @param iterable
277 * the iterable to check the contents of
278 * @param errorMessage
279 * the exception message to use if the check fails; will be converted to a string using
280 * {@link String#valueOf(Object)}
281 *
282 * @return the non-null {@code iterable} reference just validated
283 *
284 * @throws NullPointerException
285 * if {@code iterable} is null or contains at least one null element
286 */
287 public static <T extends Iterable<?>> T checkContentsNotNull(T iterable, Object errorMessage) {
288 if (containsOrIsNull(iterable)) {
289 throw new NullPointerException(String.valueOf(errorMessage));
290 }
291 return iterable;
292 }
293
294 /**
295 * Ensures that an {@code Iterable} object passed as a parameter to the calling method is not null and contains no
296 * null elements.
297 *
298 * @param iterable
299 * the iterable to check the contents of
300 * @param errorMessageTemplate
301 * a template for the exception message should the check fail. The message is formed by replacing each
302 * {@code %s} placeholder in the template with an argument. These are matched by position - the first
303 * {@code %s} gets {@code errorMessageArgs[0]}, etc. Unmatched arguments will be appended to the formatted
304 * message in square braces. Unmatched placeholders will be left as-is.
305 * @param errorMessageArgs
306 * the arguments to be substituted into the message template. Arguments are converted to strings using
307 * {@link String#valueOf(Object)}.
308 *
309 * @return the non-null {@code iterable} reference just validated
310 *
311 * @throws NullPointerException
312 * if {@code iterable} is null or contains at least one null element
313 */
314 public static <T extends Iterable<?>> T checkContentsNotNull(T iterable, String errorMessageTemplate,
315 Object... errorMessageArgs) {
316 if (containsOrIsNull(iterable)) {
317 throw new NullPointerException(format(errorMessageTemplate, errorMessageArgs));
318 }
319 return iterable;
320 }
321
322 private static boolean containsOrIsNull(Iterable<?> iterable) {
323 if (iterable == null) {
324 return true;
325 }
326
327 if (iterable instanceof Collection) {
328 Collection<?> collection = (Collection<?>) iterable;
329 try {
330 return collection.contains(null);
331 } catch (NullPointerException e) {
332 // A NPE implies that the collection doesn't contain null.
333 return false;
334 }
335 } else {
336 for (Object element : iterable) {
337 if (element == null) {
338 return true;
339 }
340 }
341 return false;
342 }
343 }
344
345 /**
346 * Ensures that {@code index} specifies a valid <i>element</i> in an array, list or string of size {@code size}. An
347 * element index may range from zero, inclusive, to {@code size}, exclusive.
348 *
349 * @param index
350 * a user-supplied index identifying an element of an array, list or string
351 * @param size
352 * the size of that array, list or string
353 *
354 * @throws IndexOutOfBoundsException
355 * if {@code index} is negative or is not less than {@code size}
356 * @throws IllegalArgumentException
357 * if {@code size} is negative
358 */
359 public static void checkElementIndex(int index, int size) {
360 checkElementIndex(index, size, "index");
361 }
362
363 /**
364 * Ensures that {@code index} specifies a valid <i>element</i> in an array, list or string of size {@code size}. An
365 * element index may range from zero, inclusive, to {@code size}, exclusive.
366 *
367 * @param index
368 * a user-supplied index identifying an element of an array, list or string
369 * @param size
370 * the size of that array, list or string
371 * @param desc
372 * the text to use to describe this index in an error message
373 *
374 * @throws IndexOutOfBoundsException
375 * if {@code index} is negative or is not less than {@code size}
376 * @throws IllegalArgumentException
377 * if {@code size} is negative
378 */
379 public static void checkElementIndex(int index, int size, String desc) {
380 checkArgument(size >= 0, "negative size: %s", size);
381 if (index < 0) {
382 throw new IndexOutOfBoundsException(format("%s (%s) must not be negative", desc, index));
383 }
384 if (index >= size) {
385 throw new IndexOutOfBoundsException(format("%s (%s) must be less than size (%s)", desc, index, size));
386 }
387 }
388
389 /**
390 * Ensures that {@code index} specifies a valid <i>position</i> in an array, list or string of size {@code size}. A
391 * position index may range from zero to {@code size}, inclusive.
392 *
393 * @param index
394 * a user-supplied index identifying a position in an array, list or string
395 * @param size
396 * the size of that array, list or string
397 *
398 * @throws IndexOutOfBoundsException
399 * if {@code index} is negative or is greater than {@code size}
400 * @throws IllegalArgumentException
401 * if {@code size} is negative
402 */
403 public static void checkPositionIndex(int index, int size) {
404 checkPositionIndex(index, size, "index");
405 }
406
407 /**
408 * Ensures that {@code index} specifies a valid <i>position</i> in an array, list or string of size {@code size}. A
409 * position index may range from zero to {@code size}, inclusive.
410 *
411 * @param index
412 * a user-supplied index identifying a position in an array, list or string
413 * @param size
414 * the size of that array, list or string
415 * @param desc
416 * the text to use to describe this index in an error message
417 *
418 * @throws IndexOutOfBoundsException
419 * if {@code index} is negative or is greater than {@code size}
420 * @throws IllegalArgumentException
421 * if {@code size} is negative
422 */
423 public static void checkPositionIndex(int index, int size, String desc) {
424 checkArgument(size >= 0, "negative size: %s", size);
425 if (index < 0) {
426 throw new IndexOutOfBoundsException(format("%s (%s) must not be negative", desc, index));
427 }
428 if (index > size) {
429 throw new IndexOutOfBoundsException(format("%s (%s) must not be greater than size (%s)", desc, index, size));
430 }
431 }
432
433 /**
434 * Ensures that {@code start} and {@code end} specify a valid <i>positions</i> in an array, list or string of size
435 * {@code size}, and are in order. A position index may range from zero to {@code size}, inclusive.
436 *
437 * @param start
438 * a user-supplied index identifying a starting position in an array, list or string
439 * @param end
440 * a user-supplied index identifying a ending position in an array, list or string
441 * @param size
442 * the size of that array, list or string
443 *
444 * @throws IndexOutOfBoundsException
445 * if either index is negative or is greater than {@code size}, or if {@code end} is less than {@code start}
446 * @throws IllegalArgumentException
447 * if {@code size} is negative
448 */
449 public static void checkPositionIndexes(int start, int end, int size) {
450 checkPositionIndex(start, size, "start index");
451 checkPositionIndex(end, size, "end index");
452 if (end < start) {
453 throw new IndexOutOfBoundsException(format("end index (%s) must not be less than start index (%s)", end, start));
454 }
455 }
456
457 /**
458 * Substitutes each {@code %s} in {@code template} with an argument. These are matched by position - the first
459 * {@code %s} gets {@code args[0]}, etc. If there are more arguments than placeholders, the unmatched arguments will
460 * be appended to the end of the formatted message in square braces.
461 *
462 * @param template
463 * a non-null string containing 0 or more {@code %s} placeholders.
464 * @param args
465 * the arguments to be substituted into the message template. Arguments are converted to strings using
466 * {@link String#valueOf(Object)}. Arguments can be null.
467 */
468 // VisibleForTesting
469 static String format(String template, Object... args) {
470 // start substituting the arguments into the '%s' placeholders
471 StringBuilder builder = new StringBuilder(template.length() + 16 * args.length);
472 int templateStart = 0;
473 int i = 0;
474 while (i < args.length) {
475 int placeholderStart = template.indexOf("%s", templateStart);
476 if (placeholderStart == -1) {
477 break;
478 }
479 builder.append(template.substring(templateStart, placeholderStart));
480 builder.append(args[i++]);
481 templateStart = placeholderStart + 2;
482 }
483 builder.append(template.substring(templateStart));
484
485 // if we run out of placeholders, append the extra args in square braces
486 if (i < args.length) {
487 builder.append(" [");
488 builder.append(args[i++]);
489 while (i < args.length) {
490 builder.append(", ");
491 builder.append(args[i++]);
492 }
493 builder.append("]");
494 }
495
496 return builder.toString();
497 }
498 }