Discussions

J2EE patterns: Easy and correct exception chaining

  1. Easy and correct exception chaining (4 messages)

    The utility class Rethrow<T extends Exception> has a single method wrap(String msg, Throwable t) which does the following:

    * Checks if t is a RuntimeException or Error, if so immediately rethrows the exception.
    * Checks if t is already an instance of T, if so returns t.
    * Returns a new instance of the target exception class.

    To use, declare a static final instance of Rethrow on your own exception class:

    public class MyException extends RuntimeException {
       public static final Rethrow<MyException> rethrow =
          new Rethrow<MyException>();
       public MyException(String msg, Throwable t) {
          super(msg,t);
       }
    }

    Then later:

       try {
          ... do something that might throw exceptions ...
       } catch (Exception e) {
          throw MyException.rethrow.wrap(e);
       }

    Full version of Rethrow included below:

    import java.lang.reflect.Constructor;
    import java.util.logging.Level;
    import java.util.logging.Logger;

    /**
     * Utility class to wrap a caught exception in a (subclass of) RuntimeException.
     */
    public class Rethrow<T extends Exception> {
        private static final Logger _logger = Logger.getLogger("rethrow");
        public static final Rethrow<RuntimeException> runtime =
            new Rethrow<RuntimeException>(RuntimeException.class);
        private Class<T> _class;
        private Constructor<T> _constructor;
        public Rethrow(Class<T> c) {
            _class = c;
            try {
                _constructor = c.getConstructor(new Class[] { String.class, Throwable.class });
            } catch (Exception e) {
                _logger.log(Level.WARNING, "could not get exception wrapper class constructor", e);
            }
        }
        @SuppressWarnings("unchecked")
        public T wrap(String msg, Throwable e) {
            if (e instanceof RuntimeException) {
                throw (RuntimeException) e;
            } else if (e instanceof Error) {
                throw (Error) e;
            } else if (_class.isAssignableFrom(e.getClass())) {
                return (T) e;
            } else {
                if (_constructor != null) {
                    try {
                        return _constructor.newInstance(new Object[] { msg, e });
                    } catch (Exception e1) {
                        _logger.log(Level.WARNING, "could not create instance of " + _class
                                + ", using RuntimeException instead", e1);
                    }
                }
                throw new RuntimeException(msg, e);
            }
        }
    }

    Threaded Messages (4)

  2. Is it really that simple?[ Go to top ]

    Can't you just put this in the Exception constructor?

    if (e instanceof RuntimeException) {
        throw (RuntimeException) e;
    } else if (e instanceof Error) {
        throw (Error) e;
    }
  3. Is it really that simple?[ Go to top ]

    While you could put the checks in a constructor that you own, I think throwing an exception in a constructor (almost as a side effect) is bad style. The model I have in my head is that "new SomeException()" creates the exception. It shouldn't throw an exception, unless preceded with "throw".

    Also, what you suggest won't work for exceptions that you don't control.
  4. Is it really that simple?[ Go to top ]

    Saying something is bad style is pretty meaningless without a pragmatic reason.

    However, I see now that I misunderstood what your code was doing, I thought you were defining an Exception class. It would be nice to have some code formatting here, TSS.
  5. Is it really that simple?[ Go to top ]

    I believe I saw this same exact thing on the Bile Blog. (not that it ever gets read). However, I've seen some very cool uses of Java 5 with Exceptions. One of which is undoing the String message anti-pattern and using an enum instead. That allows the catcher of the exception to go through a list of "likely reasons". In addiction, objects that are found to be part of the problem should often be used instead of String found in the constructor of Exception. I'd prevent it's use.