Identify PathParam inside an Undertow filter when the response entity is a String
alehoss May 18, 2017 2:28 PMI've already posted this on stackoverflow (Identify PathParam inside an Undertow filter... ), but maybe here is more apropriate:
I need to identify @PathParam from a request inside an undertow filter to ignore them (metrics purpose)
My filter looks like this:
public class MetricsHandler implements HttpHandler { private HttpHandler next; public MetricsHandler(HttpHandler next) { this.next = next; } @Override public void handleRequest(HttpServerExchange exchange) throws Exception { MetricsListener listener = new MetricsListener(); exchange.addExchangeCompleteListener(listener); next.handleRequest(exchange); } private class MetricsListener implements ExchangeCompletionListener { @Override public void exchangeEvent(HttpServerExchange exchange, NextListener nextListener) { try { String metric = exchange.getRequestURI(); UriInfo uriInfo = ResteasyProviderFactory.getContextData(UriInfo.class); /* * When the response entity is a String, this UriInfo is null at this point. If it's another type, the UriInfo is ok and i'm able to identify path parameters ... */ if(uriInfo != null) { Collection<List<String>> pathParametersValues = uriInfo.getPathParameters(false).values(); for (List<String> list : pathParametersValues) { for (String pathParameter : list) { metric = metric.replace("/"+pathParameter, ""); } } } Metrics.increment(metric); } finally { if (nextListener != null) { nextListener.proceed(); } } } } }
This filter is packaged as a wildfly module and configured in domain.xml (Wildfly 10.1.0), inside the undertow subsystem, as follows:
<subsystem xmlns="urn:jboss:domain:undertow:3.1"> <buffer-cache name="default"/> <server name="default-server"> <host name="default-host" alias="localhost"> <location name="/" handler="welcome-content"/> <filter-ref name="metricsFilter" /> </host> </server> <servlet-container name="default"> <jsp-config/> <websockets/> </servlet-container> <filters> <filter class-name="com.metrics.filter.MetricsHandler" module="com.metrics" name="metricsFilter"/> </filters> </subsystem>
And here are my REST methods:
@GET @Path("/path/num/{id}") @Produces(MediaType.APPLICATION_JSON) public Response pathNum(@PathParam("id") String id) { return Response.ok(123).build(); } @GET @Path("/path/string/{id}") @Produces(MediaType.APPLICATION_JSON) public Response pathString(@PathParam("id") String id) { return Response.ok("abc").build(); }
I'm able to identify the "id" path parameter when requesting for pathNum method, but I'm not for the pathString one. As of the code comment, calling ResteasyProviderFactory.getContextData(UriInfo.class) returns null for the pathString method.
I've tested this behavior against resteasy 3.0.19.Final, 3.0.20.Final and 3.0.22.Final, all with the same results.
Debugging resteasy I found that, when the response entity is Integer or another type, the MessageBodyWriter is ResteasyJackson2Provider (my rest @Produces json), and SynchronousDispatcher.clearContextData is called only after my filter's ExchangeCompletionListener.exchangeEvent.
BUT, when the response entity is a String, the MessageBodyWriter is a StringTextStar and the clearContextData is called after the MessageBodyWriter and before my ExchangeCompletionListener, so there is no more contextData to look.
I don't know if I'm doing something wrong or if this is a possible bug on resteasy, or on wildfly...