diff --git a/extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/DefaultMicroprofileRestClientExceptionMapper.java b/extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/DefaultMicroprofileRestClientExceptionMapper.java index d4653cc190271..02f1037cb9834 100644 --- a/extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/DefaultMicroprofileRestClientExceptionMapper.java +++ b/extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/DefaultMicroprofileRestClientExceptionMapper.java @@ -5,18 +5,29 @@ import jakarta.ws.rs.core.Response; import org.eclipse.microprofile.rest.client.ext.ResponseExceptionMapper; +import org.jboss.resteasy.reactive.client.impl.ClientResponseImpl; public class DefaultMicroprofileRestClientExceptionMapper implements ResponseExceptionMapper { public Throwable toThrowable(Response response) { try { response.bufferEntity(); - } catch (Exception var3) { + } catch (Exception ignored) { } - return new WebApplicationException( + WebApplicationException exception = new WebApplicationException( String.format("%s, status code %d", response.getStatusInfo().getReasonPhrase(), response.getStatus()), response); + + if (response instanceof ClientResponseImpl) { + ClientResponseImpl clientResponse = (ClientResponseImpl) response; + StackTraceElement[] callerStackTrace = clientResponse.getCallerStackTrace(); + if (callerStackTrace != null) { + exception.setStackTrace(callerStackTrace); + } + } + + return exception; } public boolean handles(int status, MultivaluedMap headers) { diff --git a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/handlers/ClientCaptureCurrentContextRestHandler.java b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/handlers/ClientCaptureCurrentContextRestHandler.java new file mode 100644 index 0000000000000..383a58db4ed0a --- /dev/null +++ b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/handlers/ClientCaptureCurrentContextRestHandler.java @@ -0,0 +1,49 @@ +package org.jboss.resteasy.reactive.client.handlers; + +import java.util.ArrayList; +import java.util.List; + +import org.jboss.resteasy.reactive.client.impl.ClientRequestContextImpl; +import org.jboss.resteasy.reactive.client.impl.RestClientRequestContext; +import org.jboss.resteasy.reactive.client.spi.ClientRestHandler; + +/** + * This handler is meant to be executed first in the handler chain and it captures some useful information like caller + * stacktrace. + */ +public class ClientCaptureCurrentContextRestHandler implements ClientRestHandler { + + private static final String RESTEASY_REACTIVE_PACKAGE = "org.jboss.resteasy.reactive"; + private static final String AUTOGENERATED_TAG = "$$"; + + @Override + public void handle(RestClientRequestContext requestContext) throws Exception { + ClientRequestContextImpl clientRequestContext = requestContext.getClientRequestContext(); + if (clientRequestContext == null) { + return; + } + + captureCallerStackTrace(clientRequestContext); + } + + private void captureCallerStackTrace(ClientRequestContextImpl clientRequestContext) { + StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); + List effectiveStackTrace = new ArrayList<>(stackTrace.length); + boolean foundUserMethod = false; + // skip first trace which is Thread.getStackTrace + for (int i = 1; i < stackTrace.length; i++) { + StackTraceElement trace = stackTrace[i]; + if (foundUserMethod) { + effectiveStackTrace.add(trace); + } else if (!trace.getClassName().startsWith(RESTEASY_REACTIVE_PACKAGE) + && !trace.getClassName().contains(AUTOGENERATED_TAG)) { + // Skip the latest traces that starts with the "org.jboss.resteasy.reactive" package, + effectiveStackTrace.add(trace); + foundUserMethod = true; + } + } + + clientRequestContext.getRestClientRequestContext() + .setCallerStackTrace(effectiveStackTrace.toArray(new StackTraceElement[0])); + } +} diff --git a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/ClientResponseImpl.java b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/ClientResponseImpl.java index 9f72bf9af303b..95404c22b16d5 100644 --- a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/ClientResponseImpl.java +++ b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/ClientResponseImpl.java @@ -71,4 +71,8 @@ restClientRequestContext.properties, restClientRequestContext, getStringHeaders( public String getHttpVersion() { return restClientRequestContext.getVertxClientResponse().version().toString(); } + + public StackTraceElement[] getCallerStackTrace() { + return restClientRequestContext.getCallerStackTrace(); + } } diff --git a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/HandlerChain.java b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/HandlerChain.java index d224799962444..5be02342cb8e9 100644 --- a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/HandlerChain.java +++ b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/HandlerChain.java @@ -9,6 +9,7 @@ import org.jboss.resteasy.reactive.client.api.ClientLogger; import org.jboss.resteasy.reactive.client.api.LoggingScope; +import org.jboss.resteasy.reactive.client.handlers.ClientCaptureCurrentContextRestHandler; import org.jboss.resteasy.reactive.client.handlers.ClientErrorHandler; import org.jboss.resteasy.reactive.client.handlers.ClientRequestFilterRestHandler; import org.jboss.resteasy.reactive.client.handlers.ClientResponseCompleteRestHandler; @@ -26,6 +27,7 @@ class HandlerChain { private static final ClientRestHandler[] EMPTY_REST_HANDLERS = new ClientRestHandler[0]; + private final ClientRestHandler clientCaptureCurrentContextRestHandler; private final ClientRestHandler clientSwitchToRequestContextRestHandler; private final ClientRestHandler clientSendHandler; private final ClientRestHandler clientSetResponseEntityRestHandler; @@ -36,6 +38,7 @@ class HandlerChain { public HandlerChain(boolean followRedirects, LoggingScope loggingScope, Map, MultipartResponseData> multipartData, ClientLogger clientLogger) { + this.clientCaptureCurrentContextRestHandler = new ClientCaptureCurrentContextRestHandler(); this.clientSwitchToRequestContextRestHandler = new ClientSwitchToRequestContextRestHandler(); this.clientSendHandler = new ClientSendRequestHandler(followRedirects, loggingScope, clientLogger, multipartData); this.clientSetResponseEntityRestHandler = new ClientSetResponseEntityRestHandler(); @@ -52,7 +55,8 @@ ClientRestHandler[] createHandlerChain(ConfigurationImpl configuration) { List requestFilters = configuration.getRequestFilters(); List responseFilters = configuration.getResponseFilters(); if (requestFilters.isEmpty() && responseFilters.isEmpty()) { - return new ClientRestHandler[] { clientSwitchToRequestContextRestHandler, + return new ClientRestHandler[] { clientCaptureCurrentContextRestHandler, + clientSwitchToRequestContextRestHandler, clientSendHandler, clientSetResponseEntityRestHandler, clientResponseCompleteRestHandler }; @@ -65,6 +69,7 @@ ClientRestHandler[] createHandlerChain(ConfigurationImpl configuration) { for (int i = 0; i < requestFilters.size(); i++) { result.add(new ClientRequestFilterRestHandler(requestFilters.get(i))); } + result.add(clientCaptureCurrentContextRestHandler); result.add(clientSwitchToRequestContextRestHandler); result.add(clientSendHandler); result.add(clientSetResponseEntityRestHandler); diff --git a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/RestClientRequestContext.java b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/RestClientRequestContext.java index 3fb35e41152e7..1f2cd578af864 100644 --- a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/RestClientRequestContext.java +++ b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/RestClientRequestContext.java @@ -82,9 +82,6 @@ public class RestClientRequestContext extends AbstractResteasyReactiveContext, MultipartResponseData> multipartResponsesData; + private StackTraceElement[] callerStackTrace; public RestClientRequestContext(ClientImpl restClient, HttpClient httpClient, String httpMethod, URI uri, @@ -541,6 +539,14 @@ public void setMultipartResponsesData(Map, MultipartResponseData> multi this.multipartResponsesData = multipartResponsesData; } + public StackTraceElement[] getCallerStackTrace() { + return callerStackTrace; + } + + public void setCallerStackTrace(StackTraceElement[] callerStackTrace) { + this.callerStackTrace = callerStackTrace; + } + @SuppressWarnings("SameParameterValue") private Boolean getBooleanProperty(String name, Boolean defaultValue) { Object value = configuration.getProperty(name);