On Wed, 22 Oct 2025 12:01:43 GMT, Jaikiran Pai <[email protected]> wrote:
>> OK - I think what you have is fine. Let's peel of UncheckedIOException. In
>> most cases I could see the UncheckedIOException is only used to smugle an
>> IOException, and in most case it's created at the point where the
>> IOException is created too. That let me think that the extra stack trace
>> will not be needed in most of the cases. We could revisit possibly later in
>> a followup if we have reason to...
>
> I think, not propagating the original `UncheckedIOException` would be a bug.
> Imagine this application code:
>
>
> final Future<HttpResponse<String>> future = client.sendAsync(req, new
> BodyHandler<String>() {
> @Override
> public BodySubscriber<String> apply(ResponseInfo ri) {
> throw new UncheckedIOException("application specific message", new
> IOException("some other message"));
> }
> });
> final HttpResponse<String> resp;
> try {
> resp = future.get();
> } catch (ExecutionException e) {
> final Throwable cause = e.getCause();
> // cause must be UncheckedIOException and its message must be
> "application specific message"
> assert ...
> }
>
> I think the application should receive the `UncheckedIOException` as the top
> level cause of the `ExecutionException` and that `UncheckedIOException` must
> contain the original cause and the original message that was there when the
> application raised it. Not passing along that to the application, I think,
> would be wrong.
Then we should wrap - but that could be strange. Especially in those cases
where the application does:
throw new UncheckedIOException(new IOException(msg));
But yes - maybe you're right. Since send() does rewrap UncheckedIOException
into IOException then maybe sendAsync should do so too. Utils.toIOException
could be overriden with a method that takes a lambda to convert
UncheckedIOException to IOException. Something like:
public static IOException toIOException(Throwable cause) {
+ return toIOException(cause, UncheckedIOException::getCause);
+ }
+
+ public static IOException toIOException(Throwable cause,
Function<UncheckedIOException, IOException> uncheckedIOConverter) {
if (cause == null) return null;
if (cause instanceof CompletionException ce) {
cause = ce.getCause();
@@ -522,7 +526,7 @@ public static IOException toIOException(Throwable cause) {
if (cause instanceof IOException io) {
return io;
} else if (cause instanceof UncheckedIOException uio) {
- return uio.getCause();
+ return uncheckedIOConverter.apply(uio);
}
return new IOException(cause.getMessage(), cause);
}
Then sendAsync could call `Utils.toIOException(throwable, IOException::new)`
-------------
PR Review Comment: https://git.openjdk.org/jdk/pull/27787#discussion_r2452001406