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 steList.remove(0); // remove the catchThrowable(...) call
602 steList.remove(0); // remove the Attemp.assign/execute(...) call
603 StackTraceElement[] ste = steList.toArray(new StackTraceElement[steList.size()]);
604 String where = ste[0].getClassName() + "." + ste[0].getMethodName() + " (" + ste[0].getLineNumber() + "): ";
605 Object[] args = argList.toArray();
606 String formattedMessage;
607 try
608 {
609 formattedMessage = where + String.format(message, args);
610 }
611 catch (IllegalFormatException exception)
612 {
613 formattedMessage = where + message + " [FormatException; args=" + argList + "]";
614 }
615
616 // throw all other exceptions through reflection
617 T exception;
618 try
619 {
620 @SuppressWarnings("unchecked")
621 Constructor<T> constructor = (Constructor<T>) ClassUtil.resolveConstructor(throwableClass,
622 new Class<?>[] {String.class, Throwable.class});
623 List<StackTraceElement> steCause = new ArrayList<>(Arrays.asList(cause.getStackTrace()));
624 steCause.remove(steCause.size() - 1); // remove method that called Attemp.assign/execute(...) as that's in steList
625 steCause.remove(steCause.size() - 1); // remove the Attemp.assign/execute(...) call
626 steCause.remove(steCause.size() - 1); // remove the Assignment/Execution implementation (can be lambda$#)
627 cause.setStackTrace(steCause.toArray(new StackTraceElement[steCause.size()]));
628 exception = constructor.newInstance(formattedMessage, cause);
629 exception.setStackTrace(ste);
630 }
631 catch (Throwable t)
632 {
633 RuntimeException rte = new RuntimeException(t.getMessage(), new Exception(formattedMessage, cause));
634 rte.setStackTrace(ste);
635 throw rte;
636 }
637 return exception;
638 }
639
640 // Test fail/succeed (JUNIT)
641
642 /**
643 * Fails if the assignment succeeds.
644 * @param assignment Assignment<V>; functional interface to assign value
645 * @param <V> value type
646 * @return V; value to assign
647 */
648 public static <V> V testFail(final Assignment<V> assignment)
649 {
650 return testFail(assignment, null, Throwable.class);
651 }
652
653 /**
654 * Fails if the assignment succeeds.
655 * @param assignment Assignment<V>; functional interface to assign value
656 * @param message String; fail message
657 * @param <V> value type
658 * @return V; value to assign
659 */
660 public static <V> V testFail(final Assignment<V> assignment, final String message)
661 {
662 return testFail(assignment, message, Throwable.class);
663 }
664
665 /**
666 * Fails if the assignment succeeds.
667 * @param assignment Assignment<V>; functional interface to assign value
668 * @param throwableClass Class<T>; throwable class to catch
669 * @param <V> value type
670 * @param <T> throwable type
671 * @return V; value to assign
672 */
673 public static <V, T extends Throwable> V testFail(final Assignment<V> assignment, final Class<T> throwableClass)
674 {
675 return testFail(assignment, null, throwableClass);
676 }
677
678 /**
679 * Fails if the assignment succeeds.
680 * @param assignment Assignment<V>; functional interface to assign value
681 * @param message String; fail message
682 * @param throwableClass Class<T>; throwable class to catch
683 * @param <V> value type
684 * @param <T> throwable type
685 * @return V; value to assign
686 */
687 public static <V, T extends Throwable> V testFail(final Assignment<V> assignment, final String message,
688 final Class<T> throwableClass)
689 {
690 V value;
691 try
692 {
693 value = assignment.assign();
694 throw new AssertionError(message);
695 }
696 catch (Throwable cause)
697 {
698 if (!throwableClass.isAssignableFrom(cause.getClass()))
699 {
700 throw new AssertionError("Assignment failed on unexpected Throwable, expected ("
701 + throwableClass.getSimpleName() + "), but got (" + cause.getClass().getSimpleName() + ").");
702 }
703 // expected to fail
704 value = null;
705 }
706 return value;
707 }
708
709 /**
710 * Fails if the assignment does not succeed.
711 * @param assignment Assignment<V>; functional interface to assign value
712 * @param <V> value type
713 * @return V; value to assign
714 */
715 public static <V> V testSucceed(final Assignment<V> assignment)
716 {
717 return testSucceed(assignment, null, Throwable.class);
718 }
719
720 /**
721 * Fails if the assignment does not succeed.
722 * @param assignment Assignment<V>; functional interface to assign value
723 * @param message String; fail message
724 * @param <V> value type
725 * @return V; value to assign
726 */
727 public static <V> V testSucceed(final Assignment<V> assignment, final String message)
728 {
729 return testSucceed(assignment, message, Throwable.class);
730 }
731
732 /**
733 * Fails if the assignment does not succeed.
734 * @param assignment Assignment<V>; functional interface to assign value
735 * @param throwableClass Class<T>; throwable class to catch
736 * @param <V> value type
737 * @param <T> throwable type
738 * @return V; value to assign
739 */
740 public static <V, T extends Throwable> V testSucceed(final Assignment<V> assignment, final Class<T> throwableClass)
741 {
742 return testSucceed(assignment, null, throwableClass);
743 }
744
745 /**
746 * Fails if the assignment does not succeed.
747 * @param assignment Assignment<V>; functional interface to assign value
748 * @param message String; fail message
749 * @param throwableClass Class<T>; throwable class to catch
750 * @param <V> value type
751 * @param <T> throwable type
752 * @return V; value to assign
753 */
754 public static <V, T extends Throwable> V testSucceed(final Assignment<V> assignment, final String message,
755 final Class<T> throwableClass)
756 {
757 V value;
758 try
759 {
760 value = assignment.assign();
761 }
762 catch (Throwable cause)
763 {
764 if (throwableClass.isAssignableFrom(cause.getClass()))
765 {
766 value = null;
767 }
768 else
769 {
770 throw new AssertionError("Assignment failed on unexpected Throwable, expected ("
771 + throwableClass.getSimpleName() + "), but got (" + cause.getClass().getSimpleName() + ").");
772 }
773 }
774 return value;
775 }
776
777 /**
778 * Fails if the execution succeeds.
779 * @param execution Execution; functional interface to execute
780 */
781 public static void testFail(final Execution execution)
782 {
783 testFail(execution, null, Throwable.class);
784 }
785
786 /**
787 * Fails if the execution succeeds.
788 * @param execution Execution; functional interface to execute
789 * @param message String; fail message
790 */
791 public static void testFail(final Execution execution, final String message)
792 {
793 testFail(execution, message, Throwable.class);
794 }
795
796 /**
797 * Fails if the execution succeeds.
798 * @param execution Execution; functional interface to execute
799 * @param throwableClass Class<T>; throwable class to catch
800 * @param <T> throwable type
801 */
802 public static <T extends Throwable> void testFail(final Execution execution, final Class<T> throwableClass)
803 {
804 testFail(execution, null, throwableClass);
805 }
806
807 /**
808 * Fails if the execution succeeds.
809 * @param execution Execution; functional interface to execute
810 * @param message String; fail message
811 * @param throwableClass Class<T>; throwable class to catch
812 * @param <T> throwable type
813 */
814 public static <T extends Throwable> void testFail(final Execution execution, final String message,
815 final Class<T> throwableClass)
816 {
817 try
818 {
819 execution.execute();
820 }
821 catch (Throwable cause)
822 {
823 if (!throwableClass.isAssignableFrom(cause.getClass()))
824 {
825 throw new AssertionError("Execution failed on unexpected Throwable, expected (" + throwableClass.getSimpleName()
826 + "), but got (" + cause.getClass().getSimpleName() + ").");
827 }
828 // expected to fail
829 return;
830 }
831 throw new AssertionError(message);
832 }
833
834 /**
835 * Fails if the execution does not succeed.
836 * @param execution Execution; functional interface to execute
837 */
838 public static void testSucceed(final Execution execution)
839 {
840 testSucceed(execution, null, Throwable.class);
841 }
842
843 /**
844 * Fails if the execution does not succeed.
845 * @param execution Execution; functional interface to execute
846 * @param message String; fail message
847 */
848 public static void testSucceed(final Execution execution, final String message)
849 {
850 testSucceed(execution, message, Throwable.class);
851 }
852
853 /**
854 * Fails if the execution does not succeed.
855 * @param execution Execution; functional interface to execute
856 * @param throwableClass Class<T>; throwable class to catch
857 * @param <T> throwable type
858 */
859 public static <T extends Throwable> void testSucceed(final Execution execution, final Class<T> throwableClass)
860 {
861 testSucceed(execution, null, throwableClass);
862 }
863
864 /**
865 * Fails if the execution does not succeed.
866 * @param execution Execution; functional interface to execute
867 * @param message String; fail message
868 * @param throwableClass Class<T>; throwable class to catch
869 * @param <T> throwable type
870 */
871 public static <T extends Throwable> void testSucceed(final Execution execution, final String message,
872 final Class<T> throwableClass)
873 {
874 try
875 {
876 execution.execute();
877 }
878 catch (Throwable cause)
879 {
880 if (throwableClass.isAssignableFrom(cause.getClass()))
881 {
882 throw new AssertionError(message);
883 }
884 else
885 {
886 throw new AssertionError("Execution failed on unexpected Throwable, expected (" + throwableClass.getSimpleName()
887 + "), but got (" + cause.getClass().getSimpleName() + ").");
888 }
889 }
890 }
891
892 // Interfaces
893
894 /**
895 * Functional interface for calls to Try.assign(...). For this a lambda expression can be used.
896 *
897 * <pre>
898 * FileInputStream fis = Try.assign(() -> new FileInputStream(fileString), IllegalArgumentException.class,
899 * "File %s is not a valid file.", fileString);
900 * </pre>
901 * <p>
902 * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
903 * <br>
904 * BSD-style license. See <a href="https://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
905 * <p>
906 * @version $Revision$, $LastChangedDate$, by $Author$, initial version 31 jan. 2018 <br>
907 * @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
908 * @author <a href="https://www.tudelft.nl/staff/p.knoppers/">Peter Knoppers</a>
909 * @author <a href="https://www.transport.citg.tudelft.nl">Wouter Schakel</a>
910 * @param <V> value type
911 */
912 @FunctionalInterface
913 public interface Assignment<V>
914 {
915 /**
916 * Returns a value which is obtained from the context in which the Assignment was created.
917 * @return value which is obtained from the context in which the Assignment was created
918 * @throws Throwable on any throwable in the try
919 */
920 V assign() throws Throwable;
921 }
922
923 /**
924 * Functional interface for calls to Try.execute(...). For this a lambda expression can be used.
925 *
926 * <pre>
927 * Try.execute(() -> fis.close(), "Could not close the file.");
928 * </pre>
929 * <p>
930 * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
931 * <br>
932 * BSD-style license. See <a href="https://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
933 * <p>
934 * @version $Revision$, $LastChangedDate$, by $Author$, initial version 31 jan. 2018 <br>
935 * @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
936 * @author <a href="https://www.tudelft.nl/staff/p.knoppers/">Peter Knoppers</a>
937 * @author <a href="https://www.transport.citg.tudelft.nl">Wouter Schakel</a>
938 */
939 @FunctionalInterface
940 public interface Execution
941 {
942 /**
943 * Executes some code using the context in which the Execution was created.
944 * @throws Throwable on any throwable in the try
945 */
946 void execute() throws Throwable;
947 }
948
949 }