Matteo NNZ
Matteo NNZ

Reputation: 12655

Ability to throw an exception type provided by the caller

I have a generic function which does something and, in case of failure, it should throw a specific exception.

To simplify you can imagine it as such:

public static <E extends Exception> void doSomething(Class<E> exceptionClass) throws E {
    try {
        //Do stuff
    } catch (Exception e) {
        String message = "...";
        //-> here I want to throw a new exception of type E with the message I built above and the caught exception as cause
    }
}

In order to do that, what I can think about is to build a new E by reflection and throw an unchecked exception if any of the exceptions that can be thrown during reflection is actually thrown:

public static <E extends Exception> buildException(Class<E> exceptionClass, String msg, Throwable cause) {
    try {
        return exceptionClass.getDeclaredConstructor(String.class, Throwable.class).newInstance(msg, cause);
    } catch (NoSuchMethodException ... e) {
        //Catch everything that can be thrown
        throw new RuntimeException(e);
    }
}

... and then call it simply throw buildException(exceptionClass, message, e) inside the main function.

However I don't like too much this solution because I need to get the class in parameter from the caller (while they are already inferring me the type via E) and I may as well have to throw a Runtime exception if my reflection operation fails (all E extends Exception so the constructor I look for should always be there, but we never know if the caller doesn't customize the exception too much...)

Although the drawbacks, I can't get anything better into my mind.

Does anyone have some better design ideas for this?

Note: about the need. I have several classes which perform the same operation (the "do stuff") but that need to throw a specific exception (class 1 throws exception 1, class 2 throws exception 2 etc.) which wraps any possible exception thrown while performing the "do stuff" operation. Of course I may move the catch on caller side but that would make a lot of code duplication for the exact same operation.

Upvotes: 2

Views: 66

Answers (1)

Tom
Tom

Reputation: 17567

Instead of passing the class and let the called method handle the exception creation you could let the calling method handle it instead. This is possible by accepting a function:

public static <E extends Exception> void doSomething(Function<String, E> exceptionFunction) throws E {
    try {
        //Do stuff
    } catch (Exception e) {
        String message = "...";
        throw exceptionFunction.apply(message);
    }
}

This function would expect a String, your message, and will then return an instance of the exception to be thrown. As you can see, you can trigger the function by using exceptionFunction.apply(message).

You can also use e to add the "cause" stacktrace:

public static <E extends Exception> void doSomething(Function<String, E> exceptionFunction) throws E {
    try {
        //Do stuff
    } catch (Exception e) {
        String message = "...";
        var exception = exceptionFunction.apply(message);
        exception.initCause(e);
        throw exception;
    }
}

The call of the doSomething method would then look like this:

doSomething((s) -> new MyException());

or if you prefer method references, like this:

doSomething(MyException::new);

(mind that MyException would need a constructor with a String parameter)

Upvotes: 1

Related Questions