Try.java

  1. package org.opentrafficsim.core.gtu;

  2. import static org.junit.Assert.fail;

  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. import nl.tudelft.simulation.language.reflection.ClassUtil;

  9. /**
  10.  * The Try class has a number of static methods that make it easy to try-catch an exception for any Throwable class, including
  11.  * the standard Java exceptions and exceptions from libraries that are used in the project. Instead of:
  12.  *
  13.  * <pre>
  14.  * FileInputStream fis;
  15.  * try
  16.  * {
  17.  *     fis = new FileInputStream(fileString);
  18.  * }
  19.  * catch (FileNotFoundException exception)
  20.  * {
  21.  *     throw new IllegalArgumentException("File " + fileString + " is not a valid file.", exception);
  22.  * }
  23.  * try
  24.  * {
  25.  *     fis.close();
  26.  * }
  27.  * catch (IOException exception)
  28.  * {
  29.  *     throw new RuntimeException("Could not close the file.", exception);
  30.  * }
  31.  * </pre>
  32.  *
  33.  * we can write:
  34.  *
  35.  * <pre>
  36.  * FileInputStream fis = Try.assign(() -&gt; new FileInputStream(fileString), IllegalArgumentException.class,
  37.  *         "File %s is not a valid file.", fileString);
  38.  * Try.execute(() -&gt; fis.close(), "Could not close the file.");
  39.  * </pre>
  40.  *
  41.  * The exception message can be formatted with additional arguments, such that the overhead of building the exception message
  42.  * only occurs if the exception condition is met. For each method there is a version without Throwable class, in which case a
  43.  * RuntimeException will be thrown.<br>
  44.  * <br>
  45.  * Try is not suitable for try-with-resource statements.<br>
  46.  * <br>
  47.  * Try also has a few methods to aid JUNIT tests: {@code testFail(...)} and {@code testNotFail(...)}.
  48.  * <p>
  49.  * Copyright (c) 2013-2018 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
  50.  * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
  51.  * <p>
  52.  * @version $Revision$, $LastChangedDate$, by $Author$, initial version 31 jan. 2018 <br>
  53.  * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
  54.  * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
  55.  * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
  56.  */
  57. public final class Try
  58. {
  59.     /** private constructor for utility class. */
  60.     private Try()
  61.     {
  62.         // utility class
  63.     }

  64.     // Assign

  65.     /**
  66.      * Tries to return a value to assign. Will throw a RuntimeException if the try fails.
  67.      * @param assignment Assignment&lt;V&gt;; functional interface to assign value
  68.      * @param message String; the message to use in the throwable
  69.      * @param <V> value type
  70.      * @return V; value to assign
  71.      * @throws RuntimeException on failed Try
  72.      */
  73.     public static <V> V assign(final Assignment<V> assignment, final String message) throws RuntimeException
  74.     {
  75.         try
  76.         {
  77.             return assignment.assign();
  78.         }
  79.         catch (Throwable cause)
  80.         {
  81.             throw catchThrowable(RuntimeException.class, message, new ArrayList<>(), cause);
  82.         }
  83.     }

  84.     /**
  85.      * Tries to return a value to assign. Will throw a RuntimeException if the try fails.
  86.      * @param assignment Assignment&lt;V&gt;; functional interface to assign value
  87.      * @param message String; the message to use in the throwable, with formatting identifier
  88.      * @param arg Object; value to use for the formatting identifier
  89.      * @param <V> value type
  90.      * @return V; value to assign
  91.      * @throws RuntimeException on failed Try
  92.      */
  93.     public static <V> V assign(final Assignment<V> assignment, final String message, final Object arg) throws RuntimeException
  94.     {
  95.         try
  96.         {
  97.             return assignment.assign();
  98.         }
  99.         catch (Throwable cause)
  100.         {
  101.             List<Object> argList = new ArrayList<>();
  102.             argList.add(arg);
  103.             throw catchThrowable(RuntimeException.class, message, argList, cause);
  104.         }
  105.     }

  106.     /**
  107.      * Tries to return a value to assign. Will throw a RuntimeException if the try fails.
  108.      * @param assignment Assignment&lt;V&gt;; functional interface to assign value
  109.      * @param message String; the message to use in the throwable, with formatting identifiers
  110.      * @param arg1 Object; 1st value to use for the formatting identifiers
  111.      * @param arg2 Object; 2nd value to use for the formatting identifiers
  112.      * @param <V> value type
  113.      * @return V; value to assign
  114.      * @throws RuntimeException on failed Try
  115.      */
  116.     public static <V> V assign(final Assignment<V> assignment, final String message, final Object arg1, final Object arg2)
  117.             throws RuntimeException
  118.     {
  119.         try
  120.         {
  121.             return assignment.assign();
  122.         }
  123.         catch (Throwable cause)
  124.         {
  125.             List<Object> argList = new ArrayList<>();
  126.             argList.add(arg1);
  127.             argList.add(arg2);
  128.             throw catchThrowable(RuntimeException.class, message, argList, cause);
  129.         }
  130.     }

  131.     /**
  132.      * Tries to return a value to assign. Will throw a RuntimeException if the try fails.
  133.      * @param assignment Assignment&lt;V&gt;; functional interface to assign value
  134.      * @param message String; the message to use in the throwable, with formatting identifiers
  135.      * @param arg1 Object; 1st value to use for the formatting identifiers
  136.      * @param arg2 Object; 2nd value to use for the formatting identifiers
  137.      * @param arg3 Object; 3rd value to use for the formatting identifiers
  138.      * @param <V> value type
  139.      * @return V; value to assign
  140.      * @throws RuntimeException on failed Try
  141.      */
  142.     public static <V> V assign(final Assignment<V> assignment, final String message, final Object arg1, final Object arg2,
  143.             final Object arg3) throws RuntimeException
  144.     {
  145.         try
  146.         {
  147.             return assignment.assign();
  148.         }
  149.         catch (Throwable cause)
  150.         {
  151.             List<Object> argList = new ArrayList<>();
  152.             argList.add(arg1);
  153.             argList.add(arg2);
  154.             argList.add(arg3);
  155.             throw catchThrowable(RuntimeException.class, message, argList, cause);
  156.         }
  157.     }

  158.     /**
  159.      * Tries to return a value to assign. Will throw a RuntimeException if the try fails.
  160.      * @param assignment Assignment&lt;V&gt;; functional interface to assign value
  161.      * @param message String; the message to use in the throwable, with formatting identifiers
  162.      * @param arg1 Object; 1st value to use for the formatting identifiers
  163.      * @param arg2 Object; 2nd value to use for the formatting identifiers
  164.      * @param arg3 Object; 3rd value to use for the formatting identifiers
  165.      * @param args Object...; potential 4th and further values to use for the formatting identifiers
  166.      * @param <V> value type
  167.      * @return V; value to assign
  168.      * @throws RuntimeException on failed Try
  169.      */
  170.     public static <V> V assign(final Assignment<V> assignment, final String message, final Object arg1, final Object arg2,
  171.             final Object arg3, final Object... args) throws RuntimeException
  172.     {
  173.         try
  174.         {
  175.             return assignment.assign();
  176.         }
  177.         catch (Throwable cause)
  178.         {
  179.             List<Object> argList = new ArrayList<>();
  180.             argList.add(arg1);
  181.             argList.add(arg2);
  182.             argList.add(arg3);
  183.             argList.addAll(Arrays.asList(args));
  184.             throw catchThrowable(RuntimeException.class, message, argList, cause);
  185.         }
  186.     }

  187.     /**
  188.      * Tries to return a value to assign. Will throw a specified Throwable if the try fails.
  189.      * @param assignment Assignment&lt;V&gt;; functional interface to assign value
  190.      * @param throwableClass Class&lt;T&gt;; class of the throwable to throw
  191.      * @param message String; the message to use in the throwable
  192.      * @param <V> value type
  193.      * @param <T> throwable type
  194.      * @return V; value to assign
  195.      * @throws T throwable on failed Try
  196.      */
  197.     public static <V, T extends Throwable> V assign(final Assignment<V> assignment, final Class<T> throwableClass,
  198.             final String message) throws T
  199.     {
  200.         try
  201.         {
  202.             return assignment.assign();
  203.         }
  204.         catch (Throwable cause)
  205.         {
  206.             throw catchThrowable(throwableClass, message, new ArrayList<>(), cause);
  207.         }
  208.     }

  209.     /**
  210.      * Tries to return a value to assign. Will throw a specified Throwable if the try fails.
  211.      * @param assignment Assignment&lt;V&gt;; functional interface to assign value
  212.      * @param throwableClass Class&lt;T&gt;; class of the throwable to throw
  213.      * @param message String; the message to use in the throwable, with formatting identifier
  214.      * @param arg Object; value to use for the formatting identifier
  215.      * @param <V> value type
  216.      * @param <T> throwable type
  217.      * @return V; value to assign
  218.      * @throws T throwable on failed Try
  219.      */
  220.     public static <V, T extends Throwable> V assign(final Assignment<V> assignment, final Class<T> throwableClass,
  221.             final String message, final Object arg) throws T
  222.     {
  223.         try
  224.         {
  225.             return assignment.assign();
  226.         }
  227.         catch (Throwable cause)
  228.         {
  229.             List<Object> argList = new ArrayList<>();
  230.             argList.add(arg);
  231.             throw catchThrowable(throwableClass, message, argList, cause);
  232.         }
  233.     }

  234.     /**
  235.      * Tries to return a value to assign. Will throw a specified Throwable if the try fails.
  236.      * @param assignment Assignment&lt;V&gt;; functional interface to assign value
  237.      * @param throwableClass Class&lt;T&gt;; class of the throwable to throw
  238.      * @param message String; the message to use in the throwable, with formatting identifiers
  239.      * @param arg1 Object; 1st value to use for the formatting identifiers
  240.      * @param arg2 Object; 2nd value to use for the formatting identifiers
  241.      * @param <V> value type
  242.      * @param <T> throwable type
  243.      * @return V; value to assign
  244.      * @throws T throwable on failed Try
  245.      */
  246.     public static <V, T extends Throwable> V assign(final Assignment<V> assignment, final Class<T> throwableClass,
  247.             final String message, final Object arg1, final Object arg2) throws T
  248.     {
  249.         try
  250.         {
  251.             return assignment.assign();
  252.         }
  253.         catch (Throwable cause)
  254.         {
  255.             List<Object> argList = new ArrayList<>();
  256.             argList.add(arg1);
  257.             argList.add(arg2);
  258.             throw catchThrowable(throwableClass, message, argList, cause);
  259.         }
  260.     }

  261.     /**
  262.      * Tries to return a value to assign. Will throw a specified Throwable if the try fails.
  263.      * @param assignment Assignment&lt;V&gt;; functional interface to assign value
  264.      * @param throwableClass Class&lt;T&gt;; class of the throwable to throw
  265.      * @param message String; the message to use in the throwable, with formatting identifiers
  266.      * @param arg1 Object; 1st value to use for the formatting identifiers
  267.      * @param arg2 Object; 2nd value to use for the formatting identifiers
  268.      * @param arg3 Object; 3rd value to use for the formatting identifiers
  269.      * @param <V> value type
  270.      * @param <T> throwable type
  271.      * @return V; value to assign
  272.      * @throws T throwable on failed Try
  273.      */
  274.     public static <V, T extends Throwable> V assign(final Assignment<V> assignment, final Class<T> throwableClass,
  275.             final String message, final Object arg1, final Object arg2, final Object arg3) throws T
  276.     {
  277.         try
  278.         {
  279.             return assignment.assign();
  280.         }
  281.         catch (Throwable cause)
  282.         {
  283.             List<Object> argList = new ArrayList<>();
  284.             argList.add(arg1);
  285.             argList.add(arg2);
  286.             argList.add(arg3);
  287.             throw catchThrowable(throwableClass, message, argList, cause);
  288.         }
  289.     }

  290.     /**
  291.      * Tries to return a value to assign. Will throw a specified Throwable if the try fails.
  292.      * @param assignment Assignment&lt;V&gt;; functional interface to assign value
  293.      * @param throwableClass Class&lt;T&gt;; class of the throwable to throw
  294.      * @param message String; the message to use in the throwable, with formatting identifiers
  295.      * @param arg1 Object; 1st value to use for the formatting identifiers
  296.      * @param arg2 Object; 2nd value to use for the formatting identifiers
  297.      * @param arg3 Object; 3rd value to use for the formatting identifiers
  298.      * @param args Object...; potential 4th and further values to use for the formatting identifiers
  299.      * @param <V> value type
  300.      * @param <T> throwable type
  301.      * @return V; value to assign
  302.      * @throws T throwable on failed Try
  303.      */
  304.     public static <V, T extends Throwable> V assign(final Assignment<V> assignment, final Class<T> throwableClass,
  305.             final String message, final Object arg1, final Object arg2, final Object arg3, final Object... args) throws T
  306.     {
  307.         try
  308.         {
  309.             return assignment.assign();
  310.         }
  311.         catch (Throwable cause)
  312.         {
  313.             List<Object> argList = new ArrayList<>();
  314.             argList.add(arg1);
  315.             argList.add(arg2);
  316.             argList.add(arg3);
  317.             argList.addAll(Arrays.asList(args));
  318.             throw catchThrowable(throwableClass, message, argList, cause);
  319.         }
  320.     }

  321.     // Execute

  322.     /**
  323.      * Tries to execute. Will throw a RuntimeException if the try fails.
  324.      * @param execution Execution; functional interface to execute
  325.      * @param message String; the message to use in the throwable
  326.      * @throws RuntimeException on failed Try
  327.      */
  328.     public static void execute(final Execution execution, final String message) throws RuntimeException
  329.     {
  330.         try
  331.         {
  332.             execution.execute();
  333.         }
  334.         catch (Throwable cause)
  335.         {
  336.             throw catchThrowable(RuntimeException.class, message, new ArrayList<>(), cause);
  337.         }
  338.     }

  339.     /**
  340.      * Tries to execute. Will throw a RuntimeException if the try fails.
  341.      * @param execution Execution; functional interface to execute
  342.      * @param message String; the message to use in the throwable, with formatting identifier
  343.      * @param arg Object; value to use for the formatting identifier
  344.      * @throws RuntimeException on failed Try
  345.      */
  346.     public static void execute(final Execution execution, final String message, final Object arg) throws RuntimeException
  347.     {
  348.         try
  349.         {
  350.             execution.execute();
  351.         }
  352.         catch (Throwable cause)
  353.         {
  354.             List<Object> argList = new ArrayList<>();
  355.             argList.add(arg);
  356.             throw catchThrowable(RuntimeException.class, message, argList, cause);
  357.         }
  358.     }

  359.     /**
  360.      * Tries to execute. Will throw a RuntimeException if the try fails.
  361.      * @param execution Execution; functional interface to execute
  362.      * @param message String; the message to use in the throwable, with formatting identifiers
  363.      * @param arg1 Object; 1st value to use for the formatting identifiers
  364.      * @param arg2 Object; 2nd value to use for the formatting identifiers
  365.      * @throws RuntimeException on failed Try
  366.      */
  367.     public static void execute(final Execution execution, final String message, final Object arg1, final Object arg2)
  368.             throws RuntimeException
  369.     {
  370.         try
  371.         {
  372.             execution.execute();
  373.         }
  374.         catch (Throwable cause)
  375.         {
  376.             List<Object> argList = new ArrayList<>();
  377.             argList.add(arg1);
  378.             argList.add(arg2);
  379.             throw catchThrowable(RuntimeException.class, message, argList, cause);
  380.         }
  381.     }

  382.     /**
  383.      * Tries to execute. Will throw a RuntimeException if the try fails.
  384.      * @param execution Execution; functional interface to execute
  385.      * @param message String; the message to use in the throwable, with formatting identifiers
  386.      * @param arg1 Object; 1st value to use for the formatting identifiers
  387.      * @param arg2 Object; 2nd value to use for the formatting identifiers
  388.      * @param arg3 Object; 3rd value to use for the formatting identifiers
  389.      * @throws RuntimeException on failed Try
  390.      */
  391.     public static void execute(final Execution execution, final String message, final Object arg1, final Object arg2,
  392.             final Object arg3) throws RuntimeException
  393.     {
  394.         try
  395.         {
  396.             execution.execute();
  397.         }
  398.         catch (Throwable cause)
  399.         {
  400.             List<Object> argList = new ArrayList<>();
  401.             argList.add(arg1);
  402.             argList.add(arg2);
  403.             argList.add(arg3);
  404.             throw catchThrowable(RuntimeException.class, message, argList, cause);
  405.         }
  406.     }

  407.     /**
  408.      * Tries to execute. Will throw a RuntimeException if the try fails.
  409.      * @param execution Execution; functional interface to execute
  410.      * @param message String; the message to use in the throwable, with formatting identifiers
  411.      * @param arg1 Object; 1st value to use for the formatting identifiers
  412.      * @param arg2 Object; 2nd value to use for the formatting identifiers
  413.      * @param arg3 Object; 3rd value to use for the formatting identifiers
  414.      * @param args Object...; potential 4th and further values to use for the formatting identifiers
  415.      * @throws RuntimeException on failed Try
  416.      */
  417.     public static void execute(final Execution execution, final String message, final Object arg1, final Object arg2,
  418.             final Object arg3, final Object... args) throws RuntimeException
  419.     {
  420.         try
  421.         {
  422.             execution.execute();
  423.         }
  424.         catch (Throwable cause)
  425.         {
  426.             List<Object> argList = new ArrayList<>();
  427.             argList.add(arg1);
  428.             argList.add(arg2);
  429.             argList.add(arg3);
  430.             argList.addAll(Arrays.asList(args));
  431.             throw catchThrowable(RuntimeException.class, message, argList, cause);
  432.         }
  433.     }

  434.     /**
  435.      * Tries to execute. Will throw a specified Throwable if the try fails.
  436.      * @param execution Execution; functional interface to execute
  437.      * @param throwableClass Class&lt;T&gt;; class of the throwable to throw
  438.      * @param message String; the message to use in the throwable
  439.      * @param <T> throwable type
  440.      * @throws T throwable on failed Try
  441.      */
  442.     public static <T extends Throwable> void execute(final Execution execution, final Class<T> throwableClass,
  443.             final String message) throws T
  444.     {
  445.         try
  446.         {
  447.             execution.execute();
  448.         }
  449.         catch (Throwable cause)
  450.         {
  451.             throw catchThrowable(throwableClass, message, new ArrayList<>(), cause);
  452.         }
  453.     }

  454.     /**
  455.      * Tries to execute. Will throw a specified Throwable if the try fails.
  456.      * @param execution Execution; functional interface to execute
  457.      * @param throwableClass Class&lt;T&gt;; class of the throwable to throw
  458.      * @param message String; the message to use in the throwable, with formatting identifier
  459.      * @param arg Object; value to use for the formatting identifier
  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, final Object arg) throws T
  465.     {
  466.         try
  467.         {
  468.             execution.execute();
  469.         }
  470.         catch (Throwable cause)
  471.         {
  472.             List<Object> argList = new ArrayList<>();
  473.             argList.add(arg);
  474.             throw catchThrowable(throwableClass, message, argList, cause);
  475.         }
  476.     }

  477.     /**
  478.      * Tries to execute. Will throw a specified Throwable if the try fails.
  479.      * @param execution Execution; functional interface to execute
  480.      * @param throwableClass Class&lt;T&gt;; class of the throwable to throw
  481.      * @param message String; the message to use in the throwable, with formatting identifiers
  482.      * @param arg1 Object; 1st value to use for the formatting identifiers
  483.      * @param arg2 Object; 2nd value to use for the formatting identifiers
  484.      * @param <T> throwable type
  485.      * @throws T throwable on failed Try
  486.      */
  487.     public static <T extends Throwable> void execute(final Execution execution, final Class<T> throwableClass,
  488.             final String message, final Object arg1, final Object arg2) throws T
  489.     {
  490.         try
  491.         {
  492.             execution.execute();
  493.         }
  494.         catch (Throwable cause)
  495.         {
  496.             List<Object> argList = new ArrayList<>();
  497.             argList.add(arg1);
  498.             argList.add(arg2);
  499.             throw catchThrowable(throwableClass, message, argList, cause);
  500.         }
  501.     }

  502.     /**
  503.      * Tries to execute. Will throw a specified Throwable if the try fails.
  504.      * @param execution Execution; functional interface to execute
  505.      * @param throwableClass Class&lt;T&gt;; class of the throwable to throw
  506.      * @param message String; the message to use in the throwable, with formatting identifiers
  507.      * @param arg1 Object; 1st value to use for the formatting identifiers
  508.      * @param arg2 Object; 2nd value to use for the formatting identifiers
  509.      * @param arg3 Object; 3rd value to use for the formatting identifiers
  510.      * @param <T> throwable type
  511.      * @throws T throwable on failed Try
  512.      */
  513.     public static <T extends Throwable> void execute(final Execution execution, final Class<T> throwableClass,
  514.             final String message, final Object arg1, final Object arg2, final Object arg3) throws T
  515.     {
  516.         try
  517.         {
  518.             execution.execute();
  519.         }
  520.         catch (Throwable cause)
  521.         {
  522.             List<Object> argList = new ArrayList<>();
  523.             argList.add(arg1);
  524.             argList.add(arg2);
  525.             argList.add(arg3);
  526.             throw catchThrowable(throwableClass, message, argList, cause);
  527.         }
  528.     }

  529.     /**
  530.      * Tries to execute. Will throw a specified Throwable if the try fails.
  531.      * @param execution Execution; functional interface to execute
  532.      * @param throwableClass Class&lt;T&gt;; class of the throwable to throw
  533.      * @param message String; the message to use in the throwable, with formatting identifiers
  534.      * @param arg1 Object; 1st value to use for the formatting identifiers
  535.      * @param arg2 Object; 2nd value to use for the formatting identifiers
  536.      * @param arg3 Object; 3rd value to use for the formatting identifiers
  537.      * @param args Object...; potential 4th and further values to use for the formatting identifiers
  538.      * @param <T> throwable type
  539.      * @throws T throwable on failed Try
  540.      */
  541.     public static <T extends Throwable> void execute(final Execution execution, final Class<T> throwableClass,
  542.             final String message, final Object arg1, final Object arg2, final Object arg3, final Object... args) throws T
  543.     {
  544.         try
  545.         {
  546.             execution.execute();
  547.         }
  548.         catch (Throwable cause)
  549.         {
  550.             List<Object> argList = new ArrayList<>();
  551.             argList.add(arg1);
  552.             argList.add(arg2);
  553.             argList.add(arg3);
  554.             argList.addAll(Arrays.asList(args));
  555.             throw catchThrowable(throwableClass, message, argList, cause);
  556.         }
  557.     }

  558.     // Core of assign/execute methods

  559.     /**
  560.      * Core method to create the Throwable to throw.
  561.      * @param throwableClass Class&lt;T&gt;; the throwable class
  562.      * @param message String; the message to construct when an exception is thrown.
  563.      * @param argList List&lt;Object&gt; the arguments as implied by format escapes in <code>message</code>
  564.      * @param cause Throwable; underlying cause thrown inside the assign()/execute()
  565.      * @param <T> throwable type
  566.      * @return T; throwable
  567.      */
  568.     private static <T extends Throwable> T catchThrowable(final Class<T> throwableClass, final String message,
  569.             final List<Object> argList, final Throwable cause)
  570.     {
  571.         // create a clear message
  572.         List<StackTraceElement> steList = new ArrayList<>(Arrays.asList(new Throwable().getStackTrace()));
  573.         steList.remove(0); // remove the catchThrowable(...) call
  574.         steList.remove(0); // remove the Attemp.assign/execute(...) call
  575.         StackTraceElement[] ste = steList.toArray(new StackTraceElement[steList.size()]);
  576.         String where = ste[0].getClassName() + "." + ste[0].getMethodName() + " (" + ste[0].getLineNumber() + "): ";
  577.         Object[] args = argList.toArray();
  578.         String formattedMessage;
  579.         try
  580.         {
  581.             formattedMessage = where + String.format(message, args);
  582.         }
  583.         catch (IllegalFormatException exception)
  584.         {
  585.             formattedMessage = where + message + " [FormatException; args=" + argList + "]";
  586.         }

  587.         // throw all other exceptions through reflection
  588.         T exception;
  589.         try
  590.         {
  591.             @SuppressWarnings("unchecked")
  592.             Constructor<T> constructor = (Constructor<T>) ClassUtil.resolveConstructor(throwableClass,
  593.                     new Class<?>[] { String.class, Throwable.class });
  594.             List<StackTraceElement> steCause = new ArrayList<>(Arrays.asList(cause.getStackTrace()));
  595.             steCause.remove(steCause.size() - 1); // remove method that called Attemp.assign/execute(...) as that's in steList
  596.             steCause.remove(steCause.size() - 1); // remove the Attemp.assign/execute(...) call
  597.             steCause.remove(steCause.size() - 1); // remove the Assignment/Execution implementation (can be lambda$#)
  598.             cause.setStackTrace(steCause.toArray(new StackTraceElement[steCause.size()]));
  599.             exception = constructor.newInstance(formattedMessage, cause);
  600.             exception.setStackTrace(ste);
  601.         }
  602.         catch (Throwable t)
  603.         {
  604.             RuntimeException rte = new RuntimeException(t.getMessage(), new Exception(formattedMessage, cause));
  605.             rte.setStackTrace(ste);
  606.             throw rte;
  607.         }
  608.         return exception;
  609.     }

  610.     // Test fail/succeed (JUNIT)

  611.     /**
  612.      * Executes a JUNIT fail if the assignment succeeds.
  613.      * @param assignment Assignment&lt;V&gt;; functional interface to assign value
  614.      * @param <V> value type
  615.      * @return V; value to assign
  616.      */
  617.     public static <V> V testFail(final Assignment<V> assignment)
  618.     {
  619.         return testFail(assignment, null, Throwable.class);
  620.     }

  621.     /**
  622.      * Executes a JUNIT fail if the assignment succeeds.
  623.      * @param assignment Assignment&lt;V&gt;; functional interface to assign value
  624.      * @param message String; fail message
  625.      * @param <V> value type
  626.      * @return V; value to assign
  627.      */
  628.     public static <V> V testFail(final Assignment<V> assignment, final String message)
  629.     {
  630.         return testFail(assignment, message, Throwable.class);
  631.     }

  632.     /**
  633.      * Executes a JUNIT fail if the assignment succeeds.
  634.      * @param assignment Assignment&lt;V&gt;; functional interface to assign value
  635.      * @param throwableClass Class&lt;T&gt;; throwable class to catch
  636.      * @param <V> value type
  637.      * @param <T> throwable type
  638.      * @return V; value to assign
  639.      */
  640.     public static <V, T extends Throwable> V testFail(final Assignment<V> assignment, final Class<T> throwableClass)
  641.     {
  642.         return testFail(assignment, null, throwableClass);
  643.     }

  644.     /**
  645.      * Executes a JUNIT fail if the assignment succeeds.
  646.      * @param assignment Assignment&lt;V&gt;; functional interface to assign value
  647.      * @param message String; fail message
  648.      * @param throwableClass Class&lt;T&gt;; throwable class to catch
  649.      * @param <V> value type
  650.      * @param <T> throwable type
  651.      * @return V; value to assign
  652.      */
  653.     public static <V, T extends Throwable> V testFail(final Assignment<V> assignment, final String message,
  654.             final Class<T> throwableClass)
  655.     {
  656.         V value;
  657.         try
  658.         {
  659.             value = assignment.assign();
  660.             fail(message);
  661.         }
  662.         catch (Throwable cause)
  663.         {
  664.             if (!throwableClass.isAssignableFrom(cause.getClass()))
  665.             {
  666.                 throw new AssertionError("Assignment failed on unexpected Throwable, expected ("
  667.                         + throwableClass.getSimpleName() + "), but got (" + cause.getClass().getSimpleName() + ").");
  668.             }
  669.             // expected to fail
  670.             value = null;
  671.         }
  672.         return value;
  673.     }

  674.     /**
  675.      * Executes a JUNIT fail if the assignment does not succeed.
  676.      * @param assignment Assignment&lt;V&gt;; functional interface to assign value
  677.      * @param <V> value type
  678.      * @return V; value to assign
  679.      */
  680.     public static <V> V testSucceed(final Assignment<V> assignment)
  681.     {
  682.         return testSucceed(assignment, null, Throwable.class);
  683.     }

  684.     /**
  685.      * Executes a JUNIT fail if the assignment does not succeed.
  686.      * @param assignment Assignment&lt;V&gt;; functional interface to assign value
  687.      * @param message String; fail message
  688.      * @param <V> value type
  689.      * @return V; value to assign
  690.      */
  691.     public static <V> V testSucceed(final Assignment<V> assignment, final String message)
  692.     {
  693.         return testSucceed(assignment, message, Throwable.class);
  694.     }

  695.     /**
  696.      * Executes a JUNIT fail if the assignment does not succeed.
  697.      * @param assignment Assignment&lt;V&gt;; functional interface to assign value
  698.      * @param throwableClass Class&lt;T&gt;; throwable class to catch
  699.      * @param <V> value type
  700.      * @param <T> throwable type
  701.      * @return V; value to assign
  702.      */
  703.     public static <V, T extends Throwable> V testSucceed(final Assignment<V> assignment, final Class<T> throwableClass)
  704.     {
  705.         return testSucceed(assignment, null, throwableClass);
  706.     }

  707.     /**
  708.      * Executes a JUNIT fail if the assignment does not succeed.
  709.      * @param assignment Assignment&lt;V&gt;; functional interface to assign value
  710.      * @param message String; fail message
  711.      * @param throwableClass Class&lt;T&gt;; throwable class to catch
  712.      * @param <V> value type
  713.      * @param <T> throwable type
  714.      * @return V; value to assign
  715.      */
  716.     public static <V, T extends Throwable> V testSucceed(final Assignment<V> assignment, final String message,
  717.             final Class<T> throwableClass)
  718.     {
  719.         V value;
  720.         try
  721.         {
  722.             value = assignment.assign();
  723.         }
  724.         catch (Throwable cause)
  725.         {
  726.             if (throwableClass.isAssignableFrom(cause.getClass()))
  727.             {
  728.                 fail(message);
  729.                 value = null;
  730.             }
  731.             else
  732.             {
  733.                 throw new AssertionError("Assignment failed on unexpected Throwable, expected ("
  734.                         + throwableClass.getSimpleName() + "), but got (" + cause.getClass().getSimpleName() + ").");
  735.             }
  736.         }
  737.         return value;
  738.     }

  739.     /**
  740.      * Executes a JUNIT fail if the execution succeeds.
  741.      * @param execution Execution; functional interface to execute
  742.      */
  743.     public static void testFail(final Execution execution)
  744.     {
  745.         testFail(execution, null, Throwable.class);
  746.     }

  747.     /**
  748.      * Executes a JUNIT fail if the execution succeeds.
  749.      * @param execution Execution; functional interface to execute
  750.      * @param message String; fail message
  751.      */
  752.     public static void testFail(final Execution execution, final String message)
  753.     {
  754.         testFail(execution, message, Throwable.class);
  755.     }

  756.     /**
  757.      * Executes a JUNIT fail if the execution succeeds.
  758.      * @param execution Execution; functional interface to execute
  759.      * @param throwableClass Class&lt;T&gt;; throwable class to catch
  760.      * @param <T> throwable type
  761.      */
  762.     public static <T extends Throwable> void testFail(final Execution execution, final Class<T> throwableClass)
  763.     {
  764.         testFail(execution, null, throwableClass);
  765.     }

  766.     /**
  767.      * Executes a JUNIT fail if the execution succeeds.
  768.      * @param execution Execution; functional interface to execute
  769.      * @param message String; fail message
  770.      * @param throwableClass Class&lt;T&gt;; throwable class to catch
  771.      * @param <T> throwable type
  772.      */
  773.     public static <T extends Throwable> void testFail(final Execution execution, final String message,
  774.             final Class<T> throwableClass)
  775.     {
  776.         try
  777.         {
  778.             execution.execute();
  779.             fail(message);
  780.         }
  781.         catch (Throwable cause)
  782.         {
  783.             if (!throwableClass.isAssignableFrom(cause.getClass()))
  784.             {
  785.                 throw new AssertionError("Execution failed on unexpected Throwable, expected (" + throwableClass.getSimpleName()
  786.                         + "), but got (" + cause.getClass().getSimpleName() + ").");
  787.             }
  788.             // expected to fail
  789.         }
  790.     }

  791.     /**
  792.      * Executes a JUNIT fail if the execution does not succeed.
  793.      * @param execution Execution; functional interface to execute
  794.      */
  795.     public static void testSucceed(final Execution execution)
  796.     {
  797.         testSucceed(execution, null, Throwable.class);
  798.     }

  799.     /**
  800.      * Executes a JUNIT fail if the execution does not succeed.
  801.      * @param execution Execution; functional interface to execute
  802.      * @param message String; fail message
  803.      */
  804.     public static void testSucceed(final Execution execution, final String message)
  805.     {
  806.         testSucceed(execution, message, Throwable.class);
  807.     }

  808.     /**
  809.      * Executes a JUNIT fail if the execution does not succeed.
  810.      * @param execution Execution; functional interface to execute
  811.      * @param throwableClass Class&lt;T&gt;; throwable class to catch
  812.      * @param <T> throwable type
  813.      */
  814.     public static <T extends Throwable> void testSucceed(final Execution execution, final Class<T> throwableClass)
  815.     {
  816.         testSucceed(execution, null, throwableClass);
  817.     }

  818.     /**
  819.      * Executes a JUNIT fail if the execution does not succeed.
  820.      * @param execution Execution; functional interface to execute
  821.      * @param message String; fail message
  822.      * @param throwableClass Class&lt;T&gt;; throwable class to catch
  823.      * @param <T> throwable type
  824.      */
  825.     public static <T extends Throwable> void testSucceed(final Execution execution, final String message,
  826.             final Class<T> throwableClass)
  827.     {
  828.         try
  829.         {
  830.             execution.execute();
  831.         }
  832.         catch (Throwable cause)
  833.         {
  834.             if (throwableClass.isAssignableFrom(cause.getClass()))
  835.             {
  836.                 fail(message);
  837.             }
  838.             else
  839.             {
  840.                 throw new AssertionError("Execution failed on unexpected Throwable, expected (" + throwableClass.getSimpleName()
  841.                         + "), but got (" + cause.getClass().getSimpleName() + ").");
  842.             }
  843.         }
  844.     }

  845.     // Interfaces

  846.     /**
  847.      * Functional interface for calls to Try.assign(...). For this a lambda expression can be used.
  848.      *
  849.      * <pre>
  850.      * FileInputStream fis = Try.assign(() -&gt; new FileInputStream(fileString), IllegalArgumentException.class,
  851.      *         "File %s is not a valid file.", fileString);
  852.      * </pre>
  853.      * <p>
  854.      * Copyright (c) 2013-2018 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
  855.      * <br>
  856.      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
  857.      * <p>
  858.      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 31 jan. 2018 <br>
  859.      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
  860.      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
  861.      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
  862.      * @param <V> value type
  863.      */
  864.     @FunctionalInterface
  865.     public interface Assignment<V>
  866.     {
  867.         /**
  868.          * Returns a value which is obtained from the context in which the Assignment was created.
  869.          * @return value which is obtained from the context in which the Assignment was created
  870.          * @throws Throwable on any throwable in the try
  871.          */
  872.         V assign() throws Throwable;
  873.     }

  874.     /**
  875.      * Functional interface for calls to Try.execute(...). For this a lambda expression can be used.
  876.      *
  877.      * <pre>
  878.      * Try.execute(() -&gt; fis.close(), "Could not close the file.");
  879.      * </pre>
  880.      * <p>
  881.      * Copyright (c) 2013-2018 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
  882.      * <br>
  883.      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
  884.      * <p>
  885.      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 31 jan. 2018 <br>
  886.      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
  887.      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
  888.      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
  889.      */
  890.     @FunctionalInterface
  891.     public interface Execution
  892.     {
  893.         /**
  894.          * Executes some code using the context in which the Execution was created.
  895.          * @throws Throwable on any throwable in the try
  896.          */
  897.         void execute() throws Throwable;
  898.     }

  899. }