Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using restclient builder, exceptions are not mapped when calling subresources methods #239

Closed
cghislai opened this issue Dec 28, 2023 · 1 comment · Fixed by #241
Closed

Comments

@cghislai
Copy link

cghislai commented Dec 28, 2023

Im using restclient builder to access jax-rs subresrources. However, when an error http response is received, instead of calling a registered ResponseExceptionMapper, a ExceptionMapping.HandlerException is thrown with the message 'Handled internally'. To get the correct runtime exception thrown, i have to surround my call in try/catch and call the mapping manually:

        try {
            return subResourceController.subresourceMethod(subresourceMethodParam);
        } catch (ExceptionMapping.HandlerException e) {
            // Mapping not performed on subresources :/
            try {
                Method subresourceMethod = SubResourceController.class.getMethod("subresourceMethod", SubresourceMethodParam.class);
                e.mapException(subresourceMethod); 
            } catch (RuntimeException e2) {
                throw e2; // rethrows the mapped exception
            } catch (Exception e3) {
                throw new AssertionError("Should not reach this", e3); // error during mapping
            }
            throw new AssertionError("Should not reach this", e); // exception not mapped
        }

With this construct, my ResponseExceptionMapper is called as expected, and I can access the desired fields (response status, body, ...)

Im using resteasy-client 6.2.4.Final and microprofile-rest-client 2.1.4.Final.

The exception is created there: https://github.com/resteasy/resteasy-microprofile/blob/main/rest-client-base/src/main/java/org/jboss/resteasy/microprofile/client/ExceptionMapping.java#L50

The stacktrace leading to it is:

org.jboss.resteasy.microprofile.client.ExceptionMapping$HandlerException: Handled Internally
	at org.jboss.resteasy.microprofile.client.ExceptionMapping.filter(ExceptionMapping.java:113)
	at org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.filterResponse(ClientInvocation.java:667)
	at org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.invoke(ClientInvocation.java:428)
	at org.jboss.resteasy.client.jaxrs.internal.proxy.ClientInvoker.invokeSync(ClientInvoker.java:134)
	at org.jboss.resteasy.client.jaxrs.internal.proxy.ClientInvoker.invoke(ClientInvoker.java:103)
	at org.jboss.resteasy.client.jaxrs.internal.proxy.ClientProxy.invoke(ClientProxy.java:61)

For a call on a normal resource (not a subresource), the HandlerException is created, from the same call stack; but later mapped and rethrown as a WebApplicationException:

at be.fiscalteam.nitro.it.client.util.ClientExceptionMapper.toThrowable(ClientExceptionMapper.java:17)
	at be.fiscalteam.nitro.it.client.util.ClientExceptionMapper.toThrowable(ClientExceptionMapper.java:9)
	at org.jboss.resteasy.microprofile.client.ExceptionMapping$HandlerException.mapException(ExceptionMapping.java:60)
	at org.jboss.resteasy.microprofile.client.ProxyInvocationHandler.invoke(ProxyInvocationHandler.java:147)

This is the be.fiscalteam.nitro.it.client.util.ClientExceptionMapper. registered using RestClientBuilder.newBuilder().register(new ClientExceptionMapper()):

public class ClientExceptionMapper implements ResponseExceptionMapper<WebApplicationException> {
    @Override
    public boolean handles(int status, MultivaluedMap<String, Object> headers) {
        return ResponseExceptionMapper.super.handles(status, headers);
    }

    @Override
    public WebApplicationException toThrowable(Response response) {
        return new WebApplicationException(response);
    }
}

The subresources I use are defined as simple Jax-rs interfaces, like for the normal resources but lacking a @path annotation on the class.
Examples:

@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public interface WsNitroRuleActionsSubResourceController  {

    @POST
    @Path("")
    WsNitroRuleAction createNitroRuleAction(@NotNull WsNitroRuleAction wsNitroRuleAction);

    @GET
    @Path("/list")
    List<WsNitroRuleAction> listNitroRuleActions();
}

@Path("nitroRule")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public interface WsNitroRuleController  {

    @POST
    @Path("")
    WsNitroRule createNitroRule(@NotNull WsNitroRule wsNitroRule);

    @GET
    @Path("/{id: [0-9]+}")
    WsNitroRule getNitroRule(@PathParam("id") Long id);

    @Path("/{id: [0-9]+}/actions")
    WsNitroRuleActionsSubResourceController getActionsSubresource(@PathParam("id") Long id);

}
@jamezp
Copy link
Contributor

jamezp commented Jan 2, 2024

Sorry for the delay on this. I'm just back from PTO today. I'll try to have a look at this by the end of the week.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants