source: josm/trunk/src/com/google/gdata/util/common/base/Preconditions.java@ 4231

Last change on this file since 4231 was 4231, checked in by stoecker, 13 years ago

add signpost and metadata extractor code to repository directly

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