1 package org.djutils.exceptions;
2
3 import java.lang.reflect.Constructor;
4 import java.util.ArrayList;
5 import java.util.Arrays;
6 import java.util.IllegalFormatException;
7 import java.util.List;
8
9 import org.djutils.reflection.ClassUtil;
10
11 /**
12 * The Try class has a number of static methods that make it easy to try-catch an exception for any Throwable class, including
13 * the standard Java exceptions and exceptions from libraries that are used in the project. Instead of:
14 *
15 * <pre>
16 * FileInputStream fis;
17 * try
18 * {
19 * fis = new FileInputStream(fileString);
20 * }
21 * catch (FileNotFoundException exception)
22 * {
23 * throw new IllegalArgumentException("File " + fileString + " is not a valid file.", exception);
24 * }
25 * try
26 * {
27 * fis.close();
28 * }
29 * catch (IOException exception)
30 * {
31 * throw new RuntimeException("Could not close the file.", exception);
32 * }
33 * </pre>
34 *
35 * we can write:
36 *
37 * <pre>
38 * FileInputStream fis = Try.assign(() -> new FileInputStream(fileString), IllegalArgumentException.class,
39 * "File %s is not a valid file.", fileString);
40 * Try.execute(() -> fis.close(), "Could not close the file.");
41 * </pre>
42 *
43 * The exception message can be formatted with additional arguments, such that the overhead of building the exception message
44 * only occurs if the exception condition is met. For each method there is a version without Throwable class, in which case a
45 * RuntimeException will be thrown.<br>
46 * <br>
47 * Try is not suitable for try-with-resource statements.<br>
48 * <br>
49 * Try also has a few methods to aid JUNIT tests: {@code testFail(...)} and {@code testNotFail(...)}.
50 * <p>
51 * Copyright (c) 2016-2019 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See
52 * for project information <a href="https://djutils.org" target="_blank"> https://djutils.org</a>. The DJUTILS project is
53 * distributed under a three-clause BSD-style license, which can be found at
54 * <a href="https://djutils.org/docs/license.html" target="_blank"> https://djutils.org/docs/license.html</a>.
55 * </p>
56 * @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
57 * @author <a href="https://www.tudelft.nl/staff/p.knoppers/">Peter Knoppers</a>
58 * @author <a href="https://www.transport.citg.tudelft.nl">Wouter Schakel</a>
59 */
60 public final class Try
61 {
62 /** private constructor for utility class. */
63 private Try()
64 {
65 // utility class
66 }
67
68 // Assign
69
70 /**
71 * Tries to return a value to assign. Will throw a RuntimeException if the try fails.
72 * @param assignment Assignment<V>; functional interface to assign value
73 * @param message String; the message to use in the throwable
74 * @param <V> value type
75 * @return V; value to assign
76 * @throws RuntimeException on failed Try
77 */
78 public static <V> V assign(final Assignment<V> assignment, final String message) throws RuntimeException
79 {
80 try
81 {
82 return assignment.assign();
83 }
84 catch (Throwable cause)
85 {
86 throw catchThrowable(RuntimeException.class, message, new ArrayList<>(), cause);
87 }
88 }
89
90 /**
91 * Tries to return a value to assign. Will throw a RuntimeException if the try fails.
92 * @param assignment Assignment<V>; functional interface to assign value
93 * @param message String; the message to use in the throwable, with formatting identifier
94 * @param arg Object; value to use for the formatting identifier
95 * @param <V> value type
96 * @return V; value to assign
97 * @throws RuntimeException on failed Try
98 */
99 public static <V> V assign(final Assignment<V> assignment, final String message, final Object arg) throws RuntimeException
100 {
101 try
102 {
103 return assignment.assign();
104 }
105 catch (Throwable cause)
106 {
107 List<Object> argList = new ArrayList<>();
108 argList.add(arg);
109 throw catchThrowable(RuntimeException.class, message, argList, cause);
110 }
111 }
112
113 /**
114 * Tries to return a value to assign. Will throw a RuntimeException if the try fails.
115 * @param assignment Assignment<V>; functional interface to assign value
116 * @param message String; the message to use in the throwable, with formatting identifiers
117 * @param arg1 Object; 1st value to use for the formatting identifiers
118 * @param arg2 Object; 2nd value to use for the formatting identifiers
119 * @param <V> value type
120 * @return V; value to assign
121 * @throws RuntimeException on failed Try
122 */
123 public static <V> V assign(final Assignment<V> assignment, final String message, final Object arg1, final Object arg2)
124 throws RuntimeException
125 {
126 try
127 {
128 return assignment.assign();
129 }
130 catch (Throwable cause)
131 {
132 List<Object> argList = new ArrayList<>();
133 argList.add(arg1);
134 argList.add(arg2);
135 throw catchThrowable(RuntimeException.class, message, argList, cause);
136 }
137 }
138
139 /**
140 * Tries to return a value to assign. Will throw a RuntimeException if the try fails.
141 * @param assignment Assignment<V>; functional interface to assign value
142 * @param message String; the message to use in the throwable, with formatting identifiers
143 * @param arg1 Object; 1st value to use for the formatting identifiers
144 * @param arg2 Object; 2nd value to use for the formatting identifiers
145 * @param arg3 Object; 3rd value to use for the formatting identifiers
146 * @param <V> value type
147 * @return V; value to assign
148 * @throws RuntimeException on failed Try
149 */
150 public static <V> V assign(final Assignment<V> assignment, final String message, final Object arg1, final Object arg2,
151 final Object arg3) throws RuntimeException
152 {
153 try
154 {
155 return assignment.assign();
156 }
157 catch (Throwable cause)
158 {
159 List<Object> argList = new ArrayList<>();
160 argList.add(arg1);
161 argList.add(arg2);
162 argList.add(arg3);
163 throw catchThrowable(RuntimeException.class, message, argList, cause);
164 }
165 }
166
167 /**
168 * Tries to return a value to assign. Will throw a RuntimeException if the try fails.
169 * @param assignment Assignment<V>; functional interface to assign value
170 * @param message String; the message to use in the throwable, with formatting identifiers
171 * @param arg1 Object; 1st value to use for the formatting identifiers
172 * @param arg2 Object; 2nd value to use for the formatting identifiers
173 * @param arg3 Object; 3rd value to use for the formatting identifiers
174 * @param args Object...; potential 4th and further values to use for the formatting identifiers
175 * @param <V> value type
176 * @return V; value to assign
177 * @throws RuntimeException on failed Try
178 */
179 public static <V> V assign(final Assignment<V> assignment, final String message, final Object arg1, final Object arg2,
180 final Object arg3, final Object... args) throws RuntimeException
181 {
182 try
183 {
184 return assignment.assign();
185 }
186 catch (Throwable cause)
187 {
188 List<Object> argList = new ArrayList<>();
189 argList.add(arg1);
190 argList.add(arg2);
191 argList.add(arg3);
192 argList.addAll(Arrays.asList(args));
193 throw catchThrowable(RuntimeException.class, message, argList, cause);
194 }
195 }
196
197 /**
198 * Tries to return a value to assign. Will throw a specified Throwable if the try fails.
199 * @param assignment Assignment<V>; functional interface to assign value
200 * @param throwableClass Class<T>; class of the throwable to throw
201 * @param message String; the message to use in the throwable
202 * @param <V> value type
203 * @param <T> throwable type
204 * @return V; value to assign
205 * @throws T throwable on failed Try
206 */
207 public static <V, T extends Throwable> V assign(final Assignment<V> assignment, final Class<T> throwableClass,
208 final String message) throws T
209 {
210 try
211 {
212 return assignment.assign();
213 }
214 catch (Throwable cause)
215 {
216 throw catchThrowable(throwableClass, message, new ArrayList<>(), cause);
217 }
218 }
219
220 /**
221 * Tries to return a value to assign. Will throw a specified Throwable if the try fails.
222 * @param assignment Assignment<V>; functional interface to assign value
223 * @param throwableClass Class<T>; class of the throwable to throw
224 * @param message String; the message to use in the throwable, with formatting identifier
225 * @param arg Object; value to use for the formatting identifier
226 * @param <V> value type
227 * @param <T> throwable type
228 * @return V; value to assign
229 * @throws T throwable on failed Try
230 */
231 public static <V, T extends Throwable> V assign(final Assignment<V> assignment, final Class<T> throwableClass,
232 final String message, final Object arg) throws T
233 {
234 try
235 {
236 return assignment.assign();
237 }
238 catch (Throwable cause)
239 {
240 List<Object> argList = new ArrayList<>();
241 argList.add(arg);
242 throw catchThrowable(throwableClass, message, argList, cause);
243 }
244 }
245
246 /**
247 * Tries to return a value to assign. Will throw a specified Throwable if the try fails.
248 * @param assignment Assignment<V>; functional interface to assign value
249 * @param throwableClass Class<T>; class of the throwable to throw
250 * @param message String; the message to use in the throwable, with formatting identifiers
251 * @param arg1 Object; 1st value to use for the formatting identifiers
252 * @param arg2 Object; 2nd value to use for the formatting identifiers
253 * @param <V> value type
254 * @param <T> throwable type
255 * @return V; value to assign
256 * @throws T throwable on failed Try
257 */
258 public static <V, T extends Throwable> V assign(final Assignment<V> assignment, final Class<T> throwableClass,
259 final String message, final Object arg1, final Object arg2) throws T
260 {
261 try
262 {
263 return assignment.assign();
264 }
265 catch (Throwable cause)
266 {
267 List<Object> argList = new ArrayList<>();
268 argList.add(arg1);
269 argList.add(arg2);
270 throw catchThrowable(throwableClass, message, argList, cause);
271 }
272 }
273
274 /**
275 * Tries to return a value to assign. Will throw a specified Throwable if the try fails.
276 * @param assignment Assignment<V>; functional interface to assign value
277 * @param throwableClass Class<T>; class of the throwable to throw
278 * @param message String; the message to use in the throwable, with formatting identifiers
279 * @param arg1 Object; 1st value to use for the formatting identifiers
280 * @param arg2 Object; 2nd value to use for the formatting identifiers
281 * @param arg3 Object; 3rd value to use for the formatting identifiers
282 * @param <V> value type
283 * @param <T> throwable type
284 * @return V; value to assign
285 * @throws T throwable on failed Try
286 */
287 public static <V, T extends Throwable> V assign(final Assignment<V> assignment, final Class<T> throwableClass,
288 final String message, final Object arg1, final Object arg2, final Object arg3) throws T
289 {
290 try
291 {
292 return assignment.assign();
293 }
294 catch (Throwable cause)
295 {
296 List<Object> argList = new ArrayList<>();
297 argList.add(arg1);
298 argList.add(arg2);
299 argList.add(arg3);
300 throw catchThrowable(throwableClass, message, argList, cause);
301 }
302 }
303
304 /**
305 * Tries to return a value to assign. Will throw a specified Throwable if the try fails.
306 * @param assignment Assignment<V>; functional interface to assign value
307 * @param throwableClass Class<T>; class of the throwable to throw
308 * @param message String; the message to use in the throwable, with formatting identifiers
309 * @param arg1 Object; 1st value to use for the formatting identifiers
310 * @param arg2 Object; 2nd value to use for the formatting identifiers
311 * @param arg3 Object; 3rd value to use for the formatting identifiers
312 * @param args Object...; potential 4th and further values to use for the formatting identifiers
313 * @param <V> value type
314 * @param <T> throwable type
315 * @return V; value to assign
316 * @throws T throwable on failed Try
317 */
318 public static <V, T extends Throwable> V assign(final Assignment<V> assignment, final Class<T> throwableClass,
319 final String message, final Object arg1, final Object arg2, final Object arg3, final Object... args) throws T
320 {
321 try
322 {
323 return assignment.assign();
324 }
325 catch (Throwable cause)
326 {
327 List<Object> argList = new ArrayList<>();
328 argList.add(arg1);
329 argList.add(arg2);
330 argList.add(arg3);
331 argList.addAll(Arrays.asList(args));
332 throw catchThrowable(throwableClass, message, argList, cause);
333 }
334 }
335
336 // Execute
337
338 /**
339 * Tries to execute. Will throw a RuntimeException if the try fails.
340 * @param execution Execution; functional interface to execute
341 * @param message String; the message to use in the throwable
342 * @throws RuntimeException on failed Try
343 */
344 public static void execute(final Execution execution, final String message) throws RuntimeException
345 {
346 try
347 {
348 execution.execute();
349 }
350 catch (Throwable cause)
351 {
352 throw catchThrowable(RuntimeException.class, message, new ArrayList<>(), cause);
353 }
354 }
355
356 /**
357 * Tries to execute. Will throw a RuntimeException if the try fails.
358 * @param execution Execution; functional interface to execute
359 * @param message String; the message to use in the throwable, with formatting identifier
360 * @param arg Object; value to use for the formatting identifier
361 * @throws RuntimeException on failed Try
362 */
363 public static void execute(final Execution execution, final String message, final Object arg) throws RuntimeException
364 {
365 try
366 {
367 execution.execute();
368 }
369 catch (Throwable cause)
370 {
371 List<Object> argList = new ArrayList<>();
372 argList.add(arg);
373 throw catchThrowable(RuntimeException.class, message, argList, cause);
374 }
375 }
376
377 /**
378 * Tries to execute. Will throw a RuntimeException if the try fails.
379 * @param execution Execution; functional interface to execute
380 * @param message String; the message to use in the throwable, with formatting identifiers
381 * @param arg1 Object; 1st value to use for the formatting identifiers
382 * @param arg2 Object; 2nd value to use for the formatting identifiers
383 * @throws RuntimeException on failed Try
384 */
385 public static void execute(final Execution execution, final String message, final Object arg1, final Object arg2)
386 throws RuntimeException
387 {
388 try
389 {
390 execution.execute();
391 }
392 catch (Throwable cause)
393 {
394 List<Object> argList = new ArrayList<>();
395 argList.add(arg1);
396 argList.add(arg2);
397 throw catchThrowable(RuntimeException.class, message, argList, cause);
398 }
399 }
400
401 /**
402 * Tries to execute. Will throw a RuntimeException if the try fails.
403 * @param execution Execution; functional interface to execute
404 * @param message String; the message to use in the throwable, with formatting identifiers
405 * @param arg1 Object; 1st value to use for the formatting identifiers
406 * @param arg2 Object; 2nd value to use for the formatting identifiers
407 * @param arg3 Object; 3rd value to use for the formatting identifiers
408 * @throws RuntimeException on failed Try
409 */
410 public static void execute(final Execution execution, final String message, final Object arg1, final Object arg2,
411 final Object arg3) throws RuntimeException
412 {
413 try
414 {
415 execution.execute();
416 }
417 catch (Throwable cause)
418 {
419 List<Object> argList = new ArrayList<>();
420 argList.add(arg1);
421 argList.add(arg2);
422 argList.add(arg3);
423 throw catchThrowable(RuntimeException.class, message, argList, cause);
424 }
425 }
426
427 /**
428 * Tries to execute. Will throw a RuntimeException if the try fails.
429 * @param execution Execution; functional interface to execute
430 * @param message String; the message to use in the throwable, with formatting identifiers
431 * @param arg1 Object; 1st value to use for the formatting identifiers
432 * @param arg2 Object; 2nd value to use for the formatting identifiers
433 * @param arg3 Object; 3rd value to use for the formatting identifiers
434 * @param args Object...; potential 4th and further values to use for the formatting identifiers
435 * @throws RuntimeException on failed Try
436 */
437 public static void execute(final Execution execution, final String message, final Object arg1, final Object arg2,
438 final Object arg3, final Object... args) throws RuntimeException
439 {
440 try
441 {
442 execution.execute();
443 }
444 catch (Throwable cause)
445 {
446 List<Object> argList = new ArrayList<>();
447 argList.add(arg1);
448 argList.add(arg2);
449 argList.add(arg3);
450 argList.addAll(Arrays.asList(args));
451 throw catchThrowable(RuntimeException.class, message, argList, cause);
452 }
453 }
454
455 /**
456 * Tries to execute. Will throw a specified Throwable if the try fails.
457 * @param execution Execution; functional interface to execute
458 * @param throwableClass Class<T>; class of the throwable to throw
459 * @param message String; the message to use in the throwable
460 * @param <T> throwable type
461 * @throws T throwable on failed Try
462 */
463 public static <T extends Throwable> void execute(final Execution execution, final Class<T> throwableClass,
464 final String message) throws T
465 {
466 try
467 {
468 execution.execute();
469 }
470 catch (Throwable cause)
471 {
472 throw catchThrowable(throwableClass, message, new ArrayList<>(), cause);
473 }
474 }
475
476 /**
477 * Tries to execute. Will throw a specified Throwable if the try fails.
478 * @param execution Execution; functional interface to execute
479 * @param throwableClass Class<T>; class of the throwable to throw
480 * @param message String; the message to use in the throwable, with formatting identifier
481 * @param arg Object; value to use for the formatting identifier
482 * @param <T> throwable type
483 * @throws T throwable on failed Try
484 */
485 public static <T extends Throwable> void execute(final Execution execution, final Class<T> throwableClass,
486 final String message, final Object arg) throws T
487 {
488 try
489 {
490 execution.execute();
491 }
492 catch (Throwable cause)
493 {
494 List<Object> argList = new ArrayList<>();
495 argList.add(arg);
496 throw catchThrowable(throwableClass, message, argList, cause);
497 }
498 }
499
500 /**
501 * Tries to execute. Will throw a specified Throwable if the try fails.
502 * @param execution Execution; functional interface to execute
503 * @param throwableClass Class<T>; class of the throwable to throw
504 * @param message String; the message to use in the throwable, with formatting identifiers
505 * @param arg1 Object; 1st value to use for the formatting identifiers
506 * @param arg2 Object; 2nd value to use for the formatting identifiers
507 * @param <T> throwable type
508 * @throws T throwable on failed Try
509 */
510 public static <T extends Throwable> void execute(final Execution execution, final Class<T> throwableClass,
511 final String message, final Object arg1, final Object arg2) throws T
512 {
513 try
514 {
515 execution.execute();
516 }
517 catch (Throwable cause)
518 {
519 List<Object> argList = new ArrayList<>();
520 argList.add(arg1);
521 argList.add(arg2);
522 throw catchThrowable(throwableClass, message, argList, cause);
523 }
524 }
525
526 /**
527 * Tries to execute. Will throw a specified Throwable if the try fails.
528 * @param execution Execution; functional interface to execute
529 * @param throwableClass Class<T>; class of the throwable to throw
530 * @param message String; the message to use in the throwable, with formatting identifiers
531 * @param arg1 Object; 1st value to use for the formatting identifiers
532 * @param arg2 Object; 2nd value to use for the formatting identifiers
533 * @param arg3 Object; 3rd value to use for the formatting identifiers
534 * @param <T> throwable type
535 * @throws T throwable on failed Try
536 */
537 public static <T extends Throwable> void execute(final Execution execution, final Class<T> throwableClass,
538 final String message, final Object arg1, final Object arg2, final Object arg3) throws T
539 {
540 try
541 {
542 execution.execute();
543 }
544 catch (Throwable cause)
545 {
546 List<Object> argList = new ArrayList<>();
547 argList.add(arg1);
548 argList.add(arg2);
549 argList.add(arg3);
550 throw catchThrowable(throwableClass, message, argList, cause);
551 }
552 }
553
554 /**
555 * Tries to execute. Will throw a specified Throwable if the try fails.
556 * @param execution Execution; functional interface to execute
557 * @param throwableClass Class<T>; class of the throwable to throw
558 * @param message String; the message to use in the throwable, with formatting identifiers
559 * @param arg1 Object; 1st value to use for the formatting identifiers
560 * @param arg2 Object; 2nd value to use for the formatting identifiers
561 * @param arg3 Object; 3rd value to use for the formatting identifiers
562 * @param args Object...; potential 4th and further values to use for the formatting identifiers
563 * @param <T> throwable type
564 * @throws T throwable on failed Try
565 */
566 public static <T extends Throwable> void execute(final Execution execution, final Class<T> throwableClass,
567 final String message, final Object arg1, final Object arg2, final Object arg3, final Object... args) throws T
568 {
569 try
570 {
571 execution.execute();
572 }
573 catch (Throwable cause)
574 {
575 List<Object> argList = new ArrayList<>();
576 argList.add(arg1);
577 argList.add(arg2);
578 argList.add(arg3);
579 argList.addAll(Arrays.asList(args));
580 throw catchThrowable(throwableClass, message, argList, cause);
581 }
582 }
583
584 // Core of assign/execute methods
585
586 /**
587 * Core method to create the Throwable to throw.
588 * @param throwableClass Class<T>; the throwable class
589 * @param message String; the message to construct when an exception is thrown.
590 * @param argList List<Object>; List<Object> the arguments as implied by format escapes in
591 * <code>message</code>
592 * @param cause Throwable; underlying cause thrown inside the assign()/execute()
593 * @param <T> throwable type
594 * @return T; throwable
595 */
596 private static <T extends Throwable> T catchThrowable(final Class<T> throwableClass, final String message,
597 final List<Object> argList, final Throwable cause)
598 {
599 // create a clear message
600 List<StackTraceElement> steList = new ArrayList<>(Arrays.asList(new Throwable().getStackTrace()));
601 // see https://stackoverflow.com/questions/2411487/nullpointerexception-in-java-with-no-stacktrace
602 // and https://hg.openjdk.java.net/jdk/jdk/file/tip/src/hotspot/share/opto/graphKit.cpp
603 if (steList.size() > 2)
604 {
605 steList.remove(0); // remove the catchThrowable(...) call
606 steList.remove(0); // remove the Try.assign/execute(...) call
607 }
608 StackTraceElement[] ste = steList.toArray(new StackTraceElement[steList.size()]);
609 String where = ste[0].getClassName() + "." + ste[0].getMethodName() + " (" + ste[0].getLineNumber() + "): ";
610 Object[] args = argList.toArray();
611 String formattedMessage;
612 try
613 {
614 formattedMessage = where + String.format(message, args);
615 }
616 catch (IllegalFormatException exception)
617 {
618 formattedMessage = where + message + " [FormatException; args=" + argList + "]";
619 }
620
621 // throw all other exceptions through reflection
622 T exception;
623 try
624 {
625 Constructor<T> constructor =
626 ClassUtil.resolveConstructor(throwableClass, new Class<?>[] {String.class, Throwable.class});
627 List<StackTraceElement> steCause = new ArrayList<>(Arrays.asList(cause.getStackTrace()));
628 // see https://stackoverflow.com/questions/2411487/nullpointerexception-in-java-with-no-stacktrace
629 // and https://hg.openjdk.java.net/jdk/jdk/file/tip/src/hotspot/share/opto/graphKit.cpp
630 if (steCause.size() > 3)
631 {
632 steCause.remove(steCause.size() - 1); // remove method that called Try.assign/execute(...)
633 steCause.remove(steCause.size() - 1); // remove the Try.assign/execute(...) call
634 steCause.remove(steCause.size() - 1); // remove the Assignment/Execution implementation (can be lambda$#)
635 cause.setStackTrace(steCause.toArray(new StackTraceElement[steCause.size()]));
636 }
637 exception = constructor.newInstance(formattedMessage, cause);
638 exception.setStackTrace(ste);
639 }
640 catch (Throwable t)
641 {
642 RuntimeException rte = new RuntimeException(t.getMessage(), new Exception(formattedMessage, cause));
643 rte.setStackTrace(ste);
644 throw rte;
645 }
646 return exception;
647 }
648
649 // Test fail/succeed (JUNIT)
650
651 /**
652 * Fails if the assignment succeeds.
653 * @param assignment Assignment<V>; functional interface to assign value
654 * @param <V> value type
655 * @return V; value to assign
656 */
657 public static <V> V testFail(final Assignment<V> assignment)
658 {
659 return testFail(assignment, null, Throwable.class);
660 }
661
662 /**
663 * Fails if the assignment succeeds.
664 * @param assignment Assignment<V>; functional interface to assign value
665 * @param message String; fail message
666 * @param <V> value type
667 * @return V; value to assign
668 */
669 public static <V> V testFail(final Assignment<V> assignment, final String message)
670 {
671 return testFail(assignment, message, Throwable.class);
672 }
673
674 /**
675 * Fails if the assignment succeeds.
676 * @param assignment Assignment<V>; functional interface to assign value
677 * @param throwableClass Class<T>; throwable class to catch
678 * @param <V> value type
679 * @param <T> throwable type
680 * @return V; value to assign
681 */
682 public static <V, T extends Throwable> V testFail(final Assignment<V> assignment, final Class<T> throwableClass)
683 {
684 return testFail(assignment, null, throwableClass);
685 }
686
687 /**
688 * Fails if the assignment succeeds.
689 * @param assignment Assignment<V>; functional interface to assign value
690 * @param message String; fail message
691 * @param throwableClass Class<T>; throwable class to catch
692 * @param <V> value type
693 * @param <T> throwable type
694 * @return V; value to assign
695 */
696 public static <V, T extends Throwable> V testFail(final Assignment<V> assignment, final String message,
697 final Class<T> throwableClass)
698 {
699 V value;
700 try
701 {
702 value = assignment.assign();
703 throw new AssertionError(message);
704 }
705 catch (Throwable cause)
706 {
707 if (!throwableClass.isAssignableFrom(cause.getClass()))
708 {
709 throw new AssertionError("Assignment failed on unexpected Throwable, expected ("
710 + throwableClass.getSimpleName() + "), but got (" + cause.getClass().getSimpleName() + ").");
711 }
712 // expected to fail
713 value = null;
714 }
715 return value;
716 }
717
718 /**
719 * Fails if the assignment does not succeed.
720 * @param assignment Assignment<V>; functional interface to assign value
721 * @param <V> value type
722 * @return V; value to assign
723 */
724 public static <V> V testSucceed(final Assignment<V> assignment)
725 {
726 return testSucceed(assignment, null, Throwable.class);
727 }
728
729 /**
730 * Fails if the assignment does not succeed.
731 * @param assignment Assignment<V>; functional interface to assign value
732 * @param message String; fail message
733 * @param <V> value type
734 * @return V; value to assign
735 */
736 public static <V> V testSucceed(final Assignment<V> assignment, final String message)
737 {
738 return testSucceed(assignment, message, Throwable.class);
739 }
740
741 /**
742 * Fails if the assignment does not succeed.
743 * @param assignment Assignment<V>; functional interface to assign value
744 * @param throwableClass Class<T>; throwable class to catch
745 * @param <V> value type
746 * @param <T> throwable type
747 * @return V; value to assign
748 */
749 public static <V, T extends Throwable> V testSucceed(final Assignment<V> assignment, final Class<T> throwableClass)
750 {
751 return testSucceed(assignment, null, throwableClass);
752 }
753
754 /**
755 * Fails if the assignment does not succeed.
756 * @param assignment Assignment<V>; functional interface to assign value
757 * @param message String; fail message
758 * @param throwableClass Class<T>; throwable class to catch
759 * @param <V> value type
760 * @param <T> throwable type
761 * @return V; value to assign
762 */
763 public static <V, T extends Throwable> V testSucceed(final Assignment<V> assignment, final String message,
764 final Class<T> throwableClass)
765 {
766 V value;
767 try
768 {
769 value = assignment.assign();
770 }
771 catch (Throwable cause)
772 {
773 if (throwableClass.isAssignableFrom(cause.getClass()))
774 {
775 value = null;
776 }
777 else
778 {
779 throw new AssertionError("Assignment failed on unexpected Throwable, expected ("
780 + throwableClass.getSimpleName() + "), but got (" + cause.getClass().getSimpleName() + ").");
781 }
782 }
783 return value;
784 }
785
786 /**
787 * Fails if the execution succeeds.
788 * @param execution Execution; functional interface to execute
789 */
790 public static void testFail(final Execution execution)
791 {
792 testFail(execution, null, Throwable.class);
793 }
794
795 /**
796 * Fails if the execution succeeds.
797 * @param execution Execution; functional interface to execute
798 * @param message String; fail message
799 */
800 public static void testFail(final Execution execution, final String message)
801 {
802 testFail(execution, message, Throwable.class);
803 }
804
805 /**
806 * Fails if the execution succeeds.
807 * @param execution Execution; functional interface to execute
808 * @param throwableClass Class<T>; throwable class to catch
809 * @param <T> throwable type
810 */
811 public static <T extends Throwable> void testFail(final Execution execution, final Class<T> throwableClass)
812 {
813 testFail(execution, null, throwableClass);
814 }
815
816 /**
817 * Fails if the execution succeeds.
818 * @param execution Execution; functional interface to execute
819 * @param message String; fail message
820 * @param throwableClass Class<T>; throwable class to catch
821 * @param <T> throwable type
822 */
823 public static <T extends Throwable> void testFail(final Execution execution, final String message,
824 final Class<T> throwableClass)
825 {
826 try
827 {
828 execution.execute();
829 }
830 catch (Throwable cause)
831 {
832 if (!throwableClass.isAssignableFrom(cause.getClass()))
833 {
834 throw new AssertionError("Execution failed on unexpected Throwable, expected (" + throwableClass.getSimpleName()
835 + "), but got (" + cause.getClass().getSimpleName() + ").");
836 }
837 // expected to fail
838 return;
839 }
840 throw new AssertionError(message);
841 }
842
843 /**
844 * Fails if the execution does not succeed.
845 * @param execution Execution; functional interface to execute
846 */
847 public static void testSucceed(final Execution execution)
848 {
849 testSucceed(execution, null, Throwable.class);
850 }
851
852 /**
853 * Fails if the execution does not succeed.
854 * @param execution Execution; functional interface to execute
855 * @param message String; fail message
856 */
857 public static void testSucceed(final Execution execution, final String message)
858 {
859 testSucceed(execution, message, Throwable.class);
860 }
861
862 /**
863 * Fails if the execution does not succeed.
864 * @param execution Execution; functional interface to execute
865 * @param throwableClass Class<T>; throwable class to catch
866 * @param <T> throwable type
867 */
868 public static <T extends Throwable> void testSucceed(final Execution execution, final Class<T> throwableClass)
869 {
870 testSucceed(execution, null, throwableClass);
871 }
872
873 /**
874 * Fails if the execution does not succeed.
875 * @param execution Execution; functional interface to execute
876 * @param message String; fail message
877 * @param throwableClass Class<T>; throwable class to catch
878 * @param <T> throwable type
879 */
880 public static <T extends Throwable> void testSucceed(final Execution execution, final String message,
881 final Class<T> throwableClass)
882 {
883 try
884 {
885 execution.execute();
886 }
887 catch (Throwable cause)
888 {
889 if (throwableClass.isAssignableFrom(cause.getClass()))
890 {
891 throw new AssertionError(message);
892 }
893 else
894 {
895 throw new AssertionError("Execution failed on unexpected Throwable, expected (" + throwableClass.getSimpleName()
896 + "), but got (" + cause.getClass().getSimpleName() + ").");
897 }
898 }
899 }
900
901 // Interfaces
902
903 /**
904 * Functional interface for calls to Try.assign(...). For this a lambda expression can be used.
905 *
906 * <pre>
907 * FileInputStream fis = Try.assign(() -> new FileInputStream(fileString), IllegalArgumentException.class,
908 * "File %s is not a valid file.", fileString);
909 * </pre>
910 * <p>
911 * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
912 * <br>
913 * BSD-style license. See <a href="https://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
914 * <p>
915 * @version $Revision$, $LastChangedDate$, by $Author$, initial version 31 jan. 2018 <br>
916 * @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
917 * @author <a href="https://www.tudelft.nl/staff/p.knoppers/">Peter Knoppers</a>
918 * @author <a href="https://www.transport.citg.tudelft.nl">Wouter Schakel</a>
919 * @param <V> value type
920 */
921 @FunctionalInterface
922 public interface Assignment<V>
923 {
924 /**
925 * Returns a value which is obtained from the context in which the Assignment was created.
926 * @return value which is obtained from the context in which the Assignment was created
927 * @throws Throwable on any throwable in the try
928 */
929 V assign() throws Throwable;
930 }
931
932 /**
933 * Functional interface for calls to Try.execute(...). For this a lambda expression can be used.
934 *
935 * <pre>
936 * Try.execute(() -> fis.close(), "Could not close the file.");
937 * </pre>
938 * <p>
939 * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
940 * <br>
941 * BSD-style license. See <a href="https://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
942 * <p>
943 * @version $Revision$, $LastChangedDate$, by $Author$, initial version 31 jan. 2018 <br>
944 * @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
945 * @author <a href="https://www.tudelft.nl/staff/p.knoppers/">Peter Knoppers</a>
946 * @author <a href="https://www.transport.citg.tudelft.nl">Wouter Schakel</a>
947 */
948 @FunctionalInterface
949 public interface Execution
950 {
951 /**
952 * Executes some code using the context in which the Execution was created.
953 * @throws Throwable on any throwable in the try
954 */
955 void execute() throws Throwable;
956 }
957
958 }