1

I am writing a method that basically does one simple thing, log the error message and throw a runtime exception using the same error message. I want it to be able to throw any child exception of RuntimeException. The method I have got is:

public static <T extends RuntimeException> void logErrorAndThrowException(Logger logger, String errorMessage, Class<T> exceptionClazz) throws T {
        logger.error(errorMessage);
        RuntimeException runtimeException = new RuntimeException(errorMessage);
        throw exceptionClazz.cast(runtimeException);   // Not work!!
    }

I have have this exception defined:

public final class MyException extends RuntimeException {
    public MyException() {
    }

    public MyException(String message) {
        super(message);
    }

    public MyException(Throwable cause) {
        super(cause);
    }

    public MyException(String message, Throwable cause) {
        super(message, cause);
    }
}

I then invoke the method using:

   logErrorAndThrowException(logger, "This is an error message", MyException.class);

The commented line above will fail with an cast exception. I then tried another implementation of:

public static <T extends RuntimeException> void logWarningAndThrowException(Logger logger, String errorMessage, Class<T> exceptionClazz) throws T {
    logger.error(errorMessage);
    try {
        throw exceptionClazz.newInstance();
    } catch (InstantiationException e) {
        // handle
    } catch (IllegalAccessException e) {
        // handle
    }
}

With this implementation, I can only invoke the no-arg constructor of my exception hence cannot set the error message.

Can anyone help with this?

2
  • If you declare your method to throw E then you can make it throw E1, E2 etc which are subclasses of E. Unfortunately, exceptions and generics don't mix too well...
    – fge
    Commented Jun 14, 2013 at 7:53
  • 2
    The more standard solution (and thus, easier to understand for others etc.) is to wrap the Exception as a cause: throw new RuntimeException(myException). This avoids the above problems and keeps the stack trace of the original exception (not just the message), which often helps with debugging. Commented Jun 14, 2013 at 8:05

2 Answers 2

5

You first need to grab the appropriate constructor for your exception class before you instantiate it. When you do:

throw exceptionClazz.cast(runtimeException);   // Not work!!

this cannot work since your class is a subclass of RuntimeException.

You can do:

final Constructor<T> c = exceptionClazz.getConstructor(String.class);
throw c.newInstance(theMessage);

But, really, don't: you'll have to deal with all possible exceptions of those two reflection methods...

Another solution, which does not involve reflection, would be to have an interface such as:

public interface ExceptionCreator<T extends RuntimeException>
{
    T doException(String whatsWrong);
}

then you have an IdentityHashMap:

// IdentityHashMap because all Class objects are singletons
private static final Map<Class<? extends RuntimeException>, ExceptionCreator<?>> MAP
    = new IdentityHashMap<>;


// fill the map in a static initialization block

Your method would then be:

public static <T extends RuntimeException> void logErrorAndThrowException(Logger logger,     
    String errorMessage, Class<T> exceptionClazz) throws T
{
    logger.error(errorMessage);
    // Note: no checks for null here. If null, just throw a "plain" RuntimeException
    throw MAP.get(exceptionClazz).doException(errorMessage);
}
3
  • 1
    That's the solution I thought of. Commented Jun 14, 2013 at 9:36
  • this seems so complex, are you sure you can't just create the exception where you want to log the error?
    – kutschkem
    Commented Jun 14, 2013 at 12:21
  • @kutschkem not my choice, the OP's ;) I just gave a possible solution to the expressed need ;)
    – fge
    Commented Jun 14, 2013 at 12:27
1

You can create an Exception without throwing it. Since you need to know the class anyway for your method, use the RuntimeException directly as a parameter. There is no point in trying to use reflection here imho.

public static <T extends RuntimeException> void logErrorAndThrowException(Logger logger, T exception) throws T {
    logger.error(exception.getMessage());
    throw exception;   // works !!! ;-)
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.