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.
Advertisement
Answer
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)