Skip to content

Commit

Permalink
Merge pull request #33869 from Sgitario/33837
Browse files Browse the repository at this point in the history
Provide better stacktrace when throwing web exceptions in Rest Client
  • Loading branch information
geoand authored Jun 7, 2023
2 parents e57d065 + 141eb36 commit f3bbc25
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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<StackTraceElement> 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]));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,8 @@ restClientRequestContext.properties, restClientRequestContext, getStringHeaders(
public String getHttpVersion() {
return restClientRequestContext.getVertxClientResponse().version().toString();
}

public StackTraceElement[] getCallerStackTrace() {
return restClientRequestContext.getCallerStackTrace();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -36,6 +38,7 @@ class HandlerChain {

public HandlerChain(boolean followRedirects, LoggingScope loggingScope,
Map<Class<?>, MultipartResponseData> multipartData, ClientLogger clientLogger) {
this.clientCaptureCurrentContextRestHandler = new ClientCaptureCurrentContextRestHandler();
this.clientSwitchToRequestContextRestHandler = new ClientSwitchToRequestContextRestHandler();
this.clientSendHandler = new ClientSendRequestHandler(followRedirects, loggingScope, clientLogger, multipartData);
this.clientSetResponseEntityRestHandler = new ClientSetResponseEntityRestHandler();
Expand All @@ -52,7 +55,8 @@ ClientRestHandler[] createHandlerChain(ConfigurationImpl configuration) {
List<ClientRequestFilter> requestFilters = configuration.getRequestFilters();
List<ClientResponseFilter> responseFilters = configuration.getResponseFilters();
if (requestFilters.isEmpty() && responseFilters.isEmpty()) {
return new ClientRestHandler[] { clientSwitchToRequestContextRestHandler,
return new ClientRestHandler[] { clientCaptureCurrentContextRestHandler,
clientSwitchToRequestContextRestHandler,
clientSendHandler,
clientSetResponseEntityRestHandler,
clientResponseCompleteRestHandler };
Expand All @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,6 @@ public class RestClientRequestContext extends AbstractResteasyReactiveContext<Re
private final ClientRestHandler[] abortHandlerChainWithoutResponseFilters;

private final boolean disableContextualErrorMessages;
/**
* Only initialised if we have request or response filters
*/
/**
* Only initialised once we get the response
*/
Expand All @@ -103,6 +100,7 @@ public class RestClientRequestContext extends AbstractResteasyReactiveContext<Re
private Response abortedWith;
private ServiceInstance callStatsCollector;
private Map<Class<?>, MultipartResponseData> multipartResponsesData;
private StackTraceElement[] callerStackTrace;

public RestClientRequestContext(ClientImpl restClient,
HttpClient httpClient, String httpMethod, URI uri,
Expand Down Expand Up @@ -541,6 +539,14 @@ public void setMultipartResponsesData(Map<Class<?>, 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);
Expand Down

0 comments on commit f3bbc25

Please sign in to comment.