I am not able to understand why Java doesn't allow to change exception message of an exception of type Exception (or its superclass Throwable) once it has been created. It allows to change the stackTrace using setStackTrace but not the message.
The use case I have seems genuine to me and would appreciate some alternative.
Use case
I have a controller service X that calls let's say 10 other dependent services. To make debugging easy, if a dependent service throws some exception we want to surface some identifiers from service X to its upstream to identify the failed request easily. For this we have requestId which we create and set for each dependency.
Now to avoid duplication across all dependent services and simplify code, we can create a common interceptor that allows us to do some work before and after each call. Something like -
// do some work
requestId = getRequestId(); // create or somehow get requestId
dependentService.setRequestId(requestId);
try {
dependentService.call();
}
catch (Exception e) {
e.setMessage(e.getMessage() + ... + requestId);
throw e;
}
//do some work
But Java doesn't allow us to set message. At the same time, we want to preserve the exception and its type (which could be any of the custom types defined by dependent services), so I don't want to do something like throw new Exception(e.getMessage() + ...)
All objects within the Java exception class hierarchy extend from the Throwable superclass. Only instances of Throwable (or an inherited subclass) are indirectly thrown by the Java Virtual Machine (JVM), or can be directly thrown via a throw statement.
Throwable is a class which Exception – and consequently all subclasses thereof – subclasses. There's nothing stopping you from using instanceof on a Throwable .
The Throwable class, which is an immediate subclass of Object, is at the root of the exception hierarchy. Throwable has two immediate subclasses: Exception and Error.
Throwing an exception is as simple as using the "throw" statement. You then specify the Exception object you wish to throw. Every Exception includes a message which is a human-readable error description. It can often be related to problems with user input, server, backend, etc.
It's not really what it's meant for, but you could attach another exception with addSuppressed
:
} catch (Exception e) {
e.addSuppressed(new ExtraInfoException(...));
throw e;
}
where ...
contains the extra info you want to include.
The advantage of this over adding to the exception message is that you can define your ExtraInfoException
so that it has the info you want in fields, rather than having to parse it back out of the exception message.
With that said, a more idiomatic way to attach more exception info it would be:
} catch (Exception e) {
throw new ExtraInfoException(e, ...);
}
which has exactly the same advantage of allowing you to return structured information, with the additional advantage that you can catch ExtraInfoException
directly, rather than catching Exception
and then hunting for the extra info reflectively.
Why doesn't Java have setMessage in Exception/Throwable classes?
The answer to your question is that they (the library designers) did not think that changing a message on an exception was a useful thing to do.
To a large degree1, the designers have taken the view that they shouldn't design the APIs to directly support all possible use-cases ... including the obscure ones that almost nobody will encounter. Like your one2.
And in your case, there are other ways to achieve what you are trying to do; see the other answers.
I did a quick search of the Java bugs database to see if someone else had put in an RFE to request a setMessage
method for Throwable
or Exception
. I couldn't find anything. If your requirement was even slightly common, there would probably be an RFE with an explanation of why it was declined.
1 - Obviously, there are exceptions to this, but that is beside the point.
2 - Obviously you would disagree that your use-case is obscure, but that that is also beside the point. The question is why they haven't implemented this, not whether they were wrong. (Asking / debating whether they were wrong is off-topic, because it is a matter of opinion.)
Resetting a message it's some kind of rewriting the history. You have a catch
block when you catch exception and handle them. If you need to throw an exception during the handling, it's a different problem and an exception should be different.
} catch (SomeException e) {
// here we have SomeException and we want to handle it.
// if we can't we throw a new one, because we have a problem with handling.
// if the handling problem cause is SomeException we put it at the cause.
throw new AnotherException("with some message", e);
}
And in the stacks trace we will see that we have AnotherException
because of SomeException
which gives us information about the root of problem.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With